gerrit
2017-06-22 16:42:46 UTC
This is an automated email from Gerrit.
Paul Fertser (***@gmail.com) just uploaded a new patch set to Gerrit, which you can find at http://openocd.zylin.com/4168
-- gerrit
commit 80f14312be2488e114ac5df485d1c77ff32b3fbb
Author: Paul Fertser <***@gmail.com>
Date: Thu Jun 22 19:35:17 2017 +0300
Huge code drop from AD developers
ftp://ftp.analog.com/pub/tools/patches/gnu_sources/cces/2.4.0/openocd-0.9.0-cces-2.4.0-src.tar.gz
Includes support for Blackfin target, aducm302x flash driver, ice1000
debug adapter, some Cortex-A tweaks/bugfixes, build process
modifications related to cross-compiling for windows.
Most of the code is apparently written by
Jie Zhang <***@analog.com>
Change-Id: Ia923787f20c5f4a297b59256cb644c9fd737ecda
Signed-off-by: Paul Fertser <***@gmail.com>
diff --git a/Makefile.am b/Makefile.am
index 2ddc96d..4b40041 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -67,7 +67,7 @@ $(THE_MANUAL): %.pdf: %.tex
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' | \
+TCL_FILES = find $(srcdir)/$(TCL_PATH) -name '*.cfg' -o -name '*.tcl' -o -name '*.txt' -o -name '*.xml' | \
sed -e 's,^$(srcdir)/$(TCL_PATH),,'
dist-hook:
diff --git a/acx.m4 b/acx.m4
new file mode 100644
index 0000000..9ff31eb
--- /dev/null
+++ b/acx.m4
@@ -0,0 +1,621 @@
+# Autoconf M4 include file defining utility macros for complex Canadian
+# cross builds.
+
+dnl ####
+dnl # _GCC_TOPLEV_NONCANONICAL_BUILD
+dnl # $build_alias or canonical $build if blank.
+dnl # Used when we would use $build_alias, but empty is not OK.
+AC_DEFUN([_GCC_TOPLEV_NONCANONICAL_BUILD],
+[AC_REQUIRE([AC_CANONICAL_BUILD]) []dnl
+case ${build_alias} in
+ "") build_noncanonical=${build} ;;
+ *) build_noncanonical=${build_alias} ;;
+esac
+]) []dnl # _GCC_TOPLEV_NONCANONICAL_BUILD
+
+dnl ####
+dnl # _GCC_TOPLEV_NONCANONICAL_HOST
+dnl # $host_alias, or $build_noncanonical if blank.
+dnl # Used when we would use $host_alias, but empty is not OK.
+AC_DEFUN([_GCC_TOPLEV_NONCANONICAL_HOST],
+[AC_REQUIRE([_GCC_TOPLEV_NONCANONICAL_BUILD]) []dnl
+case ${host_alias} in
+ "") host_noncanonical=${build_noncanonical} ;;
+ *) host_noncanonical=${host_alias} ;;
+esac
+]) []dnl # _GCC_TOPLEV_NONCANONICAL_HOST
+
+dnl ####
+dnl # _GCC_TOPLEV_NONCANONICAL_TARGET
+dnl # $target_alias or $host_noncanonical if blank.
+dnl # Used when we would use $target_alias, but empty is not OK.
+AC_DEFUN([_GCC_TOPLEV_NONCANONICAL_TARGET],
+[AC_REQUIRE([_GCC_TOPLEV_NONCANONICAL_HOST]) []dnl
+case ${target_alias} in
+ "") target_noncanonical=${host_noncanonical} ;;
+ *) target_noncanonical=${target_alias} ;;
+esac
+]) []dnl # _GCC_TOPLEV_NONCANONICAL_TARGET
+
+dnl ####
+dnl # ACX_NONCANONICAL_BUILD
+dnl # Like underscored version, but AC_SUBST's.
+AC_DEFUN([ACX_NONCANONICAL_BUILD],
+[AC_REQUIRE([_GCC_TOPLEV_NONCANONICAL_BUILD]) []dnl
+AC_SUBST(build_noncanonical)
+]) []dnl # ACX_NONCANONICAL_BUILD
+
+dnl ####
+dnl # ACX_NONCANONICAL_HOST
+dnl # Like underscored version, but AC_SUBST's.
+AC_DEFUN([ACX_NONCANONICAL_HOST],
+[AC_REQUIRE([_GCC_TOPLEV_NONCANONICAL_HOST]) []dnl
+AC_SUBST(host_noncanonical)
+]) []dnl # ACX_NONCANONICAL_HOST
+
+dnl ####
+dnl # ACX_NONCANONICAL_TARGET
+dnl # Like underscored version, but AC_SUBST's.
+AC_DEFUN([ACX_NONCANONICAL_TARGET],
+[AC_REQUIRE([_GCC_TOPLEV_NONCANONICAL_TARGET]) []dnl
+AC_SUBST(target_noncanonical)
+]) []dnl # ACX_NONCANONICAL_TARGET
+
+dnl ####
+dnl # GCC_TOPLEV_SUBDIRS
+dnl # GCC & friends build 'build', 'host', and 'target' tools. These must
+dnl # be separated into three well-known subdirectories of the build directory:
+dnl # build_subdir, host_subdir, and target_subdir. The values are determined
+dnl # here so that they can (theoretically) be changed in the future. They
+dnl # were previously reproduced across many different files.
+dnl #
+dnl # This logic really amounts to very little with autoconf 2.13; it will
+dnl # amount to a lot more with autoconf 2.5x.
+AC_DEFUN([GCC_TOPLEV_SUBDIRS],
+[AC_REQUIRE([_GCC_TOPLEV_NONCANONICAL_TARGET]) []dnl
+AC_REQUIRE([_GCC_TOPLEV_NONCANONICAL_BUILD]) []dnl
+
+# post-stage1 host modules use a different CC_FOR_BUILD so, in order to
+# have matching libraries, they should use host libraries: Makefile.tpl
+# arranges to pass --with-build-libsubdir=$(HOST_SUBDIR).
+# However, they still use the build modules, because the corresponding
+# host modules (e.g. bison) are only built for the host when bootstrap
+# finishes. So:
+# - build_subdir is where we find build modules, and never changes.
+# - build_libsubdir is where we find build libraries, and can be overridden.
+
+# Prefix 'build-' so this never conflicts with target_subdir.
+build_subdir="build-${build_noncanonical}"
+AC_ARG_WITH(build-libsubdir,
+[ --with-build-libsubdir=[DIR] Directory where to find libraries for build system],
+build_libsubdir="$withval",
+build_libsubdir="$build_subdir")
+# --srcdir=. covers the toplevel, while "test -d" covers the subdirectories
+if ( test $srcdir = . && test -d gcc ) \
+ || test -d $srcdir/../host-${host_noncanonical}; then
+ host_subdir="host-${host_noncanonical}"
+else
+ host_subdir=.
+fi
+# No prefix.
+target_subdir=${target_noncanonical}
+AC_SUBST([build_libsubdir]) []dnl
+AC_SUBST([build_subdir]) []dnl
+AC_SUBST([host_subdir]) []dnl
+AC_SUBST([target_subdir]) []dnl
+]) []dnl # GCC_TOPLEV_SUBDIRS
+
+
+####
+# _NCN_TOOL_PREFIXES: Some stuff that oughtta be done in AC_CANONICAL_SYSTEM
+# or AC_INIT.
+# These demand that AC_CANONICAL_SYSTEM be called beforehand.
+AC_DEFUN([_NCN_TOOL_PREFIXES],
+[ncn_tool_prefix=
+test -n "$host_alias" && ncn_tool_prefix=$host_alias-
+ncn_target_tool_prefix=
+test -n "$target_alias" && ncn_target_tool_prefix=$target_alias-
+]) []dnl # _NCN_TOOL_PREFIXES
+
+####
+# NCN_STRICT_CHECK_TOOLS(variable, progs-to-check-for,[value-if-not-found],[path])
+# Like plain AC_CHECK_TOOLS, but require prefix if build!=host.
+
+AC_DEFUN([NCN_STRICT_CHECK_TOOLS],
+[AC_REQUIRE([_NCN_TOOL_PREFIXES]) []dnl
+AC_ARG_VAR([$1], [$1 for the host])
+
+if test -n "[$]$1"; then
+ ac_cv_prog_$1=[$]$1
+elif test -n "$ac_cv_prog_$1"; then
+ $1=$ac_cv_prog_$1
+fi
+
+if test -n "$ac_cv_prog_$1"; then
+ for ncn_progname in $2; do
+ AC_CHECK_PROG([$1], [${ncn_progname}], [${ncn_progname}], , [$4])
+ done
+fi
+
+for ncn_progname in $2; do
+ if test -n "$ncn_tool_prefix"; then
+ AC_CHECK_PROG([$1], [${ncn_tool_prefix}${ncn_progname}],
+ [${ncn_tool_prefix}${ncn_progname}], , [$4])
+ fi
+ if test -z "$ac_cv_prog_$1" && test $build = $host ; then
+ AC_CHECK_PROG([$1], [${ncn_progname}], [${ncn_progname}], , [$4])
+ fi
+ test -n "$ac_cv_prog_$1" && break
+done
+
+if test -z "$ac_cv_prog_$1" ; then
+ ifelse([$3],[], [set dummy $2
+ if test $build = $host ; then
+ $1="[$]2"
+ else
+ $1="${ncn_tool_prefix}[$]2"
+ fi], [$1="$3"])
+fi
+]) []dnl # NCN_STRICT_CHECK_TOOLS
+
+####
+# NCN_STRICT_CHECK_TARGET_TOOLS(variable, progs-to-check-for,[value-if-not-found],[path])
+# Like CVS Autoconf AC_CHECK_TARGET_TOOLS, but require prefix if build!=target.
+
+AC_DEFUN([NCN_STRICT_CHECK_TARGET_TOOLS],
+[AC_REQUIRE([_NCN_TOOL_PREFIXES]) []dnl
+AC_ARG_VAR([$1], patsubst([$1], [_FOR_TARGET$], [])[ for the target])
+
+if test -n "[$]$1"; then
+ ac_cv_prog_$1=[$]$1
+elif test -n "$ac_cv_prog_$1"; then
+ $1=$ac_cv_prog_$1
+fi
+
+if test -n "$ac_cv_prog_$1"; then
+ for ncn_progname in $2; do
+ AC_CHECK_PROG([$1], [${ncn_progname}], [${ncn_progname}], , [$4])
+ done
+fi
+
+if test -z "$ac_cv_prog_$1" && test -n "$with_build_time_tools"; then
+ for ncn_progname in $2; do
+ AC_MSG_CHECKING([for ${ncn_progname} in $with_build_time_tools])
+ if test -x $with_build_time_tools/${ncn_progname}; then
+ ac_cv_prog_$1=$with_build_time_tools/${ncn_progname}
+ AC_MSG_RESULT(yes)
+ break
+ else
+ AC_MSG_RESULT(no)
+ fi
+ done
+fi
+
+if test -z "$ac_cv_prog_$1"; then
+ for ncn_progname in $2; do
+ if test -n "$ncn_target_tool_prefix"; then
+ AC_CHECK_PROG([$1], [${ncn_target_tool_prefix}${ncn_progname}],
+ [${ncn_target_tool_prefix}${ncn_progname}], , [$4])
+ fi
+ if test -z "$ac_cv_prog_$1" && test $build = $target ; then
+ AC_CHECK_PROG([$1], [${ncn_progname}], [${ncn_progname}], , [$4])
+ fi
+ test -n "$ac_cv_prog_$1" && break
+ done
+fi
+
+if test -z "$ac_cv_prog_$1" ; then
+ ifelse([$3],[], [set dummy $2
+ if test $build = $target ; then
+ $1="[$]2"
+ else
+ $1="${ncn_target_tool_prefix}[$]2"
+ fi], [$1="$3"])
+else
+ $1="$ac_cv_prog_$1"
+fi
+]) []dnl # NCN_STRICT_CHECK_TARGET_TOOLS
+
+
+# Backported from Autoconf 2.5x; can go away when and if
+# we switch. Put the OS path separator in $PATH_SEPARATOR.
+AC_DEFUN([ACX_PATH_SEP], [
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ echo "#! /bin/sh" >conf$$.sh
+ echo "exit 0" >>conf$$.sh
+ chmod +x conf$$.sh
+ if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+ PATH_SEPARATOR=';'
+ else
+ PATH_SEPARATOR=:
+ fi
+ rm -f conf$$.sh
+fi
+])
+
+
+AC_DEFUN([ACX_TOOL_DIRS], [
+AC_REQUIRE([ACX_PATH_SEP])
+if test "x$exec_prefix" = xNONE; then
+ if test "x$prefix" = xNONE; then
+ gcc_cv_tool_prefix=$ac_default_prefix
+ else
+ gcc_cv_tool_prefix=$prefix
+ fi
+else
+ gcc_cv_tool_prefix=$exec_prefix
+fi
+
+# If there is no compiler in the tree, use the PATH only. In any
+# case, if there is no compiler in the tree nobody should use
+# AS_FOR_TARGET and LD_FOR_TARGET.
+if test x$host = x$build && test -f $srcdir/gcc/BASE-VER; then
+ gcc_version=`cat $srcdir/gcc/BASE-VER`
+ gcc_cv_tool_dirs="$gcc_cv_tool_prefix/libexec/gcc/$target_noncanonical/$gcc_version$PATH_SEPARATOR"
+ gcc_cv_tool_dirs="$gcc_cv_tool_dirs$gcc_cv_tool_prefix/libexec/gcc/$target_noncanonical$PATH_SEPARATOR"
+ gcc_cv_tool_dirs="$gcc_cv_tool_dirs/usr/lib/gcc/$target_noncanonical/$gcc_version$PATH_SEPARATOR"
+ gcc_cv_tool_dirs="$gcc_cv_tool_dirs/usr/lib/gcc/$target_noncanonical$PATH_SEPARATOR"
+ gcc_cv_tool_dirs="$gcc_cv_tool_dirs$gcc_cv_tool_prefix/$target_noncanonical/bin/$target_noncanonical/$gcc_version$PATH_SEPARATOR"
+ gcc_cv_tool_dirs="$gcc_cv_tool_dirs$gcc_cv_tool_prefix/$target_noncanonical/bin$PATH_SEPARATOR"
+else
+ gcc_cv_tool_dirs=
+fi
+
+if test x$build = x$target && test -n "$md_exec_prefix"; then
+ gcc_cv_tool_dirs="$gcc_cv_tool_dirs$md_exec_prefix$PATH_SEPARATOR"
+fi
+
+]) []dnl # ACX_TOOL_DIRS
+
+# ACX_HAVE_GCC_FOR_TARGET
+# Check if the variable GCC_FOR_TARGET really points to a GCC binary.
+AC_DEFUN([ACX_HAVE_GCC_FOR_TARGET], [
+cat > conftest.c << \EOF
+#ifdef __GNUC__
+ gcc_yay;
+#endif
+EOF
+if ($GCC_FOR_TARGET -E conftest.c | grep gcc_yay) > /dev/null 2>&1; then
+ have_gcc_for_target=yes
+else
+ GCC_FOR_TARGET=${ncn_target_tool_prefix}gcc
+ have_gcc_for_target=no
+fi
+rm conftest.c
+])
+
+# ACX_CHECK_INSTALLED_TARGET_TOOL(VAR, PROG)
+# Searching for installed target binutils. We need to take extra care,
+# else we may find the wrong assembler, linker, etc., and lose.
+#
+# First try --with-build-time-tools, if specified.
+#
+# For build != host, we ask the installed GCC for the name of the tool it
+# uses, and accept it if it is an absolute path. This is because the
+# only good choice for a compiler is the same GCC version that is being
+# installed (or we couldn't make target libraries), and we assume that
+# on the host system we'll have not only the same GCC version, but also
+# the same binutils version.
+#
+# For build == host, search the same directories that the installed
+# compiler will search. We used to do this for the assembler, linker,
+# and nm only; for simplicity of configuration, however, we extend this
+# criterion to tools (such as ar and ranlib) that are never invoked by
+# the compiler, to avoid mismatches.
+#
+# Also note we have to check MD_EXEC_PREFIX before checking the user's path
+# if build == target. This makes the most sense only when bootstrapping,
+# but we also do so when build != host. In this case, we hope that the
+# build and host systems will have similar contents of MD_EXEC_PREFIX.
+#
+# If we do not find a suitable binary, then try the user's path.
+
+AC_DEFUN([ACX_CHECK_INSTALLED_TARGET_TOOL], [
+AC_REQUIRE([ACX_TOOL_DIRS])
+AC_REQUIRE([ACX_HAVE_GCC_FOR_TARGET])
+if test -z "$ac_cv_path_$1" ; then
+ if test -n "$with_build_time_tools"; then
+ AC_MSG_CHECKING([for $2 in $with_build_time_tools])
+ if test -x $with_build_time_tools/$2; then
+ $1=`cd $with_build_time_tools && pwd`/$2
+ ac_cv_path_$1=[$]$1
+ AC_MSG_RESULT([$ac_cv_path_$1])
+ else
+ AC_MSG_RESULT(no)
+ fi
+ elif test $build != $host && test $have_gcc_for_target = yes; then
+ $1=`$GCC_FOR_TARGET --print-prog-name=$2`
+ test [$]$1 = $2 && $1=
+ test -n "[$]$1" && ac_cv_path_$1=[$]$1
+ fi
+fi
+if test -z "$ac_cv_path_$1" && test -n "$gcc_cv_tool_dirs"; then
+ AC_PATH_PROG([$1], [$2], [], [$gcc_cv_tool_dirs])
+fi
+if test -z "$ac_cv_path_$1" ; then
+ NCN_STRICT_CHECK_TARGET_TOOLS([$1], [$2])
+else
+ $1=$ac_cv_path_$1
+fi
+]) []dnl # ACX_CHECK_INSTALLED_TARGET_TOOL
+
+###
+# AC_PROG_CPP_WERROR
+# Used for autoconf 2.5x to force AC_PREPROC_IFELSE to reject code which
+# triggers warnings from the preprocessor. Will be in autoconf 2.58.
+# For now, using this also overrides header checks to use only the
+# preprocessor (matches 2.13 behavior; matching 2.58's behavior is a
+# bit harder from here).
+# Eventually autoconf will default to checking headers with the compiler
+# instead, and we'll have to do this differently.
+
+AC_DEFUN([AC_PROG_CPP_WERROR],
+[AC_REQUIRE([AC_PROG_CPP])dnl
+m4_define([AC_CHECK_HEADER],m4_defn([_AC_CHECK_HEADER_OLD]))
+ac_c_preproc_warn_flag=yes])# AC_PROG_CPP_WERROR
+
+# Test for GNAT.
+# We require the gnatbind & gnatmake programs, as well as a compiler driver
+# that understands Ada. We use the user's CC setting, already found, and
+# possibly add $1 to the command-line parameters.
+#
+# Sets the shell variable have_gnat to yes or no as appropriate, and
+# substitutes GNATBIND and GNATMAKE.
+AC_DEFUN([ACX_PROG_GNAT],
+[AC_REQUIRE([AC_CHECK_TOOL_PREFIX])
+AC_REQUIRE([AC_PROG_CC])
+AC_CHECK_TOOL(GNATBIND, gnatbind, no)
+AC_CHECK_TOOL(GNATMAKE, gnatmake, no)
+AC_CACHE_CHECK([whether compiler driver understands Ada],
+ acx_cv_cc_gcc_supports_ada,
+[cat >conftest.adb <<EOF
+procedure conftest is begin null; end conftest;
+EOF
+acx_cv_cc_gcc_supports_ada=no
+# There is a bug in old released versions of GCC which causes the
+# driver to exit successfully when the appropriate language module
+# has not been installed. This is fixed in 2.95.4, 3.0.2, and 3.1.
+# Therefore we must check for the error message as well as an
+# unsuccessful exit.
+# Other compilers, like HP Tru64 UNIX cc, exit successfully when
+# given a .adb file, but produce no object file. So we must check
+# if an object file was really produced to guard against this.
+errors=`(${CC} $1[]m4_ifval([$1], [ ])-c conftest.adb) 2>&1 || echo failure`
+if test x"$errors" = x && test -f conftest.$ac_objext; then
+ acx_cv_cc_gcc_supports_ada=yes
+fi
+rm -f conftest.*])
+
+if test "x$GNATBIND" != xno && test "x$GNATMAKE" != xno && test x$acx_cv_cc_gcc_supports_ada != xno; then
+ have_gnat=yes
+else
+ have_gnat=no
+fi
+])
+
+dnl 'make compare' can be significantly faster, if cmp itself can
+dnl skip bytes instead of using tail. The test being performed is
+dnl "if cmp --ignore-initial=2 t1 t2 && ! cmp --ignore-initial=1 t1 t2"
+dnl but we need to sink errors and handle broken shells. We also test
+dnl for the parameter format "cmp file1 file2 skip1 skip2" which is
+dnl accepted by cmp on some systems.
+AC_DEFUN([ACX_PROG_CMP_IGNORE_INITIAL],
+[AC_CACHE_CHECK([how to compare bootstrapped objects], gcc_cv_prog_cmp_skip,
+[ echo abfoo >t1
+ echo cdfoo >t2
+ gcc_cv_prog_cmp_skip='tail +16c $$f1 > tmp-foo1; tail +16c $$f2 > tmp-foo2; cmp tmp-foo1 tmp-foo2'
+ if cmp t1 t2 2 2 > /dev/null 2>&1; then
+ if cmp t1 t2 1 1 > /dev/null 2>&1; then
+ :
+ else
+ gcc_cv_prog_cmp_skip='cmp $$f1 $$f2 16 16'
+ fi
+ fi
+ if cmp --ignore-initial=2 t1 t2 > /dev/null 2>&1; then
+ if cmp --ignore-initial=1 t1 t2 > /dev/null 2>&1; then
+ :
+ else
+ gcc_cv_prog_cmp_skip='cmp --ignore-initial=16 $$f1 $$f2'
+ fi
+ fi
+ rm t1 t2
+])
+do_compare="$gcc_cv_prog_cmp_skip"
+AC_SUBST(do_compare)
+])
+
+dnl See whether we can include both string.h and strings.h.
+AC_DEFUN([ACX_HEADER_STRING],
+[AC_CACHE_CHECK([whether string.h and strings.h may both be included],
+ gcc_cv_header_string,
+[AC_TRY_COMPILE([#include <string.h>
+#include <strings.h>], , gcc_cv_header_string=yes, gcc_cv_header_string=no)])
+if test $gcc_cv_header_string = yes; then
+ AC_DEFINE(STRING_WITH_STRINGS, 1, [Define if you can safely include both <string.h> and <strings.h>.])
+fi
+])
+
+dnl See if stdbool.h properly defines bool and true/false.
+dnl Check whether _Bool is built-in.
+AC_DEFUN([ACX_HEADER_STDBOOL],
+[AC_CACHE_CHECK([for working stdbool.h],
+ ac_cv_header_stdbool_h,
+[AC_TRY_COMPILE([#include <stdbool.h>],
+[bool foo = false;],
+ac_cv_header_stdbool_h=yes, ac_cv_header_stdbool_h=no)])
+if test $ac_cv_header_stdbool_h = yes; then
+ AC_DEFINE(HAVE_STDBOOL_H, 1,
+ [Define if you have a working <stdbool.h> header file.])
+fi
+AC_CACHE_CHECK(for built-in _Bool, gcc_cv_c__bool,
+[AC_TRY_COMPILE(,
+[_Bool foo;],
+gcc_cv_c__bool=yes, gcc_cv_c__bool=no)
+])
+if test $gcc_cv_c__bool = yes; then
+ AC_DEFINE(HAVE__BOOL, 1, [Define if the \`_Bool' type is built-in.])
+fi
+])
+
+dnl See if hard links work and if not, try to substitute $1 or simple copy.
+AC_DEFUN([ACX_PROG_LN],
+[AC_MSG_CHECKING(whether ln works)
+AC_CACHE_VAL(acx_cv_prog_LN,
+[rm -f conftestdata_t
+echo >conftestdata_f
+if ln conftestdata_f conftestdata_t 2>/dev/null
+then
+ acx_cv_prog_LN=ln
+else
+ acx_cv_prog_LN=no
+fi
+rm -f conftestdata_f conftestdata_t
+])dnl
+if test $acx_cv_prog_LN = no; then
+ LN="ifelse([$1],,cp,[$1])"
+ AC_MSG_RESULT([no, using $LN])
+else
+ LN="$acx_cv_prog_LN"
+ AC_MSG_RESULT(yes)
+fi
+AC_SUBST(LN)dnl
+])
+
+dnl GCC_TARGET_TOOL(PROGRAM, TARGET-VAR, HOST-VAR, IN-TREE-TOOL, LANGUAGE)
+AC_DEFUN([GCC_TARGET_TOOL],
+[AC_MSG_CHECKING(where to find the target $1)
+if test "x${build}" != "x${host}" ; then
+ if expr "x[$]$2" : "x/" > /dev/null; then
+ # We already found the complete path
+ ac_dir=`dirname [$]$2`
+ AC_MSG_RESULT(pre-installed in $ac_dir)
+ else
+ # Canadian cross, just use what we found
+ AC_MSG_RESULT(pre-installed)
+ fi
+else
+ ifelse([$4],,,
+ [ok=yes
+ case " ${configdirs} " in
+ *" patsubst([$4], [/.*], []) "*) ;;
+ *) ok=no ;;
+ esac
+ ifelse([$5],,,
+ [case ,${enable_languages}, in
+ *,$5,*) ;;
+ *) ok=no ;;
+ esac])
+ if test $ok = yes; then
+ # An in-tree tool is available and we can use it
+ $2='$$r/$(HOST_SUBDIR)/$4'
+ AC_MSG_RESULT(just compiled)
+ el])if expr "x[$]$2" : "x/" > /dev/null; then
+ # We already found the complete path
+ ac_dir=`dirname [$]$2`
+ AC_MSG_RESULT(pre-installed in $ac_dir)
+ elif test "x$target" = "x$host"; then
+ # We can use an host tool
+ $2='$($3)'
+ AC_MSG_RESULT(host tool)
+ else
+ # We need a cross tool
+ AC_MSG_RESULT(pre-installed)
+ fi
+fi
+AC_SUBST($2)])
+
+
+dnl Locate a program and check that its version is acceptable.
+dnl ACX_PROG_CHECK_VER(var, name, version-switch,
+dnl version-extract-regexp, version-glob)
+AC_DEFUN([ACX_CHECK_PROG_VER],[
+ AC_CHECK_PROG([$1], [$2], [$2])
+ if test -n "[$]$1"; then
+ # Found it, now check the version.
+ AC_CACHE_CHECK([for modern $2],
+ [gcc_cv_prog_$2_modern],
+ [ac_prog_version=`eval [$]$1 $3 2>&1 |
+ sed -n 's/^.*patsubst([[$4]],/,\/).*$/\1/p'`
+
+ [case $ac_prog_version in
+ '') gcc_cv_prog_$2_modern=no;;
+ $5) gcc_cv_prog_$2_modern=yes;;
+ *) gcc_cv_prog_$2_modern=no;;
+ esac]
+ ])
+ else
+ gcc_cv_prog_$2_modern=no
+ fi
+ if test $gcc_cv_prog_$2_modern = no; then
+ $1="${CONFIG_SHELL-/bin/sh} $ac_aux_dir/missing $2"
+ fi
+])
+
+dnl Support the --with-pkgversion configure option.
+dnl ACX_PKGVERSION(default-pkgversion)
+AC_DEFUN([ACX_PKGVERSION],[
+ AC_ARG_WITH(pkgversion,
+ AS_HELP_STRING([--with-pkgversion=PKG],
+ [Use PKG in the version string in place of "$1"]),
+ [case "$withval" in
+ yes) AC_MSG_ERROR([package version not specified]) ;;
+ no) PKGVERSION= ;;
+ *) PKGVERSION="($withval) " ;;
+ esac],
+ PKGVERSION="($1) "
+ )
+ AC_SUBST(PKGVERSION)
+])
+
+dnl Support the --with-bugurl configure option.
+dnl ACX_BUGURL(default-bugurl)
+AC_DEFUN([ACX_BUGURL],[
+ AC_ARG_WITH(bugurl,
+ AS_HELP_STRING([--with-bugurl=URL],
+ [Direct users to URL to report a bug]),
+ [case "$withval" in
+ yes) AC_MSG_ERROR([bug URL not specified]) ;;
+ no) BUGURL=
+ ;;
+ *) BUGURL="$withval"
+ ;;
+ esac],
+ BUGURL="$1"
+ )
+ case ${BUGURL} in
+ "")
+ REPORT_BUGS_TO=
+ REPORT_BUGS_TEXI=
+ ;;
+ *)
+ REPORT_BUGS_TO="<$BUGURL>"
+ REPORT_BUGS_TEXI=@uref{`echo "$BUGURL" | sed 's/@/@@/g'`}
+ ;;
+ esac;
+ AC_SUBST(REPORT_BUGS_TO)
+ AC_SUBST(REPORT_BUGS_TEXI)
+])
+
+dnl ####
+dnl # ACX_CHECK_CYGWIN_CAT_WORKS
+dnl # On Cygwin hosts, check that the cat command ignores
+dnl # carriage returns as otherwise builds will not work.
+dnl # See binutils PR 4334 for more details.
+AC_DEFUN([ACX_CHECK_CYGWIN_CAT_WORKS],[
+AC_MSG_CHECKING([to see if cat works as expected])
+echo a >cygwin-cat-check
+if test `cat cygwin-cat-check` = a ; then
+ rm cygwin-cat-check
+ AC_MSG_RESULT(yes)
+else
+ rm cygwin-cat-check
+ AC_MSG_RESULT(no)
+ AC_MSG_ERROR([The cat command does not ignore carriage return characters.
+ Please either mount the build directory in binary mode or run the following
+ commands before running any configure script:
+set -o igncr
+export SHELLOPTS
+ ])
+fi
+])
diff --git a/config_subdir.m4 b/config_subdir.m4
index 1c79098..aa88053 100644
--- a/config_subdir.m4
+++ b/config_subdir.m4
@@ -11,16 +11,3 @@ 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],
-[echo -e '#!/bin/sh\nexec "`dirname "'\$'0"`/configure" $2 "'\$'@"' > "$srcdir/$1/configure.gnu"
-])
-])
diff --git a/configure.ac b/configure.ac
index 1022808..cd461d3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,9 +1,19 @@
AC_PREREQ(2.64)
-AC_INIT([openocd], [0.9.0],
- [OpenOCD Mailing List <openocd-***@lists.sourceforge.net>])
+AC_INIT([openocd], [0.9.0])
AC_CONFIG_SRCDIR([src/openocd.c])
+m4_include([acx.m4])
+ACX_PKGVERSION([OpenOCD])
+ACX_BUGURL([openocd-***@lists.sourceforge.net])
+
+AC_DEFINE_UNQUOTED([PKGVERSION], ["$PKGVERSION"],
+ [Define to the package version.])dnl
+AC_DEFINE_UNQUOTED([REPORT_BUGS_TO], ["$REPORT_BUGS_TO"],
+ [Define to the URL or email address for report bugs to.])dnl
+
m4_include([config_subdir.m4])dnl
+m4_include([lib-link.m4])
+m4_include([expat.m4])
# check for makeinfo before calling AM_INIT_AUTOMAKE
AC_CHECK_PROG([MAKEINFO], [makeinfo], [makeinfo])
@@ -140,9 +150,14 @@ AC_C_BIGENDIAN
AC_CHECK_FUNCS([strndup])
AC_CHECK_FUNCS([strnlen])
AC_CHECK_FUNCS([gettimeofday])
+AC_CHECK_FUNCS([nanosleep])
AC_CHECK_FUNCS([usleep])
AC_CHECK_FUNCS([vasprintf])
+AC_CHECK_TYPE([struct timespec],
+ [AC_DEFINE(HAVE_STRUCT_TIMESPEC, 1, [Define to 1 if you have the struct timespec type])],
+ [], [[#include <time.h>]])
+
build_bitbang=no
build_bitq=no
is_cygwin=no
@@ -196,11 +211,13 @@ __EOF__
m4_define([ADAPTER_ARG], [m4_argn([1], $1)])
m4_define([ADAPTER_DESC], [m4_argn([2], $1)])
m4_define([ADAPTER_SYM], [m4_argn([3], $1)])
-m4_define([ADAPTER_VAR], [enable_[]ADAPTER_ARG($1)])
+m4_define([ADAPTER_VAR], [enable_[]m4_translit(ADAPTER_ARG($1), [-], [_])])
m4_define([ADAPTER_OPT], [m4_translit(ADAPTER_ARG($1), [_], [-])])
m4_define([USB1_ADAPTERS],
[[[ftdi], [MPSSE mode of FTDI based devices], [FTDI]],
+ [[ice-1000], [Analog Devices ICE-1000], [ICE_1000]],
+ [[ice-2000], [Analog Devices ICE-2000], [ICE_2000]],
[[stlink], [ST-Link JTAG Programmer], [HLADAPTER_STLINK]],
[[ti_icdi], [TI ICDI JTAG Programmer], [HLADAPTER_ICDI]],
[[ulink], [Keil ULINK JTAG Programmer], [ULINK]],
@@ -279,6 +296,8 @@ AC_ARG_WITH(ftd2xx-lib,
with_ftd2xx_lib=static
])
+AM_EXPAT_LINK
+
AC_ARG_ENABLE([doxygen-html],
AS_HELP_STRING([--disable-doxygen-html],
[Disable building Doxygen manual as HTML.]),
@@ -594,8 +613,6 @@ case $host in
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.])
@@ -781,7 +798,8 @@ fi
if test $use_internal_jimtcl = yes; then
if test -f "$srcdir/jimtcl/configure.ac"; then
- AX_CONFIG_SUBDIR_OPTION([jimtcl], [--disable-install-jim])
+ ac_configure_args="$ac_configure_args --disable-install-jim"
+ AC_CONFIG_SUBDIRS([jimtcl])
else
AC_MSG_ERROR([jimtcl not found, run git submodule init and git submodule update.])
fi
diff --git a/contrib/loaders/flash/aducm302x.s b/contrib/loaders/flash/aducm302x.s
new file mode 100644
index 0000000..a057b63
--- /dev/null
+++ b/contrib/loaders/flash/aducm302x.s
@@ -0,0 +1,77 @@
+/***************************************************************************
+ * Copyright (C) 2016 Analog Devices, 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 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
+ ***************************************************************************/
+
+ .text
+ .syntax unified
+ .cpu cortex-m3
+ .thumb
+ .thumb_func
+
+/*
+ * Params :
+ * r0 = workarea start
+ * r1 = workarea end
+ * r2 = target address
+ * r3 = count (64bit double words)
+ *
+ * Clobbered:
+ * r4 = pFLASH_CTRL_BASE
+ * r5 = FLASHWRITECMD
+ * r6 - tmp
+ * r7 - rp
+ * r8 - wp, tmp
+ */
+
+write:
+ ldr r4, pFLASH_CTRL_BASE
+ ldr r5, FLASHWRITECMD
+
+wait_fifo:
+ ldr r8, [r0, #0] /* read wp */
+ cmp r8, #0 /* abort if wp == 0 */
+ beq exit
+ ldr r7, [r0, #4] /* read rp */
+ cmp r7, r8 /* wait until rp != wp */
+ beq wait_fifo
+
+mainloop:
+ str r2, [r4, #0xc] /* KH_ADDR - write address */
+ add r2, r2, #8 /* increment target address */
+ ldr r6, [r7], #4
+ ldr r8, [r7], #4
+ str r6, [r4, #0x10] /* KH_DATA0 - write data */
+ str r8, [r4, #0x14] /* KH_DATA1 - write data */
+ str r5, [r4, #8] /* CMD - enable write */
+busy:
+ ldr r8, [r4, #0]
+ tst r8, #4
+ beq busy
+
+ cmp r7, r1 /* wrap rp at end of buffer */
+ it cs
+ addcs r7, r0, #8 /* skip loader args */
+ str r7, [r0, #4] /* store rp */
+ subs r3, r3, #1 /* decrement word count */
+ cbz r3, exit /* loop if not done */
+ b wait_fifo
+exit:
+ bkpt #0
+
+pFLASH_CTRL_BASE: .word 0x40018000
+FLASHWRITECMD: .word 0x4
diff --git a/doc/openocd.texi b/doc/openocd.texi
index 511bc6c..1ad7b37 100644
--- a/doc/openocd.texi
+++ b/doc/openocd.texi
@@ -62,6 +62,8 @@ Free Documentation License''.
* About:: About OpenOCD
* Developers:: OpenOCD Developer Resources
* Debug Adapter Hardware:: Debug Adapter Hardware
+* Supported Targets:: Supported Targets
+* Supported Boards:: Supported Boards
* About Jim-Tcl:: About Jim-Tcl
* Running:: Running OpenOCD
* OpenOCD Project Setup:: OpenOCD Project Setup
@@ -355,6 +357,29 @@ For more information, visit:
@b{ZY1000} See: @url{http://www.ultsol.com/index.php/component/content/article/8/210-zylin-zy1000-main}
+@section USB Analog Devices ICE-1000 and ICE-2000
+
+The Analog Devices ICE-1000 and ICE-2000 support debugging Analog Devices
+processors. Both of them support JTAG and SWD.
+
+ICE-1000 supports frequency up to 5 MHz (1 MHz, 2 MHz, 5 MHz).
+ICE-2000 supports frequency up to 46 MHz (1 MHz, 2 MHz, 5 MHz, 9 MHz, 15 MHz, 23 MHz, 46 MHz).
+
+ICE-1000 and ICE-2000 feature a multi-color LED for indicating emulator status:
+
+@itemize @bullet
+@item @b{Green}
+@* indicates the emulator is ready for operations.
+@item @b{Yellow}
+@* indicates the emulator has an issue.
+@item @b{Magenta}
+@* indicates the emulator is in JTAG mode.
+@item @b{Cyan}
+@* indicates the emulator is in SWD mode.
+@end itemize
+
+For more information, visit: @url{http://www.analog.com/ice1000} and @url{http://www.analog.com/ice2000}
+
@section USB FT2232 Based
There are many USB JTAG dongles on the market, many of them based
@@ -602,6 +627,104 @@ produced, PDF schematics are easily found and it is easy to make.
@end itemize
+@node Supported Targets
+@chapter Supported Targets
+
+OpenOCD supports many targets. Below are some of them.
+
+@section Analog Devices
+
+OpenOCD supports the following targets from Analog Devices.
+
+@subsection ADuCM3027/9
+@cindex ADuCM3027
+@cindex ADuCM3029
+
+These parts are supported through @file{target/aducm3027.cfg} and
+@file{target/aducm3029.cfg}. These two parts only support SWD.
+
+@subsection ADSP-SC570/571/572/573
+@cindex ADSP-SC570
+@cindex ADSP-SC571
+@cindex ADSP-SC572
+@cindex ADSP-SC573
+
+These parts are supported through @file{target/adspsc57x.cfg}.
+This config file uses JTAG as transport by default.
+You can make it to use SWD as transport by comment out @code{transport select jtag}
+and uncomment @code{transport select swd} near the top of that config file.
+This config file do a system reset by default when GDB attaches OpenOCD.
+If you don't want to reset the target, you can edit the @code{gdb-attach}
+event handler toward the end of the config file to change @code{reset} to @code{halt}.
+
+If the part is locked, you have two ways to unlock the part:
+
+@itemize @bullet
+
+@item @b{through OpenOCD command line}
+
+@* You can use @option{-c} to set up userkey before the config file
+
+@example
+openocd -f interface/ice1000.cfg \
+ -c "set USERKEY0 0x12345678; set USERKEY1 0x9abcdef0; \
+ set USERKEY2 0x00000000; set USERKEY3 0x5f5f5f5f; list" \
+ -f target/adspsc57x.cfg
+@end example
+
+@item @b{edit the config file}
+
+@* you can uncomment these four lines in the config file:
+
+@example
+#set USERKEY0 0x00000000
+#set USERKEY1 0x00000000
+#set USERKEY2 0x00000000
+#set USERKEY3 0x00000000
+@end example
+
+and change @code{0x00000000} to the correct userkey.
+
+@end itemize
+
+@subsection ADSP-SC582/583/584/587/589
+@cindex ADSP-SC582
+@cindex ADSP-SC583
+@cindex ADSP-SC584
+@cindex ADSP-SC587
+@cindex ADSP-SC589
+
+These parts are supported through @file{target/adspsc58x.cfg}.
+The usage is as same as @file{target/adspsc57x.cfg} except that
+@file{target/adspsc58x.cfg} does not support system reset.
+
+@node Supported Boards
+@chapter Supported Boards
+
+OpenOCD supports many boards. Below are some of them.
+
+@section Analog Devices
+
+OpenOCD supports the following boards from Analog Devices.
+
+@subsection ADSP-SC573 EZ-KIT
+@cindex ADSP-SC573 EZ-KIT
+
+This board is supported throught @file{board/adspsc573_ezkit.cfg}.
+This board config file disables MMU and then initializes SDRAM when GDB connects to OpenOCD.
+
+@subsection ADSP-SC584 EZ-BRD
+@cindex ADSP-SC584 EZ-BRD
+
+This board is supported throught @file{board/adspsc584_ezbrd.cfg}.
+This board config file disables MMU and then initializes SDRAM when GDB connects to OpenOCD.
+
+@subsection ADSP-SC589 EZ-BRD
+@cindex ADSP-SC589 EZ-BRD
+
+This board is supported throught @file{board/adspsc589_ezbrd.cfg}.
+This board config file disables MMU and then initializes SDRAM when GDB connects to OpenOCD.
+
@node About Jim-Tcl
@chapter About Jim-Tcl
@cindex Jim-Tcl
@@ -2609,6 +2732,25 @@ For example adapter definitions, see the configuration files shipped in the
@file{interface/ftdi} directory.
@end deffn
+@deffn {Interface Driver} {ice1000}
+Analog Devices ICE-1000 USB emulator. It supports JTAG and SWD transports.
+@end deffn
+
+@deffn {Interface Driver} {ice2000}
+Analog Devices ICE-2000 USB emulator. It supports JTAG and SWD transports.
+It has one driver-specific command:
+
+@deffn {Config Command} {ice2000_voltage} @option{1}|@option{2}|@option{3}
+Set voltage:
+@itemize @minus
+@item @option{1}: 1.8 V
+@item @option{2}: 2.5 V
+@item @option{3}: 3.3 V
+@end itemize
+@end deffn
+
+@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
@@ -4921,6 +5063,22 @@ at91samd bootloader 16384
@end deffn
+@deffn {Flash Driver} aducm302x
+The ADuCM3027/9 microcontrollers from Analog Devices include internal
+flash and use ARM Cortex-M3 cores.
+The flash size on ADuCM3027 is 128KB.
+The flash size on ADuCM3029 is 256KB.
+The flash start address is 0 on both.
+
+@example
+# ADuCM3027
+flash bank $_FLASHNAME aducm302x 0 0x20000 0 0 $_TARGETNAME
+
+# ADuCM3029
+flash bank $_FLASHNAME aducm302x 0 0x40000 0 0 $_TARGETNAME
+@end example
+@end deffn
+
@anchor{at91sam3}
@deffn {Flash Driver} at91sam3
@cindex at91sam3
@@ -8460,11 +8618,9 @@ Cyg_Thread::thread_list, Cyg_Scheduler_Base::current_thread.
@item ThreadX symbols
_tx_thread_current_ptr, _tx_thread_created_ptr, _tx_thread_created_count.
@item FreeRTOS symbols
-@raggedright
pxCurrentTCB, pxReadyTasksLists, xDelayedTaskList1, xDelayedTaskList2,
pxDelayedTaskList, pxOverflowDelayedTaskList, xPendingReadyList,
uxCurrentNumberOfTasks, uxTopUsedPriority.
-@end raggedright
@item linux symbols
init_task.
@item ChibiOS symbols
diff --git a/expat.m4 b/expat.m4
new file mode 100644
index 0000000..62616a8
--- /dev/null
+++ b/expat.m4
@@ -0,0 +1,57 @@
+dnl Copyright (C) 2000-2002 Free Software Foundation, Inc.
+dnl This file is free software, distributed under the terms of the GNU
+dnl General Public License. As a special exception to the GNU General
+dnl Public License, this file may be distributed as part of a program
+dnl that contains a configuration script generated by Autoconf, under
+dnl the same distribution terms as the rest of that program.
+
+dnl From Bruno Haible.
+
+AC_DEFUN([AM_EXPAT_LINKFLAGS_BODY],
+[
+ dnl Prerequisites of AC_LIB_LINKFLAGS_BODY.
+ AC_REQUIRE([AC_LIB_PREPARE_PREFIX])
+ AC_REQUIRE([AC_LIB_RPATH])
+
+ dnl Search for libexpat and define LIBEXPAT, LTLIBEXPAT and INCEXPAT
+ dnl accordingly.
+ AC_LIB_LINKFLAGS_BODY([expat])
+])
+
+AC_DEFUN([AM_EXPAT_LINK],
+[
+ dnl Search for libexpat and define LIBEXPAT, LTLIBEXPAT and INCEXPAT
+ dnl accordingly.
+ AC_REQUIRE([AM_EXPAT_LINKFLAGS_BODY])
+
+ dnl Add $INCEXPAT to CPPFLAGS before performing the following checks,
+ dnl because if the user has installed libexpat and not disabled its use
+ dnl via --without-libexpat-prefix, he wants to use it. The first
+ dnl AC_TRY_LINK will then fail, the second AC_TRY_LINK will succeed.
+ am_save_CPPFLAGS="$CPPFLAGS"
+ AC_LIB_APPENDTOVAR([CPPFLAGS], [$INCEXPAT])
+
+ AC_CACHE_CHECK(for expat, am_cv_lib_expat, [
+ am_cv_lib_expat=no
+ am_save_LIBS="$LIBS"
+ LIBS="$LIBS $LIBEXPAT"
+ AC_TRY_LINK([#include <expat.h>],
+ [XML_ParserCreate(NULL);],
+ am_cv_lib_expat=yes)
+ LIBS="$am_save_LIBS"
+ ])
+
+ if test "$am_cv_lib_expat" = yes; then
+ AC_DEFINE(HAVE_LIBEXPAT, 1, [Define if you have the libexpat.])
+ AC_MSG_CHECKING([how to link with libexpat])
+ AC_MSG_RESULT([$LIBEXPAT])
+ else
+ dnl If $LIBEXPAT didn't lead to a usable library, we don't need $INCEXPAT
+ dnl either.
+ CPPFLAGS="$am_save_CPPFLAGS"
+ LIBEXPAT=
+ LTLIBEXPAT=
+ fi
+ AC_SUBST(LIBEXPAT)
+ AC_SUBST(LTLIBEXPAT)
+])
diff --git a/git-rev b/git-rev
new file mode 100644
index 0000000..e3d10b1
--- /dev/null
+++ b/git-rev
@@ -0,0 +1 @@
+-g2ab4fc6
diff --git a/guess-rev.sh b/guess-rev.sh
index 7adbe28..140e201 100755
--- a/guess-rev.sh
+++ b/guess-rev.sh
@@ -14,6 +14,13 @@ usage() {
cd "${1:-.}" || usage
+# If there is a file named as "git-rev", just use the revision
+# in that file.
+if [ -e git-rev ]; then
+ awk '{printf $0}' git-rev
+ exit
+fi
+
# Check for git and a git repo.
if head=`git rev-parse --verify --short HEAD 2>/dev/null`; then
@@ -24,7 +31,7 @@ if head=`git rev-parse --verify --short HEAD 2>/dev/null`; then
# If we are past a tagged commit (like "v2.6.30-rc5-302-g72357d5"),
# we pretty print it.
if atag="`git describe 2>/dev/null`"; then
- echo "$atag" | awk -F- '{printf("-%05d-%s", $(NF-1),$(NF))}'
+ echo "$atag" | awk -F- '{printf("-%s", $(NF))}'
# If we don't have a tag at all we print -g{commitish}.
else
diff --git a/lib-link.m4 b/lib-link.m4
new file mode 100644
index 0000000..eeb200d
--- /dev/null
+++ b/lib-link.m4
@@ -0,0 +1,551 @@
+# lib-link.m4 serial 4 (gettext-0.12)
+dnl Copyright (C) 2001-2003 Free Software Foundation, Inc.
+dnl This file is free software, distributed under the terms of the GNU
+dnl General Public License. As a special exception to the GNU General
+dnl Public License, this file may be distributed as part of a program
+dnl that contains a configuration script generated by Autoconf, under
+dnl the same distribution terms as the rest of that program.
+
+dnl From Bruno Haible.
+
+dnl AC_LIB_LINKFLAGS(name [, dependencies]) searches for libname and
+dnl the libraries corresponding to explicit and implicit dependencies.
+dnl Sets and AC_SUBSTs the LIB${NAME} and LTLIB${NAME} variables and
+dnl augments the CPPFLAGS variable.
+AC_DEFUN([AC_LIB_LINKFLAGS],
+[
+ AC_REQUIRE([AC_LIB_PREPARE_PREFIX])
+ AC_REQUIRE([AC_LIB_RPATH])
+ define([Name],[translit([$1],[./-], [___])])
+ define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-],
+ [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])])
+ AC_CACHE_CHECK([how to link with lib[]$1], [ac_cv_lib[]Name[]_libs], [
+ AC_LIB_LINKFLAGS_BODY([$1], [$2])
+ ac_cv_lib[]Name[]_libs="$LIB[]NAME"
+ ac_cv_lib[]Name[]_ltlibs="$LTLIB[]NAME"
+ ac_cv_lib[]Name[]_cppflags="$INC[]NAME"
+ ])
+ LIB[]NAME="$ac_cv_lib[]Name[]_libs"
+ LTLIB[]NAME="$ac_cv_lib[]Name[]_ltlibs"
+ INC[]NAME="$ac_cv_lib[]Name[]_cppflags"
+ AC_LIB_APPENDTOVAR([CPPFLAGS], [$INC]NAME)
+ AC_SUBST([LIB]NAME)
+ AC_SUBST([LTLIB]NAME)
+ dnl Also set HAVE_LIB[]NAME so that AC_LIB_HAVE_LINKFLAGS can reuse the
+ dnl results of this search when this library appears as a dependency.
+ HAVE_LIB[]NAME=yes
+ undefine([Name])
+ undefine([NAME])
+])
+
+dnl AC_LIB_HAVE_LINKFLAGS(name, dependencies, includes, testcode)
+dnl searches for libname and the libraries corresponding to explicit and
+dnl implicit dependencies, together with the specified include files and
+dnl the ability to compile and link the specified testcode. If found, it
+dnl sets and AC_SUBSTs HAVE_LIB${NAME}=yes and the LIB${NAME} and
+dnl LTLIB${NAME} variables and augments the CPPFLAGS variable, and
+dnl #defines HAVE_LIB${NAME} to 1. Otherwise, it sets and AC_SUBSTs
+dnl HAVE_LIB${NAME}=no and LIB${NAME} and LTLIB${NAME} to empty.
+AC_DEFUN([AC_LIB_HAVE_LINKFLAGS],
+[
+ AC_REQUIRE([AC_LIB_PREPARE_PREFIX])
+ AC_REQUIRE([AC_LIB_RPATH])
+ define([Name],[translit([$1],[./-], [___])])
+ define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-],
+ [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])])
+
+ dnl Search for lib[]Name and define LIB[]NAME, LTLIB[]NAME and INC[]NAME
+ dnl accordingly.
+ AC_LIB_LINKFLAGS_BODY([$1], [$2])
+
+ dnl Add $INC[]NAME to CPPFLAGS before performing the following checks,
+ dnl because if the user has installed lib[]Name and not disabled its use
+ dnl via --without-lib[]Name-prefix, he wants to use it.
+ ac_save_CPPFLAGS="$CPPFLAGS"
+ AC_LIB_APPENDTOVAR([CPPFLAGS], [$INC]NAME)
+
+ AC_CACHE_CHECK([for lib[]$1], [ac_cv_lib[]Name], [
+ ac_save_LIBS="$LIBS"
+ LIBS="$LIBS $LIB[]NAME"
+ AC_TRY_LINK([$3], [$4], [ac_cv_lib[]Name=yes], [ac_cv_lib[]Name=no])
+ LIBS="$ac_save_LIBS"
+ ])
+ if test "$ac_cv_lib[]Name" = yes; then
+ HAVE_LIB[]NAME=yes
+ AC_DEFINE([HAVE_LIB]NAME, 1, [Define if you have the $1 library.])
+ AC_MSG_CHECKING([how to link with lib[]$1])
+ AC_MSG_RESULT([$LIB[]NAME])
+ else
+ HAVE_LIB[]NAME=no
+ dnl If $LIB[]NAME didn't lead to a usable library, we don't need
+ dnl $INC[]NAME either.
+ CPPFLAGS="$ac_save_CPPFLAGS"
+ LIB[]NAME=
+ LTLIB[]NAME=
+ fi
+ AC_SUBST([HAVE_LIB]NAME)
+ AC_SUBST([LIB]NAME)
+ AC_SUBST([LTLIB]NAME)
+ undefine([Name])
+ undefine([NAME])
+])
+
+dnl Determine the platform dependent parameters needed to use rpath:
+dnl libext, shlibext, hardcode_libdir_flag_spec, hardcode_libdir_separator,
+dnl hardcode_direct, hardcode_minus_L.
+AC_DEFUN([AC_LIB_RPATH],
+[
+ AC_REQUIRE([AC_PROG_CC]) dnl we use $CC, $GCC, $LDFLAGS
+ AC_REQUIRE([AC_LIB_PROG_LD]) dnl we use $LD, $with_gnu_ld
+ AC_REQUIRE([AC_CANONICAL_HOST]) dnl we use $host
+ AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT]) dnl we use $ac_aux_dir
+ AC_CACHE_CHECK([for shared library run path origin], acl_cv_rpath, [
+ CC="$CC" GCC="$GCC" LDFLAGS="$LDFLAGS" LD="$LD" with_gnu_ld="$with_gnu_ld" \
+ ${CONFIG_SHELL-/bin/sh} "$ac_aux_dir/config.rpath" "$host" > conftest.sh
+ . ./conftest.sh
+ rm -f ./conftest.sh
+ acl_cv_rpath=done
+ ])
+ wl="$acl_cv_wl"
+ libext="$acl_cv_libext"
+ shlibext="$acl_cv_shlibext"
+ hardcode_libdir_flag_spec="$acl_cv_hardcode_libdir_flag_spec"
+ hardcode_libdir_separator="$acl_cv_hardcode_libdir_separator"
+ hardcode_direct="$acl_cv_hardcode_direct"
+ hardcode_minus_L="$acl_cv_hardcode_minus_L"
+ dnl Determine whether the user wants rpath handling at all.
+ AC_ARG_ENABLE(rpath,
+ [ --disable-rpath do not hardcode runtime library paths],
+ :, enable_rpath=yes)
+])
+
+dnl AC_LIB_LINKFLAGS_BODY(name [, dependencies]) searches for libname and
+dnl the libraries corresponding to explicit and implicit dependencies.
+dnl Sets the LIB${NAME}, LTLIB${NAME} and INC${NAME} variables.
+AC_DEFUN([AC_LIB_LINKFLAGS_BODY],
+[
+ define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-],
+ [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])])
+ dnl By default, look in $includedir and $libdir.
+ use_additional=yes
+ AC_LIB_WITH_FINAL_PREFIX([
+ eval additional_includedir=\"$includedir\"
+ eval additional_libdir=\"$libdir\"
+ ])
+ AC_LIB_ARG_WITH([lib$1-prefix],
+[ --with-lib$1-prefix[=DIR] search for lib$1 in DIR/include and DIR/lib
+ --without-lib$1-prefix don't search for lib$1 in includedir and libdir],
+[
+ if test "X$withval" = "Xno"; then
+ use_additional=no
+ else
+ if test "X$withval" = "X"; then
+ AC_LIB_WITH_FINAL_PREFIX([
+ eval additional_includedir=\"$includedir\"
+ eval additional_libdir=\"$libdir\"
+ ])
+ else
+ additional_includedir="$withval/include"
+ additional_libdir="$withval/lib"
+ fi
+ fi
+])
+ dnl Search the library and its dependencies in $additional_libdir and
+ dnl $LDFLAGS. Using breadth-first-seach.
+ LIB[]NAME=
+ LTLIB[]NAME=
+ INC[]NAME=
+ rpathdirs=
+ ltrpathdirs=
+ names_already_handled=
+ names_next_round='$1 $2'
+ while test -n "$names_next_round"; do
+ names_this_round="$names_next_round"
+ names_next_round=
+ for name in $names_this_round; do
+ already_handled=
+ for n in $names_already_handled; do
+ if test "$n" = "$name"; then
+ already_handled=yes
+ break
+ fi
+ done
+ if test -z "$already_handled"; then
+ names_already_handled="$names_already_handled $name"
+ dnl See if it was already located by an earlier AC_LIB_LINKFLAGS
+ dnl or AC_LIB_HAVE_LINKFLAGS call.
+ uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./-|ABCDEFGHIJKLMNOPQRSTUVWXYZ___|'`
+ eval value=\"\$HAVE_LIB$uppername\"
+ if test -n "$value"; then
+ if test "$value" = yes; then
+ eval value=\"\$LIB$uppername\"
+ test -z "$value" || LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$value"
+ eval value=\"\$LTLIB$uppername\"
+ test -z "$value" || LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$value"
+ else
+ dnl An earlier call to AC_LIB_HAVE_LINKFLAGS has determined
+ dnl that this library doesn't exist. So just drop it.
+ :
+ fi
+ else
+ dnl Search the library lib$name in $additional_libdir and $LDFLAGS
+ dnl and the already constructed $LIBNAME/$LTLIBNAME.
+ found_dir=
+ found_la=
+ found_so=
+ found_a=
+ if test $use_additional = yes; then
+ if test -n "$shlibext" && test -f "$additional_libdir/lib$name.$shlibext"; then
+ found_dir="$additional_libdir"
+ found_so="$additional_libdir/lib$name.$shlibext"
+ if test -f "$additional_libdir/lib$name.la"; then
+ found_la="$additional_libdir/lib$name.la"
+ fi
+ else
+ if test -f "$additional_libdir/lib$name.$libext"; then
+ found_dir="$additional_libdir"
+ found_a="$additional_libdir/lib$name.$libext"
+ if test -f "$additional_libdir/lib$name.la"; then
+ found_la="$additional_libdir/lib$name.la"
+ fi
+ fi
+ fi
+ fi
+ if test "X$found_dir" = "X"; then
+ for x in $LDFLAGS $LTLIB[]NAME; do
+ AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+ case "$x" in
+ -L*)
+ dir=`echo "X$x" | sed -e 's/^X-L//'`
+ if test -n "$shlibext" && test -f "$dir/lib$name.$shlibext"; then
+ found_dir="$dir"
+ found_so="$dir/lib$name.$shlibext"
+ if test -f "$dir/lib$name.la"; then
+ found_la="$dir/lib$name.la"
+ fi
+ else
+ if test -f "$dir/lib$name.$libext"; then
+ found_dir="$dir"
+ found_a="$dir/lib$name.$libext"
+ if test -f "$dir/lib$name.la"; then
+ found_la="$dir/lib$name.la"
+ fi
+ fi
+ fi
+ ;;
+ esac
+ if test "X$found_dir" != "X"; then
+ break
+ fi
+ done
+ fi
+ if test "X$found_dir" != "X"; then
+ dnl Found the library.
+ LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$found_dir -l$name"
+ if test "X$found_so" != "X"; then
+ dnl Linking with a shared library. We attempt to hardcode its
+ dnl directory into the executable's runpath, unless it's the
+ dnl standard /usr/lib.
+ if test "$enable_rpath" = no || test "X$found_dir" = "X/usr/lib"; then
+ dnl No hardcoding is needed.
+ LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so"
+ else
+ dnl Use an explicit option to hardcode DIR into the resulting
+ dnl binary.
+ dnl Potentially add DIR to ltrpathdirs.
+ dnl The ltrpathdirs will be appended to $LTLIBNAME at the end.
+ haveit=
+ for x in $ltrpathdirs; do
+ if test "X$x" = "X$found_dir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ ltrpathdirs="$ltrpathdirs $found_dir"
+ fi
+ dnl The hardcoding into $LIBNAME is system dependent.
+ if test "$hardcode_direct" = yes; then
+ dnl Using DIR/libNAME.so during linking hardcodes DIR into the
+ dnl resulting binary.
+ LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so"
+ else
+ if test -n "$hardcode_libdir_flag_spec" && test "$hardcode_minus_L" = no; then
+ dnl Use an explicit option to hardcode DIR into the resulting
+ dnl binary.
+ LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so"
+ dnl Potentially add DIR to rpathdirs.
+ dnl The rpathdirs will be appended to $LIBNAME at the end.
+ haveit=
+ for x in $rpathdirs; do
+ if test "X$x" = "X$found_dir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ rpathdirs="$rpathdirs $found_dir"
+ fi
+ else
+ dnl Rely on "-L$found_dir".
+ dnl But don't add it if it's already contained in the LDFLAGS
+ dnl or the already constructed $LIBNAME
+ haveit=
+ for x in $LDFLAGS $LIB[]NAME; do
+ AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+ if test "X$x" = "X-L$found_dir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir"
+ fi
+ if test "$hardcode_minus_L" != no; then
+ dnl FIXME: Not sure whether we should use
+ dnl "-L$found_dir -l$name" or "-L$found_dir $found_so"
+ dnl here.
+ LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so"
+ else
+ dnl We cannot use $hardcode_runpath_var and LD_RUN_PATH
+ dnl here, because this doesn't fit in flags passed to the
+ dnl compiler. So give up. No hardcoding. This affects only
+ dnl very old systems.
+ dnl FIXME: Not sure whether we should use
+ dnl "-L$found_dir -l$name" or "-L$found_dir $found_so"
+ dnl here.
+ LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name"
+ fi
+ fi
+ fi
+ fi
+ else
+ if test "X$found_a" != "X"; then
+ dnl Linking with a static library.
+ LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_a"
+ else
+ dnl We shouldn't come here, but anyway it's good to have a
+ dnl fallback.
+ LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir -l$name"
+ fi
+ fi
+ dnl Assume the include files are nearby.
+ additional_includedir=
+ case "$found_dir" in
+ */lib | */lib/)
+ basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e 's,/lib/*$,,'`
+ additional_includedir="$basedir/include"
+ ;;
+ esac
+ if test "X$additional_includedir" != "X"; then
+ dnl Potentially add $additional_includedir to $INCNAME.
+ dnl But don't add it
+ dnl 1. if it's the standard /usr/include,
+ dnl 2. if it's /usr/local/include and we are using GCC on Linux,
+ dnl 3. if it's already present in $CPPFLAGS or the already
+ dnl constructed $INCNAME,
+ dnl 4. if it doesn't exist as a directory.
+ if test "X$additional_includedir" != "X/usr/include"; then
+ haveit=
+ if test "X$additional_includedir" = "X/usr/local/include"; then
+ if test -n "$GCC"; then
+ case $host_os in
+ linux*) haveit=yes;;
+ esac
+ fi
+ fi
+ if test -z "$haveit"; then
+ for x in $CPPFLAGS $INC[]NAME; do
+ AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+ if test "X$x" = "X-I$additional_includedir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ if test -d "$additional_includedir"; then
+ dnl Really add $additional_includedir to $INCNAME.
+ INC[]NAME="${INC[]NAME}${INC[]NAME:+ }-I$additional_includedir"
+ fi
+ fi
+ fi
+ fi
+ fi
+ dnl Look for dependencies.
+ if test -n "$found_la"; then
+ dnl Read the .la file. It defines the variables
+ dnl dlname, library_names, old_library, dependency_libs, current,
+ dnl age, revision, installed, dlopen, dlpreopen, libdir.
+ save_libdir="$libdir"
+ case "$found_la" in
+ */* | *\\*) . "$found_la" ;;
+ *) . "./$found_la" ;;
+ esac
+ libdir="$save_libdir"
+ dnl We use only dependency_libs.
+ for dep in $dependency_libs; do
+ case "$dep" in
+ -L*)
+ additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'`
+ dnl Potentially add $additional_libdir to $LIBNAME and $LTLIBNAME.
+ dnl But don't add it
+ dnl 1. if it's the standard /usr/lib,
+ dnl 2. if it's /usr/local/lib and we are using GCC on Linux,
+ dnl 3. if it's already present in $LDFLAGS or the already
+ dnl constructed $LIBNAME,
+ dnl 4. if it doesn't exist as a directory.
+ if test "X$additional_libdir" != "X/usr/lib"; then
+ haveit=
+ if test "X$additional_libdir" = "X/usr/local/lib"; then
+ if test -n "$GCC"; then
+ case $host_os in
+ linux*) haveit=yes;;
+ esac
+ fi
+ fi
+ if test -z "$haveit"; then
+ haveit=
+ for x in $LDFLAGS $LIB[]NAME; do
+ AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+ if test "X$x" = "X-L$additional_libdir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ if test -d "$additional_libdir"; then
+ dnl Really add $additional_libdir to $LIBNAME.
+ LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$additional_libdir"
+ fi
+ fi
+ haveit=
+ for x in $LDFLAGS $LTLIB[]NAME; do
+ AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+ if test "X$x" = "X-L$additional_libdir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ if test -d "$additional_libdir"; then
+ dnl Really add $additional_libdir to $LTLIBNAME.
+ LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$additional_libdir"
+ fi
+ fi
+ fi
+ fi
+ ;;
+ -R*)
+ dir=`echo "X$dep" | sed -e 's/^X-R//'`
+ if test "$enable_rpath" != no; then
+ dnl Potentially add DIR to rpathdirs.
+ dnl The rpathdirs will be appended to $LIBNAME at the end.
+ haveit=
+ for x in $rpathdirs; do
+ if test "X$x" = "X$dir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ rpathdirs="$rpathdirs $dir"
+ fi
+ dnl Potentially add DIR to ltrpathdirs.
+ dnl The ltrpathdirs will be appended to $LTLIBNAME at the end.
+ haveit=
+ for x in $ltrpathdirs; do
+ if test "X$x" = "X$dir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ ltrpathdirs="$ltrpathdirs $dir"
+ fi
+ fi
+ ;;
+ -l*)
+ dnl Handle this in the next round.
+ names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'`
+ ;;
+ *.la)
+ dnl Handle this in the next round. Throw away the .la's
+ dnl directory; it is already contained in a preceding -L
+ dnl option.
+ names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'`
+ ;;
+ *)
+ dnl Most likely an immediate library name.
+ LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$dep"
+ LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$dep"
+ ;;
+ esac
+ done
+ fi
+ else
+ dnl Didn't find the library; assume it is in the system directories
+ dnl known to the linker and runtime loader. (All the system
+ dnl directories known to the linker should also be known to the
+ dnl runtime loader, otherwise the system is severely misconfigured.)
+ LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name"
+ LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-l$name"
+ fi
+ fi
+ fi
+ done
+ done
+ if test "X$rpathdirs" != "X"; then
+ if test -n "$hardcode_libdir_separator"; then
+ dnl Weird platform: only the last -rpath option counts, the user must
+ dnl pass all path elements in one option. We can arrange that for a
+ dnl single library, but not when more than one $LIBNAMEs are used.
+ alldirs=
+ for found_dir in $rpathdirs; do
+ alldirs="${alldirs}${alldirs:+$hardcode_libdir_separator}$found_dir"
+ done
+ dnl Note: hardcode_libdir_flag_spec uses $libdir and $wl.
+ acl_save_libdir="$libdir"
+ libdir="$alldirs"
+ eval flag=\"$hardcode_libdir_flag_spec\"
+ libdir="$acl_save_libdir"
+ LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag"
+ else
+ dnl The -rpath options are cumulative.
+ for found_dir in $rpathdirs; do
+ acl_save_libdir="$libdir"
+ libdir="$found_dir"
+ eval flag=\"$hardcode_libdir_flag_spec\"
+ libdir="$acl_save_libdir"
+ LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag"
+ done
+ fi
+ fi
+ if test "X$ltrpathdirs" != "X"; then
+ dnl When using libtool, the option that works for both libraries and
+ dnl executables is -R. The -R options are cumulative.
+ for found_dir in $ltrpathdirs; do
+ LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-R$found_dir"
+ done
+ fi
+])
+
+dnl AC_LIB_APPENDTOVAR(VAR, CONTENTS) appends the elements of CONTENTS to VAR,
+dnl unless already present in VAR.
+dnl Works only for CPPFLAGS, not for LIB* variables because that sometimes
+dnl contains two or three consecutive elements that belong together.
+AC_DEFUN([AC_LIB_APPENDTOVAR],
+[
+ for element in [$2]; do
+ haveit=
+ for x in $[$1]; do
+ AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+ if test "X$x" = "X$element"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ [$1]="${[$1]}${[$1]:+ }$element"
+ fi
+ done
+])
diff --git a/openocd_blackfin_config.dtd b/openocd_blackfin_config.dtd
new file mode 100644
index 0000000..0681643
--- /dev/null
+++ b/openocd_blackfin_config.dtd
@@ -0,0 +1,11 @@
+<!-- The root element of a Blackfin target config is <blackfin-config>. -->
+
+<!ELEMENT blackfin-config (processor)>
+<!ATTLIST blackfin-config version CDATA #FIXED "1.0">
+
+<!ELEMENT processor (config)>
+<!ATTLIST processor name CDATA #REQUIRED>
+
+<!ELEMENT config EMPTY>
+<!ATTLIST config name CDATA #REQUIRED
+ value CDATA #REQUIRED>
diff --git a/openocd_memory_map.dtd b/openocd_memory_map.dtd
new file mode 100644
index 0000000..239dfbc
--- /dev/null
+++ b/openocd_memory_map.dtd
@@ -0,0 +1,22 @@
+<!-- The root element of a memory map is <memory-map>. -->
+
+<!ELEMENT memory-map (processor)>
+<!ATTLIST memory-map version CDATA #FIXED "1.0">
+
+<!ELEMENT processor (core, memory)>
+<!ATTLIST processor name CDATA #REQUIRED>
+
+<!ELEMENT core (memory)>
+<!ATTLIST core name CDATA #REQUIRED
+ start CDATA #REQUIRED
+ length CDATA #REQUIRED>
+
+<!ELEMENT memory (property)>
+<!ATTLIST memory name CDATA #REQUIRED
+ start CDATA #REQUIRED
+ length CDATA #REQUIRED
+ access CDATA #REQUIRED>
+
+<!ELEMENT property (#PCDATA)>
+<!ATTLIST property name CDATA #REQUIRED>
+
diff --git a/src/Makefile.am b/src/Makefile.am
index 26e02d0..d45c579 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -30,6 +30,8 @@ if ULINK
openocd_LDADD += -lm
endif
+openocd_LDADD += $(LIBEXPAT)
+
libopenocd_la_SOURCES = \
hello.c \
openocd.c
diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am
index 878fc26..a727a21 100644
--- a/src/flash/nor/Makefile.am
+++ b/src/flash/nor/Makefile.am
@@ -9,6 +9,7 @@ libocdflashnor_la_SOURCES = \
NOR_DRIVERS = \
aduc702x.c \
+ aducm302x.c \
at91sam4.c \
at91sam4l.c \
at91samd.c \
diff --git a/src/flash/nor/aducm302x.c b/src/flash/nor/aducm302x.c
new file mode 100644
index 0000000..723ea93
--- /dev/null
+++ b/src/flash/nor/aducm302x.c
@@ -0,0 +1,593 @@
+/***************************************************************************
+ * Copyright (C) 2014, 2016 Analog Devices, 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 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+//#include "jtag/interface.h"
+#include "imp.h"
+#include <target/algorithm.h>
+#include <target/armv7m.h>
+
+
+/* ADuCM302x ID registers */
+#define SYS_ADIID 0x40002020
+#define SYS_CHIPID 0x40002024
+
+/* ADuCM302x cache flash control registers */
+#define STAT 0x40018000
+#define IEN 0x40018004
+#define CMD 0x40018008
+#define KH_ADDR 0x4001800c
+#define KH_DATA0 0x40018010
+#define KH_DATA1 0x40018014
+#define PAGE_ADDR0 0x40018018
+#define PAGE_ADDR1 0x4001801c
+#define KEY 0x40018020
+#define WR_ABORT_ADDR 0x40018024
+#define WRPROT 0x40018028
+#define SIGNATURE 0x4001802c
+#define UCFG 0x40018030
+#define TIME_PARAM0 0x40018034
+#define TIME_PARAM1 0x40018038
+#define ABORT_EN_LO 0x4001803c
+#define ABORT_EN_HI 0x40018040
+#define ECC_CFG 0x40018044
+#define ECC_ADDR 0x40018048
+
+#define USER_KEY 0x676c7565
+
+#define STAT_CMDBUSY (1 << 0)
+#define STAT_WRCLOSE (1 << 1)
+#define STAT_CMDCOMP (1 << 2)
+#define STAT_WRALCOMP (1 << 3)
+#define STAT_CMDFAIL_MASK (3 << 4)
+#define STAT_CMDFAIL_SUCCESS (0 << 4)
+#define STAT_CMDFAIL_IGNORED (1 << 4)
+#define STAT_CMDFAIL_VERIFY_ERR (2 << 4)
+#define STAT_CMDFAIL_ABORT (3 << 4)
+#define STAT_SLEEPING (1 << 6)
+#define STAT_ECCERRCMD_MASK (3 << 7)
+#define STAT_ECCERRCMD_SUCCESS (0 << 7)
+#define STAT_ECCERRCMD_ERR_2BIT (1 << 7)
+#define STAT_ECCERRCMD_ERR_1BIT (2 << 7)
+#define STAT_ECCERRCMD_ERR_1OR2 (3 << 7)
+#define STAT_ECCRDERR_MASK (3 << 9)
+#define STAT_ECCRDERR_SUCCESS (0 << 9)
+#define STAT_ECCRDERR_ERR_2BIT (1 << 9)
+#define STAT_ECCRDERR_ERR_1BIT (2 << 9)
+#define STAT_ECCRDERR_ERR_1OR2 (3 << 9)
+#define STAT_OVERLAP (1 << 11)
+#define STAT_SIGNERR (1 << 13)
+#define STAT_INIT (1 << 14)
+#define STAT_ECCINFOSIGN_MASK (2 << 15)
+#define STAT_ECCINFOSIGN_SUCCESS (0 << 15)
+#define STAT_ECCINFOSIGN_ERR_2BIT (1 << 15)
+#define STAT_ECCINFOSIGN_ERR_1BIT (2 << 15)
+#define STAT_ECCINFOSIGN_ERR_1OR2 (3 << 15)
+#define STAT_ECCERRCNT_MASK (7 << 17)
+#define STAT_ECCICODE_MASK (3 << 25)
+#define STAT_ECCICODE_SUCCESS (0 << 25)
+#define STAT_ECCICODE_ERR_2BIT (1 << 25)
+#define STAT_ECCICODE_ERR_1BIT (2 << 25)
+#define STAT_ECCDCODE_MASK (3 << 27)
+#define STAT_ECCDCODE_SUCCESS (0 << 27)
+#define STAT_ECCDCODE_ERR_2BIT (1 << 27)
+#define STAT_ECCDCODE_ERR_1BIT (2 << 27)
+#define STAT_CACHESRAMPERR (1 << 29)
+
+#define CMD_IDLE 0
+#define CMD_ABORT 1
+#define CMD_SLEEP 2
+#define CMD_SIGN 3
+#define CMD_WRITE 4
+#define CMD_CHECK 5
+#define CMD_ERASEPAGE 6
+#define CMD_MASSERASE 7
+
+struct aducm302x_flash_bank {
+ const char *target_name;
+ bool probed;
+
+ /* flash geometry */
+ uint32_t pagesize;
+};
+
+static int aducm302x_probe(struct flash_bank *bank)
+{
+ struct target *target = bank->target;
+ struct aducm302x_flash_bank *aducm302x_info = bank->driver_priv;
+ uint16_t adiid, chipid;
+ int i;
+
+ LOG_DEBUG("bank=%p", bank);
+
+ if (aducm302x_info->probed)
+ return ERROR_OK;
+
+ /* Read ID register to make sure this is an ADuCM302x */
+ target_read_u16(target, SYS_ADIID, &adiid);
+ target_read_u16(target, SYS_CHIPID, &chipid);
+ LOG_DEBUG("ADIID 0x%" PRIx16 ", CHIPID 0x%" PRIx16 "", adiid, chipid);
+
+ if (adiid != 0x4144) {
+ LOG_WARNING("not an Analog Devices implemented Cortex based part");
+ return ERROR_FLASH_OPERATION_FAILED;
+ }
+
+ if (chipid != 0x0282) {
+ LOG_WARNING("unknown part (not ADuCM3027/9)");
+ return ERROR_FLASH_OPERATION_FAILED;
+ }
+
+ /* Clear the remap bit */
+ target_write_u32(target, 0x40018054, 0x1);
+
+ aducm302x_info->pagesize = 2048;
+ bank->num_sectors = bank->size / aducm302x_info->pagesize;
+ bank->sectors = malloc(bank->num_sectors * sizeof(struct flash_sector));
+ if (bank->sectors == NULL) {
+ LOG_ERROR("malloc failed");
+ return ERROR_FAIL;
+ }
+ for (i = 0; i < bank->num_sectors; i++) {
+ bank->sectors[i].offset = i * aducm302x_info->pagesize;
+ bank->sectors[i].size = aducm302x_info->pagesize;
+ bank->sectors[i].is_erased = -1;
+ bank->sectors[i].is_protected = -1;
+ }
+
+ aducm302x_info->probed = true;
+
+ return ERROR_OK;
+}
+
+static int aducm302x_check_cmdfail(uint32_t flash_stat)
+{
+ if ((flash_stat & STAT_CMDFAIL_MASK) == STAT_CMDFAIL_SUCCESS)
+ return ERROR_OK;
+
+ if ((flash_stat & STAT_CMDFAIL_MASK) == STAT_CMDFAIL_IGNORED)
+ LOG_ERROR("command ignored for attempted access of a protected or out of memory location)");
+ else if ((flash_stat & STAT_CMDFAIL_MASK) == STAT_CMDFAIL_VERIFY_ERR)
+ LOG_ERROR("verify error occurred for failed erase or failed signature check");
+ else if ((flash_stat & STAT_CMDFAIL_MASK) == STAT_CMDFAIL_ABORT)
+ LOG_ERROR("command aborted by either user code or a system interrupt");
+
+ return ERROR_FLASH_OPERATION_FAILED;
+}
+
+static int aducm302x_mass_erase(struct flash_bank *bank)
+{
+ struct target *target = bank->target;
+ uint32_t flash_stat;
+ int retval, i;
+
+ /* Write user key */
+ target_write_u32(target, KEY, USER_KEY);
+ /* Write massive erase command */
+ target_write_u32(target, CMD, CMD_MASSERASE);
+ /* Wait until erase complete */
+ do {
+ target_read_u32(target, STAT, &flash_stat);
+ } while ((flash_stat & STAT_CMDCOMP) == 0);
+
+ retval = aducm302x_check_cmdfail(flash_stat);
+ if (retval != ERROR_OK)
+ return retval;
+
+ for (i = 0; i < bank->num_sectors; i++)
+ bank->sectors[i].is_erased = 1;
+
+ return ERROR_OK;
+}
+
+static int aducm302x_erase(struct flash_bank *bank, int first, int last)
+{
+ struct aducm302x_flash_bank *aducm302x_info = bank->driver_priv;
+ struct target *target = bank->target;
+ uint32_t flash_stat;
+ int retval, i;
+
+ LOG_DEBUG("bank=%p first=%d last = %d", bank, first, last);
+
+ if (target->state != TARGET_HALTED) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ if (!aducm302x_info->probed)
+ return ERROR_FLASH_BANK_NOT_PROBED;
+
+ if (first < 0 || last < first || last >= bank->num_sectors)
+ return ERROR_FLASH_SECTOR_INVALID;
+
+ if (first == 0 && last == bank->num_sectors - 1) {
+ retval = aducm302x_mass_erase(bank);
+ return retval;
+ }
+
+ for (i = first; i <= last; i++) {
+ /* Address is first word in page */
+ target_write_u32(target, PAGE_ADDR0, i * aducm302x_info->pagesize);
+ /* Write user key */
+ target_write_u32(target, KEY, USER_KEY);
+ /* Write page erase command */
+ target_write_u32(target, CMD, CMD_ERASEPAGE);
+ /* Wait until erase complete */
+ do {
+ target_read_u32(target, STAT, &flash_stat);
+ } while ((flash_stat & STAT_CMDCOMP) == 0);
+
+ retval = aducm302x_check_cmdfail(flash_stat);
+ if (retval != ERROR_OK)
+ return retval;
+
+ bank->sectors[i].is_erased = 1;
+ }
+
+ return ERROR_OK;
+}
+
+static int aducm302x_protect(struct flash_bank *bank, int set, int first, int last)
+{
+ struct aducm302x_flash_bank *aducm302x_info = bank->driver_priv;
+ struct target *target = bank->target;
+ uint32_t wrprot;
+ int i;
+
+ if (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");
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+
+ if (!aducm302x_info->probed)
+ return ERROR_FLASH_BANK_NOT_PROBED;
+
+ /* One protect block has 4 pages. So the first should be 0, 4, 8, ...
+ The last should be 3, 7, 11, ... */
+ if (first < 0 || (first & 0x3) || last <= first || (last & 0x3) != 0x3
+ || last >= 4 * 32) {
+ LOG_ERROR("Can't protect unaligned or out-of-range pages.");
+ return ERROR_FLASH_SECTOR_INVALID;
+ }
+
+ /* Convert from pages to protect blocks */
+ first /= 4;
+ last /= 4;
+
+ target_read_u32(target, WRPROT, &wrprot);
+
+ for (i = first; i <= last; i++)
+ wrprot &= ~(1 << i);
+
+ LOG_DEBUG("WRPROT 0x%"PRIx32, wrprot);
+
+ target_write_u32(target, WRPROT, wrprot);
+
+ return ERROR_OK;
+}
+
+static int aducm302x_protect_check(struct flash_bank *bank)
+{
+ struct aducm302x_flash_bank *aducm302x_info = bank->driver_priv;
+ struct target *target = bank->target;
+ uint32_t wrprot;
+ int i;
+
+ if (target->state != TARGET_HALTED) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ if (!aducm302x_info->probed)
+ return ERROR_FLASH_BANK_NOT_PROBED;
+
+ for (i = 0; i < bank->num_sectors; i++)
+ bank->sectors[i].is_protected = -1;
+
+ target_read_u32(target, WRPROT, &wrprot);
+
+ for (i = 0; i < 32; i++) {
+ bank->sectors[i * 4].is_protected = !(wrprot & (1 << i));
+ bank->sectors[i * 4 + 1].is_protected = !(wrprot & (1 << i));
+ bank->sectors[i * 4 + 2].is_protected = !(wrprot & (1 << i));
+ bank->sectors[i * 4 + 3].is_protected = !(wrprot & (1 << i));
+ }
+
+ return ERROR_OK;
+}
+
+/* see contrib/loaders/flash/aducm302x.s for source code */
+static const uint8_t aducm302x_write_code[] = {
+ /* write: */
+ 0xdf, 0xf8, 0x4c, 0x40,
+ 0x13, 0x4d,
+ /* wait_fifo: */
+ 0xd0, 0xf8, 0x00, 0x80,
+ 0xb8, 0xf1, 0x00, 0x0f,
+ 0x00, 0xf0, 0x1e, 0x80,
+ 0x47, 0x68,
+ 0x47, 0x45,
+ 0x3f, 0xf4, 0xf6, 0xaf,
+ /* mainloop: */
+ 0xe2, 0x60,
+ 0x02, 0xf1, 0x08, 0x02,
+ 0x57, 0xf8, 0x04, 0x6b,
+ 0x57, 0xf8, 0x04, 0x8b,
+ 0x26, 0x61,
+ 0xc4, 0xf8, 0x14, 0x80,
+ 0xa5, 0x60,
+ /* busy: */
+ 0xd4, 0xf8, 0x00, 0x80,
+ 0x18, 0xf0, 0x04, 0x0f,
+ 0x3f, 0xf4, 0xfa, 0xaf,
+ 0x8f, 0x42,
+ 0x28, 0xbf,
+ 0x00, 0xf1, 0x08, 0x07,
+ 0x47, 0x60,
+ 0x01, 0x3b,
+ 0x0b, 0xb1,
+ 0xff, 0xf7, 0xdc, 0xbf,
+ /* exit: */
+ 0x00, 0xbe,
+ /* pFLASH_CTRL_BASE: */
+ 0x00, 0x80, 0x01, 0x40,
+ /* FLASHWRITECMD: */
+ 0x04, 0x00, 0x00, 0x00
+};
+
+static int aducm302x_write_block(struct flash_bank *bank, const uint8_t *buffer,
+ uint32_t offset, uint32_t dwcount)
+{
+ struct target *target = bank->target;
+ uint32_t buffer_size = 16384 + 8; /* 8 bytes for wp and rp */
+ 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;
+
+ /* power of two, and multiple of 8 bytes */
+ static const unsigned buf_min = 128;
+
+ LOG_DEBUG("bank=%p buffer=%p offset=%08"PRIx32" dwcount=%"PRIx32,
+ bank, buffer, offset, dwcount);
+
+ /* For small buffers it's faster not to download the algorithm */
+ if (dwcount * 8 < buf_min)
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+
+ /* flash write code */
+ if (target_alloc_working_area(target, sizeof(aducm302x_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 (dwcount * 8 < buffer_size)
+ buffer_size = dwcount * 8 + 8;
+
+ /* memory buffer */
+ while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) {
+ buffer_size = (buffer_size - 8) / 2;
+ /* make sure it's multiple of 8 bytes */
+ buffer_size = buffer_size / 8 * 8;
+ if (buffer_size <= buf_min) {
+ target_free_working_area(target, write_algorithm);
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+ }
+ /* 8 bytes for wp and rp */
+ buffer_size += 8;
+ LOG_DEBUG("retry target_alloc_working_area(%s, size=%"PRIu32")",
+ target_name(target), buffer_size);
+ }
+
+ target_write_buffer(target, write_algorithm->address,
+ sizeof(aducm302x_write_code), aducm302x_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, dwcount);
+
+ retval = target_run_flash_async_algorithm(target,
+ buffer, dwcount, 8,
+ 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 ADuCM302x 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[0]);
+ destroy_reg_param(®_params[0]);
+ destroy_reg_param(®_params[0]);
+
+ return retval;
+}
+
+static int aducm302x_write(struct flash_bank *bank, const uint8_t *buffer,
+ uint32_t offset, uint32_t count)
+{
+ struct aducm302x_flash_bank *aducm302x_info = bank->driver_priv;
+ struct target *target = bank->target;
+ uint32_t address = offset;
+ uint32_t dwords_remaining, bytes_remaining;
+ uint32_t flash_stat;
+ int retval;
+
+ LOG_DEBUG("bank=%p buffer=%p offset=%08"PRIx32" count=%"PRIx32,
+ bank, buffer, offset, count);
+
+ if (bank->target->state != TARGET_HALTED) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ if (!aducm302x_info->probed)
+ return ERROR_FLASH_BANK_NOT_PROBED;
+
+ if (offset & 0x7) {
+ uint8_t first_dword[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+ /* read the bytes from target into the write buffer */
+ target_read_buffer(target, offset & (~ 0x7), offset & 0x7, first_dword);
+
+ bytes_remaining = 8 - (offset & 0x7);
+ if (bytes_remaining > count)
+ bytes_remaining = count;
+ memcpy(first_dword + (offset & 0x7), buffer, bytes_remaining);
+
+ /* write one double word */
+ target_write_u32(target, KH_ADDR, address & (~ 0x7));
+ target_write_buffer(target, KH_DATA0, 4, first_dword);
+ target_write_buffer(target, KH_DATA1, 4, first_dword + 4);
+ target_write_u32(target, CMD, CMD_WRITE);
+
+ do {
+ target_read_u32(target, STAT, &flash_stat);
+ } while ((flash_stat & STAT_CMDCOMP) == 0);
+
+ retval = aducm302x_check_cmdfail(flash_stat);
+ if (retval != ERROR_OK)
+ return retval;
+
+ count -= bytes_remaining;
+ address &= ~ 0x7;
+ }
+
+ dwords_remaining = count / 8;
+ bytes_remaining = count % 8;
+
+ if (dwords_remaining > 0) {
+ retval = aducm302x_write_block(bank, buffer, offset, dwords_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) {
+ LOG_ERROR("flash writing failed");
+ return ERROR_FLASH_OPERATION_FAILED;
+ }
+ } else {
+ buffer += dwords_remaining * 8;
+ address += dwords_remaining * 8;
+ dwords_remaining = 0;
+ }
+ }
+
+ while (dwords_remaining > 0) {
+ target_write_u32(target, KH_ADDR, address);
+ target_write_buffer(target, KH_DATA0, 4, buffer);
+ target_write_buffer(target, KH_DATA1, 4, buffer + 4);
+ target_write_u32(target, CMD, CMD_WRITE);
+
+ do {
+ target_read_u32(target, STAT, &flash_stat);
+ } while ((flash_stat & STAT_CMDCOMP) == 0);
+
+ retval = aducm302x_check_cmdfail(flash_stat);
+ if (retval != ERROR_OK)
+ return retval;
+
+ buffer += 8;
+ address += 8;
+ dwords_remaining--;
+ }
+
+ 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_remaining);
+
+ /* write one double word */
+ target_write_u32(target, KH_ADDR, address);
+ target_write_buffer(target, KH_DATA0, 4, last_dword);
+ target_write_buffer(target, KH_DATA1, 4, last_dword + 4);
+ target_write_u32(target, CMD, CMD_WRITE);
+
+ do {
+ target_read_u32(target, STAT, &flash_stat);
+ } while ((flash_stat & STAT_CMDCOMP) == 0);
+
+ retval = aducm302x_check_cmdfail(flash_stat);
+ if (retval != ERROR_OK)
+ return retval;
+ }
+
+ return ERROR_OK;
+}
+
+FLASH_BANK_COMMAND_HANDLER(aducm302x_flash_bank_command)
+{
+ struct aducm302x_flash_bank *aducm302x_info;
+
+ if (CMD_ARGC < 6)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ aducm302x_info = calloc(sizeof(struct aducm302x_flash_bank), 1);
+ bank->base = 0x0;
+ bank->driver_priv = aducm302x_info;
+
+ aducm302x_info->target_name = "ADuCM302x";
+
+ /* part wasn't probed for info yet */
+ aducm302x_info->probed = false;
+
+ return ERROR_OK;
+}
+
+struct flash_driver aducm302x_flash = {
+ .name = "aducm302x",
+ .usage = NULL,
+ .commands = NULL,
+ .flash_bank_command = aducm302x_flash_bank_command,
+ .erase = aducm302x_erase,
+ .protect = aducm302x_protect,
+ .write = aducm302x_write,
+ .read = default_flash_read,
+ .probe = aducm302x_probe,
+ .erase_check = default_flash_blank_check,
+ .protect_check = aducm302x_protect_check,
+ .info = NULL,
+ .auto_probe = aducm302x_probe,
+};
diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c
index fead797..b267482 100644
--- a/src/flash/nor/drivers.c
+++ b/src/flash/nor/drivers.c
@@ -59,6 +59,7 @@ extern struct flash_driver nrf51_flash;
extern struct flash_driver mrvlqspi_flash;
extern struct flash_driver psoc4_flash;
extern struct flash_driver sim3x_flash;
+extern struct flash_driver aducm302x_flash;
/**
* The list of built-in flash drivers.
@@ -102,6 +103,7 @@ static struct flash_driver *flash_drivers[] = {
&mrvlqspi_flash,
&psoc4_flash,
&sim3x_flash,
+ &aducm302x_flash,
NULL,
};
diff --git a/src/flash/nor/lpcspifi.c b/src/flash/nor/lpcspifi.c
index 3b383eb..402f5f5 100644
--- a/src/flash/nor/lpcspifi.c
+++ b/src/flash/nor/lpcspifi.c
@@ -195,7 +195,7 @@ static int lpcspifi_set_hw_mode(struct flash_bank *bank)
+ SPIFI_INIT_STACK_SIZE, &spifi_init_algorithm);
if (retval != ERROR_OK) {
LOG_ERROR("Insufficient working area to initialize SPIFI "\
- "module. You must allocate at least %zdB of working "\
+ "module. You must allocate at least %"PRIzd"B of working "\
"area in order to use this driver.",
sizeof(spifi_init_code) + SPIFI_INIT_STACK_SIZE
);
@@ -537,7 +537,7 @@ static int lpcspifi_erase(struct flash_bank *bank, int first, int last)
&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.",
+ " area of at least %"PRIzd"B in order to erase SPIFI flash.",
sizeof(lpcspifi_flash_erase_code));
return retval;
}
@@ -695,7 +695,7 @@ static int lpcspifi_write(struct flash_bank *bank, const uint8_t *buffer,
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.",
+ " a working area > %"PRIzd"B in order to write to SPIFI flash.",
sizeof(lpcspifi_flash_write_code));
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
};
@@ -717,14 +717,14 @@ static int lpcspifi_write(struct flash_bank *bank, const uint8_t *buffer,
target_free_working_area(target, write_algorithm);
LOG_ERROR("Insufficient working area. Please allocate at least"\
- " %zdB of working area to enable flash writes.",
+ " %"PRIzd"B 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"\
+ " slow. Increase working area size to at least %"PRIzd"B"\
" to reduce write times.",
(size_t)(sizeof(lpcspifi_flash_write_code) + page_size)
);
diff --git a/src/flash/nor/mrvlqspi.c b/src/flash/nor/mrvlqspi.c
index 0dfe6f8..e135528 100644
--- a/src/flash/nor/mrvlqspi.c
+++ b/src/flash/nor/mrvlqspi.c
@@ -677,7 +677,7 @@ static int mrvlqspi_flash_write(struct flash_bank *bank, const uint8_t *buffer,
if (target_alloc_working_area(target, sizeof(mrvlqspi_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.",
+ " a working area > %"PRIz"dB in order to write to SPIFI flash.",
sizeof(mrvlqspi_flash_write_code));
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
};
@@ -699,14 +699,14 @@ static int mrvlqspi_flash_write(struct flash_bank *bank, const uint8_t *buffer,
target_free_working_area(target, write_algorithm);
LOG_ERROR("Insufficient working area. Please allocate at least"\
- " %zdB of working area to enable flash writes.",
+ " %"PRIz"dB of working area to enable flash writes.",
sizeof(mrvlqspi_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"\
+ " slow. Increase working area size to at least %"PRIz"dB"\
" to reduce write times.",
(size_t)(sizeof(mrvlqspi_flash_write_code) + page_size)
);
diff --git a/src/helper/command.h b/src/helper/command.h
index 0eda5b5..74bbd45 100644
--- a/src/helper/command.h
+++ b/src/helper/command.h
@@ -26,14 +26,7 @@
#include <jim-nvp.h>
-/* 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,
diff --git a/src/helper/configuration.c b/src/helper/configuration.c
index dde1491..50be4e0 100644
--- a/src/helper/configuration.c
+++ b/src/helper/configuration.c
@@ -33,6 +33,8 @@ static char **config_file_names;
static size_t num_script_dirs;
static char **script_search_dirs;
+static char* firmware_file_name;
+
void add_script_search_dir(const char *dir)
{
num_script_dirs++;
@@ -170,3 +172,17 @@ char *get_home_dir(const char *append_path)
return home_path;
}
+
+int set_firmware_filename(const char *filename)
+{
+ firmware_file_name = strdup(filename);
+ if (firmware_file_name)
+ return ERROR_OK;
+ else
+ return ERROR_FAIL;
+}
+
+char *get_firmware_filename(void)
+{
+ return firmware_file_name;
+}
diff --git a/src/helper/configuration.h b/src/helper/configuration.h
index 7b9f711..7cdc317 100644
--- a/src/helper/configuration.h
+++ b/src/helper/configuration.h
@@ -42,4 +42,7 @@ 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);
+int set_firmware_filename(const char *name);
+char *get_firmware_filename(void);
+
#endif /* CONFIGURATION_H */
diff --git a/src/helper/log.c b/src/helper/log.c
index c15b95d..414411b 100644
--- a/src/helper/log.c
+++ b/src/helper/log.c
@@ -412,12 +412,12 @@ void keep_alive()
if (gdb_actual_connections)
LOG_WARNING("keep_alive() was not invoked in the "
"1000ms timelimit. GDB alive packet not "
- "sent! (%lld). Workaround: increase "
+ "sent! (%"PRIlld"). 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 "
+ "1000ms timelimit (%"PRIlld"). This may cause "
"trouble with GDB connections.",
current_time-last_time);
}
diff --git a/src/helper/log.h b/src/helper/log.h
index 7f9f32c..e0b46a6 100644
--- a/src/helper/log.h
+++ b/src/helper/log.h
@@ -29,13 +29,22 @@
#include <helper/command.h>
-/* 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
+#ifdef IS_MINGW
+ #define PRIzu "Iu"
+ #define PRIzd "Id"
+ #define PRIzx "Ix"
+ #define PRIju "I64u"
+ #define PRIjd "I64d"
+ #define PRIllu "I64u"
+ #define PRIlld "I64d"
#else
-#define PRINTF_ATTRIBUTE_FORMAT printf
+ #define PRIzu "zu"
+ #define PRIzd "zd"
+ #define PRIzx "zx"
+ #define PRIju "ju"
+ #define PRIjd "jd"
+ #define PRIllu "llu"
+ #define PRIlld "lld"
#endif
/* logging priorities
diff --git a/src/helper/replacements.h b/src/helper/replacements.h
index 2776602..6d43425 100644
--- a/src/helper/replacements.h
+++ b/src/helper/replacements.h
@@ -132,6 +132,14 @@ static inline unsigned usleep(unsigned int usecs)
#endif
#endif /* HAVE_USLEEP */
+#ifndef HAVE_NANOSLEEP
+#include <unistd.h>
+#ifndef HAVE_STRUCT_TIMESPEC
+struct timespec { unsigned long tv_sec, tv_nsec; };
+#endif
+#define nanosleep(req, rem) usleep((req)->tv_sec * 1000 * 1000 + (req)->tv_nsec / 1000)
+#endif
+
/* Windows specific */
#ifdef _WIN32
diff --git a/src/helper/types.h b/src/helper/types.h
index 3f0724c..daee0ae 100644
--- a/src/helper/types.h
+++ b/src/helper/types.h
@@ -289,6 +289,12 @@ static inline int parity_u32(uint32_t x)
#endif
}
+#ifdef _WIN32
+#define PRIz "I"
+#else
+#define PRIz "z"
+#endif
+
#if defined(__ECOS)
/* eCos plain lacks these definition... A series of upstream patches
diff --git a/src/jtag/adapter.c b/src/jtag/adapter.c
index 2f5f6b4..5d626aa 100644
--- a/src/jtag/adapter.c
+++ b/src/jtag/adapter.c
@@ -49,6 +49,7 @@
extern struct jtag_interface *jtag_interface;
const char * const jtag_only[] = { "jtag", NULL };
+const char * const jtag_and_swd[] = { "jtag", "swd", NULL };
static int jim_adapter_name(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
{
diff --git a/src/jtag/core.c b/src/jtag/core.c
index 74c2731..a3b84e0 100644
--- a/src/jtag/core.c
+++ b/src/jtag/core.c
@@ -132,6 +132,11 @@ static struct jtag_interface *jtag;
/* configuration */
struct jtag_interface *jtag_interface;
+const char *jtag_get_name(void)
+{
+ return jtag == NULL ? NULL : jtag->name;
+}
+
void jtag_set_flush_queue_sleep(int ms)
{
jtag_flush_queue_sleep = ms;
@@ -1392,7 +1397,6 @@ int jtag_init_inner(struct command_context *cmd_ctx)
{
struct jtag_tap *tap;
int retval;
- bool issue_setup = true;
LOG_DEBUG("Init JTAG chain");
@@ -1425,24 +1429,8 @@ int jtag_init_inner(struct command_context *cmd_ctx)
* 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;
- }
+ if (retval != ERROR_OK)
+ return retval;
/* Now look at IR values. Problems here will prevent real
* communication. They mostly mean that the IR length is
@@ -1451,19 +1439,10 @@ int jtag_init_inner(struct command_context *cmd_ctx)
* 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");
+ if (retval != ERROR_OK)
+ return retval;
+ jtag_notify_event(JTAG_TAP_EVENT_SETUP);
return ERROR_OK;
}
diff --git a/src/jtag/drivers/Makefile.am b/src/jtag/drivers/Makefile.am
index aea2b38..d18197d 100644
--- a/src/jtag/drivers/Makefile.am
+++ b/src/jtag/drivers/Makefile.am
@@ -126,6 +126,13 @@ endif
if OPENJTAG
DRIVERFILES += openjtag.c
endif
+if ICE_1000
+DRIVERFILES += ice1000.c
+else
+if ICE_2000
+DRIVERFILES += ice1000.c
+endif
+endif
if CMSIS_DAP
DRIVERFILES += cmsis_dap_usb.c
diff --git a/src/jtag/drivers/ft2232.c b/src/jtag/drivers/ft2232.c
index 6f8a0fc..ab6c961 100644
--- a/src/jtag/drivers/ft2232.c
+++ b/src/jtag/drivers/ft2232.c
@@ -83,6 +83,7 @@
#include <jtag/interface.h>
#include <transport/transport.h>
#include <helper/time_support.h>
+#include "ft2232.h"
#if IS_CYGWIN == 1
#include <windows.h>
@@ -195,6 +196,7 @@ static int lisa_l_init(void);
static int flossjtag_init(void);
static int xds100v2_init(void);
static int digilent_hs1_init(void);
+static int gnice_init(void);
/* reset procedures for supported layouts */
static void ftx23_reset(int trst, int srst);
@@ -214,6 +216,7 @@ 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);
+static void gnice_reset(int trst, int srst);
/* blink procedures for layouts that support a blinking led */
static void olimex_jtag_blink(void);
@@ -224,6 +227,7 @@ static void signalyzer_h_blink(void);
static void ktlink_blink(void);
static void lisa_l_blink(void);
static void flossjtag_blink(void);
+static void gnice_blink(void);
/* common transport support options */
@@ -345,6 +349,11 @@ static const struct ft2232_layout ft2232_layouts[] = {
.reset = digilent_hs1_reset,
.channel = INTERFACE_A,
},
+ { .name = "gnice",
+ .init = gnice_init,
+ .reset = gnice_reset,
+ .blink = gnice_blink,
+ },
{ .name = NULL, /* END OF TABLE */ },
};
@@ -596,7 +605,7 @@ static int ft2232_read(uint8_t *buf, uint32_t size, uint32_t *bytes_read)
return ERROR_OK;
}
-static bool ft2232_device_is_highspeed(void)
+bool ft2232_device_is_highspeed()
{
#if BUILD_FT2232_FTD2XX == 1
return (ftdi_device == FT_DEVICE_2232H) || (ftdi_device == FT_DEVICE_4232H)
@@ -4248,6 +4257,57 @@ static void digilent_hs1_reset(int trst, int srst)
/* Dummy function, no reset signals supported. */
}
+/********************************************************************
+ * Support for gnICE
+ *******************************************************************/
+
+static int gnice_init(void)
+{
+ nTRST = 0x2;
+
+ low_output = 0x8; /* TMS */
+ low_direction = 0xb; /* TCK | TDI | TMS */
+
+ if (ft2232_set_data_bits_low_byte(low_output,low_direction) != ERROR_OK) {
+ LOG_ERROR("couldn't initialize FT2232 with 'gnICE' layout");
+ return ERROR_JTAG_INIT_FAILED;
+ }
+
+ high_output = 0x2; /* nTRST */
+ high_direction = 0xa; /* nTRST | nLED */
+
+ if (ft2232_set_data_bits_high_byte(high_output,high_direction) != ERROR_OK)
+ {
+ LOG_ERROR("couldn't initialize FT2232 with 'gnICE' layout");
+ return ERROR_JTAG_INIT_FAILED;
+ }
+
+ return ERROR_OK;
+}
+
+static void gnice_reset(int trst, int srst)
+{
+ if (trst == 1)
+ high_output &= ~nTRST;
+ else if (trst == 0)
+ high_output |= nTRST;
+
+ buffer_write(0x82);
+ buffer_write(high_output);
+ buffer_write(high_direction);
+ LOG_DEBUG("trst: %i, high_output: 0x%2.2x, high_direction: 0x%2.2x", trst, high_output, high_direction);
+}
+
+static void gnice_blink(void)
+{
+ /* LED connected to ACBUS3 */
+ high_output ^= 0x08;
+
+ buffer_write(0x82); // command "set data bits high byte"
+ buffer_write(high_output);
+ buffer_write(high_direction);
+}
+
static const struct command_registration ft2232_command_handlers[] = {
{
.name = "ft2232_device_desc",
diff --git a/src/jtag/drivers/ft2232.h b/src/jtag/drivers/ft2232.h
new file mode 100644
index 0000000..951213c
--- /dev/null
+++ b/src/jtag/drivers/ft2232.h
@@ -0,0 +1 @@
+extern bool ft2232_device_is_highspeed(void);
diff --git a/src/jtag/drivers/ftdi.c b/src/jtag/drivers/ftdi.c
index 14c5908..1a94a6c 100644
--- a/src/jtag/drivers/ftdi.c
+++ b/src/jtag/drivers/ftdi.c
@@ -598,18 +598,18 @@ static void ftdi_execute_command(struct jtag_command *cmd)
static int ftdi_execute_queue(void)
{
/* blink, if the current layout has that feature */
+ static int on = 0;
struct signal *led = find_signal_by_name("LED");
- if (led)
- ftdi_set_signal(led, '1');
+ if (led) {
+ ftdi_set_signal(led, on ? '1' : '0');
+ on ^= 1;
+ }
for (struct jtag_command *cmd = jtag_command_queue; cmd; cmd = cmd->next) {
/* fill the write buffer with the desired command */
ftdi_execute_command(cmd);
}
- if (led)
- ftdi_set_signal(led, '0');
-
int retval = mpsse_flush(mpsse_ctx);
if (retval != ERROR_OK)
LOG_ERROR("error while flushing MPSSE queue: %d", retval);
@@ -660,6 +660,11 @@ static int ftdi_initialize(void)
static int ftdi_quit(void)
{
+ struct signal *led = find_signal_by_name("LED");
+ if (led)
+ ftdi_set_signal(led, '0');
+
+ mpsse_flush(mpsse_ctx);
mpsse_close(mpsse_ctx);
free(swd_cmd_queue);
@@ -943,7 +948,7 @@ static void ftdi_swd_swdio_en(bool enable)
*/
static int ftdi_swd_run_queue(struct adiv5_dap *dap)
{
- LOG_DEBUG("Executing %zu queued transactions", swd_cmd_queue_length);
+ LOG_DEBUG("Executing %"PRIz"u queued transactions", swd_cmd_queue_length);
int retval;
struct signal *led = find_signal_by_name("LED");
@@ -1019,7 +1024,7 @@ static void ftdi_swd_queue_cmd(struct adiv5_dap *dap, uint8_t cmd, uint32_t *dst
if (q != NULL) {
swd_cmd_queue = q;
swd_cmd_queue_alloced *= 2;
- LOG_DEBUG("Increased SWD command queue to %zu elements", swd_cmd_queue_alloced);
+ LOG_DEBUG("Increased SWD command queue to %"PRIz"u elements", swd_cmd_queue_alloced);
}
}
diff --git a/src/jtag/drivers/ice1000.c b/src/jtag/drivers/ice1000.c
new file mode 100644
index 0000000..b122edc
--- /dev/null
+++ b/src/jtag/drivers/ice1000.c
@@ -0,0 +1,2304 @@
+/***************************************************************************
+* Copyright (C) 2011 by Analog Devices, Inc. *
+* Based on ice100.c of UrJTAG *
+* Jie Zhang <***@analog.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 <jtag/interface.h>
+#include <jtag/swd.h>
+#include <target/image.h>
+#include <helper/log.h>
+#include <helper/configuration.h>
+#include "libusb1_common.h"
+
+/*
+ * Internal Structures
+ */
+
+/* JTAG TMS/TDI Data */
+typedef struct
+{
+ uint8_t tms; /* TMS data */
+ uint8_t tdi; /* TDI data */
+} tap_pairs;
+
+/* swd_packet can be used to describe a read packet, a write packet,
+ an acknowledge response or a data phase. */
+struct swd_packet
+{
+ /* IN or OUT */
+ bool is_out;
+ /* bit position of ACK */
+ int ack_pos;
+ /* bit position of data */
+ int data_pos;
+ /* bit position of parity if it's an IN */
+ int parity_pos;
+ /* buffer for the data OUT */
+ const uint8_t *out;
+ /* buffer for the data IN */
+ void *in;
+ /* data length in bits */
+ uint32_t length;
+};
+
+/* For collecting data */
+typedef struct
+{
+ int32_t idx; /* Index where data is to be collected */
+ int32_t pos; /* Bit position where data is to be collected */
+ void *ptr; /* This can point to a scan_command or swd_packet */
+} dat_dat;
+
+/* Master scan control structure */
+typedef struct
+{
+ int32_t total; /* Max number of tap pointers */
+ int32_t cur_idx; /* Where to add next, or total */
+ int32_t bit_pos; /* Position to place next bit */
+ int32_t num_dat; /* Total posible data collection points */
+ int32_t cur_dat; /* Index to dat array for data to be collected */
+ int32_t rcv_dat; /* Index to retreive collected data */
+ dat_dat *dat; /* Pointer to data collection points */
+ unsigned char *cmd; /* Pointer to command, which encompasses pairs */
+ tap_pairs *pairs; /* Pointer to tap pairs array */
+} num_tap_pairs;
+
+/* Cable params_t structure with our data */
+typedef struct
+{
+ libusb_device_handle *usb_handle; /* USB handle */
+ uint32_t cur_freq; /* JTAG Frequency */
+ uint32_t cur_voltage; /* Voltage 1: 1.8V, 2: 2.5V, 3: 3.3/5V, ICE-2000 only */
+ uint32_t cur_delay; /* Delay, ICE-2000 only */
+ uint16_t version; /* Firmware Version */
+ uint32_t default_scanlen; /* #Scan pairs in scan */
+ uint32_t trigger_scanlen; /* High water mark */
+ uint32_t tap_pair_start_idx; /* depends on firmware version */
+ uint32_t num_rcv_hdr_bytes; /* Number of data bytes in received raw scan data header */
+ uint32_t max_raw_data_tx_items; /* depends on firmware version */
+ int32_t wr_ep; /* USB End Write Point */
+ int32_t wr_timeout; /* USB Write Timeout */
+ int32_t wr_buf_sz; /* USB Write Buffer Size */
+ int32_t r_ep; /* USB End Read Point */
+ int32_t r_timeout; /* USB Read Timeout */
+ int32_t r_buf_sz; /* USB Read Buffer Size */
+ num_tap_pairs tap_info; /* For collecting and sending tap scans */
+} params_t;
+
+/* Emulators's USB Data structure */
+typedef struct
+{
+ uint32_t command; /* What to do */
+ uint32_t buffer; /* used for Kit only, always initialized to 0 */
+ uint32_t count; /* Amount of data in bytes to send */
+} usb_command_block;
+
+
+/*
+ * Internal Prototypes
+ */
+
+static int perform_scan(uint8_t **rdata);
+static int do_rawscan(uint8_t firstpkt, uint8_t lastpkt,
+ int32_t collect_dof, int32_t dif_cnt, uint8_t *raw_buf,
+ uint8_t *out);
+static int add_scan_data(int32_t, uint8_t *, bool, struct scan_command *);
+static uint8_t *get_recv_data(int32_t, int32_t, uint8_t *);
+static uint16_t do_host_cmd(uint8_t cmd, uint8_t param, int32_t r_data);
+static uint32_t do_single_reg_value(uint8_t reg, int32_t r_data,
+ int32_t wr_data, uint32_t data);
+
+static int ice1000_swd_switch_seq(struct adiv5_dap *dap, enum swd_special_seq seq);
+static int ice1000_swd_run_queue(struct adiv5_dap *dap);
+
+/*
+ * Debug Macros
+ */
+
+#if 0 /* set to 1 to output debug info about scans */
+
+//#define DSP_SCAN_DATA
+#define DUMP_EACH_RCV_DATA
+//#define DSP_SCAN_CAUSE
+#define DEBUG(...) printf(__VA_ARGS__)
+
+#else
+
+#define DEBUG(...)
+
+#endif
+
+
+/*
+ * Internal Data, defines and Macros
+ */
+#define ICE_DEFAULT_SCAN_LEN 0x7FF0 /* Max DIF is 0x2AAA8, but DMA is only 16 bits. */
+#define ICE_TRIGGER_SCAN_LEN 0x7FD8 /* Start checking for RTI/TLR for xmit */
+
+#define SELECTIVE_RAW_SCAN_HDR_SZ 12
+
+#define DAT_SZ 0x8000 /* size allocated for reading data */
+#define DAT_SZ_INC 0x40 /* size to increase if data full */
+
+/* USB Emulator Commands */
+#define HOST_GET_FW_VERSION 0x01 /* get the firmware version */
+#define HOST_REQUEST_RX_DATA 0x02 /* host request to transmit data */
+#define HOST_REQUEST_TX_DATA 0x04 /* host request to transmit data */
+#define HOST_GET_SINGLE_REG 0x08 /* set a JTAG register */
+#define HOST_SET_SINGLE_REG 0x09 /* set a JTAG register */
+#define HOST_PROGRAM_FLASH 0x0C /* program flash */
+#define HOST_HARD_RESET_JTAG_CTRLR 0x0E /* do a hard reset on JTAG controller */
+#define HOST_SET_TRST 0x1F /* changes TRST Line state */
+#define HOST_GET_TRST 0x20 /* gets TRST Line state */
+#define HOST_DO_SELECTIVE_RAW_SCAN 0x21 /* Return only data needed */
+#define HOST_SET_2000_VOLTAGE 0x24
+#define HOST_SET_INTERFACE_MODE 0x25
+#define HOST_DISCONNECT 0x27
+
+/* Registers */
+#define REG_AUX 0x00
+#define REG_SCR 0x04
+#define REG_FREQ 0x40
+
+#define SCR_DEFAULT 0x30A0461
+#define SCR_TRST_BIT 0x0000040
+
+/* Ice USB controls */
+#define ICE_1000_WRITE_ENDPOINT 0x06
+#define ICE_1000_READ_ENDPOINT 0x05
+#define ICE_1000_USB_WRITE_TIMEOUT 10000
+#define ICE_1000_USB_READ_TIMEOUT 30000
+#define ICE_1000_WRITE_BUFFER_SIZE 0x9800
+#define ICE_1000_READ_BUFFER_SIZE 0x8000
+
+
+/* frequency settings for ICE-1000 */
+#define MAX_FREQ_1000 3
+static const uint8_t freq_set_1000[MAX_FREQ_1000] = { 45, 22, 8 };
+static const uint32_t avail_freqs_1000[MAX_FREQ_1000] = { 1000000, 2000000, 5000000 };
+/* frequency settings for ICE-2000 */
+#define MAX_FREQ_2000 7
+static const uint8_t freq_set_2000[MAX_FREQ_2000] = { 45, 22, 8, 4, 2, 1, 0 };
+static const uint32_t avail_freqs_2000[MAX_FREQ_2000] = { 1000000, 2000000, 5000000, 9000000, 15000000, 23000000, 46000000 };
+
+/*
+ * Internal Macros
+ */
+
+#define adi_usb_read_or_ret(buf, len) \
+ do { \
+ int __ret, __actual, __size = (len); \
+ __ret = libusb_bulk_transfer(cable_params.usb_handle, \
+ cable_params.r_ep | LIBUSB_ENDPOINT_IN, \
+ (unsigned char *)(buf), __size, \
+ &__actual, cable_params.r_timeout); \
+ if (__ret || __actual != __size) \
+ { \
+ LOG_ERROR("unable to read from usb to " #buf ": " \
+ "wanted %i bytes but only received %i bytes", \
+ __size, __actual); \
+ return ERROR_FAIL; \
+ } \
+ } while (0)
+
+#define adi_usb_write_or_ret(buf, len) \
+ do { \
+ int __ret, __actual, __size = (len); \
+ __ret = libusb_bulk_transfer(cable_params.usb_handle, \
+ cable_params.wr_ep | LIBUSB_ENDPOINT_OUT, \
+ (unsigned char *)(buf), __size, \
+ &__actual, cable_params.wr_timeout); \
+ if (__ret || __actual != __size) \
+ { \
+ LOG_ERROR("unable to write from " #buf " to usb: " \
+ "wanted %i bytes but only wrote %i bytes", \
+ __size, __actual); \
+ return ERROR_FAIL; \
+ } \
+ } while (0)
+
+
+static params_t cable_params;
+
+static bool swd_mode;
+
+/*
+ * System Interface Functions
+ */
+
+extern struct jtag_interface *jtag_interface;
+static const char *adi_cable_name(void)
+{
+ if (jtag_interface == NULL)
+ return "";
+
+ if (strcmp(jtag_interface->name, "ice1000") == 0)
+ return "ICE-1000";
+ else if (strcmp(jtag_interface->name, "ice2000") == 0)
+ return "ICE-2000";
+ else
+ return "unknown";
+}
+
+/*
+ * Gets available Frequency index.
+ */
+static int adi_get_freq(uint32_t freq, int arr_sz, const uint32_t *freq_arr)
+{
+ int i;
+
+ /* Verify Frequency is valid */
+ for (i = 0; i < arr_sz; i++)
+ {
+ if (freq == freq_arr[i])
+ {
+ /* spot on */
+ break;
+ }
+ else if (freq < freq_arr[i])
+ {
+ /* an in between frequency */
+ if (i > 0)
+ i--;
+ break;
+ }
+ }
+
+ if (i == arr_sz)
+ {
+ /* must of entered something above the max! */
+ i--;
+ }
+
+ return i;
+}
+
+/*
+ * Sets ICE-1000 Frequency
+ */
+static void ice1000_set_freq(uint32_t freq)
+{
+ params_t *params = &cable_params;
+
+ /* Verify Frequency is valid */
+ if (freq != params->cur_freq)
+ {
+ /* only change if different from current settings */
+ int idx = adi_get_freq(freq, MAX_FREQ_1000, &avail_freqs_1000[0]);
+
+ if (avail_freqs_1000[idx] != params->cur_freq)
+ {
+ /* only change if different from current settings
+ * this call's frequency may have been not one of
+ * the defined settings, but ends up there */
+ params->cur_freq = freq;
+ do_single_reg_value(REG_FREQ, 1, 1, freq_set_1000[idx]);
+ }
+ }
+}
+
+static int ice2000_validate_ircapture(int test_data_length, int total_ir_length,
+ const uint8_t *ir_test_in, uint8_t *ir_test_out)
+{
+ int retval, i;
+
+ if (test_data_length % 64)
+ return ERROR_FAIL;
+
+ jtag_add_plain_ir_scan(test_data_length + total_ir_length,
+ ir_test_in, ir_test_out, TAP_IDLE);
+
+ LOG_DEBUG("IR capture validation scan");
+ retval = jtag_execute_queue();
+ if (retval != ERROR_OK)
+ return retval;
+
+ for (i = 0; i < test_data_length / 64; i++)
+ {
+ uint64_t val_in, val_out;
+ val_in = buf_get_u64(ir_test_in, i * 64, 64);
+ val_out = buf_get_u64(ir_test_out, total_ir_length + i * 64, 64);
+ if (val_in != val_out)
+ return ERROR_FAIL;
+ }
+
+ return ERROR_OK;
+}
+
+static void ice2000_set_voltage_freq_delay(uint32_t voltage, uint32_t freq, uint32_t delay)
+{
+ uint32_t value = freq | (delay << 8) | (voltage << 16);
+
+ do_single_reg_value(REG_FREQ, 1, 1, value);
+}
+
+/* TEST_DATA_LENGTH % 64 should be 0 */
+#define TEST_DATA_LENGTH 0x8000
+
+static int ice2000_find_delay(uint32_t voltage, uint32_t freq)
+{
+ struct jtag_tap *tap;
+ int total_ir_length, test_data_length, ir_test_length;
+ uint8_t *ir_test_in, *ir_test_out;
+ params_t *params = &cable_params;
+ int delay, delay_window_size;
+ int first_good_delay = -1, last_good_delay = -1;
+ int retval;
+ int i;
+ int idx;
+
+ /* FIXME find a way to do delay test for SWD mode */
+ if (swd_mode)
+ return ERROR_OK;
+
+ total_ir_length = 0;
+ tap = jtag_tap_next_enabled(NULL);
+ for (; tap != NULL; tap = jtag_tap_next_enabled(tap))
+ total_ir_length += tap->ir_length;
+
+ test_data_length = TEST_DATA_LENGTH;
+ ir_test_length = DIV_ROUND_UP(test_data_length + total_ir_length, 8);
+
+ ir_test_in = malloc(ir_test_length);
+ if (ir_test_in == NULL)
+ return ERROR_FAIL;
+ ir_test_out = malloc(ir_test_length);
+ if (ir_test_out == NULL)
+ {
+ free(ir_test_in);
+ return ERROR_FAIL;
+ }
+
+ /* fill random test data */
+ for (i = 0; i < test_data_length / 8; i++)
+ ir_test_in[i] = rand();
+
+ /* after this scan, all TAPs will capture BYPASS instructions */
+ buf_set_ones(ir_test_in + test_data_length / 8, total_ir_length);
+
+ /* the good delay window size is roughly one cycle. the delay chip
+ is 0.25ns. */
+ idx = adi_get_freq(freq, MAX_FREQ_2000, &avail_freqs_2000[0]);
+ delay_window_size = 1000000000 / avail_freqs_2000[idx] * 4;
+
+ jtag_add_reset(0, 0);
+ jtag_add_tlr();
+ retval = jtag_execute_queue();
+ if (retval != ERROR_OK)
+ goto done;
+
+ for (delay = 0; delay <= 0xff; delay++)
+ {
+ ice2000_set_voltage_freq_delay(voltage, freq_set_2000[idx], delay);
+
+ if (ice2000_validate_ircapture(test_data_length, total_ir_length,
+ ir_test_in, ir_test_out) == ERROR_OK)
+ {
+ if (first_good_delay < 0)
+ first_good_delay = delay;
+
+ last_good_delay = delay;
+ }
+ else
+ {
+ if (last_good_delay > 0)
+ break;
+ }
+ }
+
+ /* if we cannot find a good delay */
+ if (first_good_delay < 0)
+ retval = ERROR_FAIL;
+
+ /* if we find a whole window of good delays */
+ else if (first_good_delay > 0 && last_good_delay < 0xff)
+ params->cur_delay = (first_good_delay + last_good_delay) / 2;
+
+ /* all delays are valid, just pick the middle one */
+ else if (first_good_delay == 0 && last_good_delay == 0xff)
+ params->cur_delay = (first_good_delay + last_good_delay) / 2;
+
+ /* we only find a partial window */
+ else if (first_good_delay == 0 && last_good_delay < 0xff)
+ {
+ /* we still can get the best value */
+ if (last_good_delay - delay_window_size / 2 >= 0)
+ params->cur_delay = last_good_delay - delay_window_size / 2;
+ /* or make sure the margin is big enough (10 is just a guess) */
+ else if (last_good_delay >= 10)
+ params->cur_delay = 0;
+ /* otherwise we just fail */
+ else
+ retval = ERROR_FAIL;
+ }
+
+ /* we only find a partial window */
+ else /* first_good_delay > 0 && last_good_delay == 0xff */
+ {
+ /* we still can get the best value */
+ if (first_good_delay + delay_window_size / 2 <= 0xff)
+ params->cur_delay = first_good_delay + delay_window_size / 2;
+ /* or make sure the margin is big enough (10 is just a guess) */
+ else if (0xff - first_good_delay >= 10)
+ params->cur_delay = first_good_delay;
+ /* otherwise we just fail */
+ else
+ retval = ERROR_FAIL;
+ }
+
+ /* restore the original settings */
+ idx = adi_get_freq(params->cur_freq, MAX_FREQ_2000, &avail_freqs_2000[0]);
+ ice2000_set_voltage_freq_delay(params->cur_voltage, freq_set_2000[idx], params->cur_delay);
+
+done:
+ free(ir_test_in);
+ free(ir_test_out);
+
+ if (retval == ERROR_OK)
+ LOG_INFO("%s delay %d", adi_cable_name(), params->cur_delay);
+ else
+ LOG_ERROR("%s cannot find a good delay", adi_cable_name());
+
+ return retval;
+}
+
+/*
+ * Sets ICE-2000 Frequency
+ */
+static int ice2000_set_freq(uint32_t freq)
+{
+ params_t *params = &cable_params;
+ int idx = adi_get_freq(freq, MAX_FREQ_2000, &avail_freqs_2000[0]);
+
+ /* only change if different from current settings */
+ if (avail_freqs_2000[idx] != params->cur_freq)
+ {
+ if (ice2000_find_delay(params->cur_voltage, avail_freqs_2000[idx]) != ERROR_OK)
+ return ERROR_FAIL;
+ params->cur_freq = freq;
+ ice2000_set_voltage_freq_delay(params->cur_voltage, freq_set_2000[idx], params->cur_delay);
+ }
+
+ return ERROR_OK;
+}
+/* Calculate the CRC using forward CRC-16-CCITT algorithm. */
+
+static uint16_t
+crc16_ccitt(const uint8_t *data, int length, uint16_t crc)
+{
+ int i;
+
+ for (i = 0; i < length; i++)
+ {
+ uint8_t b = data[i];
+ int j;
+
+ for (j = 0; j < 8; j++)
+ {
+ bool add = ((crc >> 15) != (b >> 7));
+ crc <<= 1;
+ b <<= 1;
+ if (add)
+ crc ^= 0x1021;
+ }
+ }
+
+ return crc;
+}
+
+static int
+ice1000_send_flash_data(struct image *firmware, uint16_t *crcp)
+{
+ /* ICE_1000_READ_BUFFER_SIZE / 4 (i.e. 0x2000) was chosen by experiments.
+ It might not be related to ICE_1000_READ_BUFFER_SIZE at all. */
+ uint8_t buffer[ICE_1000_READ_BUFFER_SIZE / 4];
+ uint8_t first = 1, last = 0;
+ int i;
+ uint16_t crc = 0xffff;
+
+ for (i = 0; i < firmware->num_sections; i++)
+ {
+ size_t section_size;
+ uint8_t *section_buffer;
+ int remaining;
+ uint32_t address;
+ size_t size_read;
+ int ret;
+
+ section_size = firmware->sections[i].size;
+ section_buffer = malloc(section_size);
+ if (section_buffer == NULL)
+ {
+ LOG_ERROR("error allocating buffer for section (%d bytes)",
+ firmware->sections[i].size);
+ return ERROR_FAIL;
+ }
+
+ ret = image_read_section(firmware, i, 0, section_size, section_buffer, &size_read);
+ if (ret != ERROR_OK || size_read != section_size)
+ {
+ free(section_buffer);
+ return ret;
+ }
+
+ crc = crc16_ccitt(section_buffer, section_size, crc);
+
+ remaining = section_size;
+ address = firmware->sections[i].base_address;
+
+ while (remaining)
+ {
+ usb_command_block usb_cmd_blk;
+ uint32_t count;
+
+ LOG_INFO("updating ...");
+
+ if (remaining < ICE_1000_READ_BUFFER_SIZE / 4 - 16)
+ count = remaining;
+ else
+ count = ICE_1000_READ_BUFFER_SIZE / 4 - 16;
+ remaining -= count;
+ if (remaining == 0)
+ last = 1;
+
+ buffer[0] = first;
+ buffer[1] = last;
+ buffer[2] = HOST_PROGRAM_FLASH;
+ buffer[3] = 0;
+ memcpy(buffer + 4, &address, 4);
+ memcpy(buffer + 8, &count, 4);
+ memcpy(buffer + 12, &crc, 2);
+ memcpy(buffer + 16, section_buffer + section_size - remaining - count, count);
+
+ usb_cmd_blk.command = HOST_REQUEST_TX_DATA;
+ usb_cmd_blk.count = count + 16;
+ usb_cmd_blk.buffer = 0;
+ adi_usb_write_or_ret(&usb_cmd_blk, sizeof (usb_cmd_blk));
+
+ adi_usb_write_or_ret(buffer, usb_cmd_blk.count);
+
+ first = 0;
+
+ address += count;
+ }
+
+ free(section_buffer);
+ }
+
+ *crcp = crc;
+
+ LOG_INFO("done");
+
+ return ERROR_OK;
+}
+
+/* The CRC is stored in the output buffer after programming the firmware
+ into the flash. Read the buffer after programming get the CRC. */
+
+static int
+ice1000_firmware_crc(uint16_t *p)
+{
+ usb_command_block usb_cmd_blk;
+
+ usb_cmd_blk.command = HOST_REQUEST_RX_DATA;
+ usb_cmd_blk.count = 2;
+ usb_cmd_blk.buffer = 0;
+
+ adi_usb_write_or_ret(&usb_cmd_blk, sizeof (usb_cmd_blk));
+
+ adi_usb_read_or_ret(p, sizeof (*p));
+
+ return ERROR_OK;
+}
+
+static int
+ice1000_update_firmware(const char *filename)
+{
+ struct image ice1000_firmware_image;
+ unsigned short crc1, crc2;
+ int ret;
+
+ LOG_INFO("Updating to firmware %s", filename);
+
+ ret = image_open(&ice1000_firmware_image, filename, "ihex");
+ if (ret != ERROR_OK)
+ return ret;
+
+ ret = ice1000_send_flash_data(&ice1000_firmware_image, &crc1);
+ if (ret != ERROR_OK)
+ return ret;
+
+ if ((ret = ice1000_firmware_crc(&crc2)) != ERROR_OK)
+ return ret;
+
+ image_close(&ice1000_firmware_image);
+
+ if (crc1 == crc2)
+ return ERROR_OK;
+ else
+ {
+ LOG_ERROR("CRCs do NOT match");
+ return ERROR_FAIL;
+ }
+}
+
+/*
+ * This function sets us up the cable and data
+ */
+static int adi_connect(const uint16_t *vids, const uint16_t *pids)
+{
+ const char *cable_name = adi_cable_name();
+ libusb_device_handle *dev;
+ libusb_device *udev;
+ struct libusb_config_descriptor *config;
+ uint8_t configuration;
+ char *firmware_filename = get_firmware_filename();
+ int i, ret;
+
+ ret = libusb_init(NULL);
+ if (ret)
+ {
+ LOG_ERROR("libusb initialization failed.");
+ return ERROR_FAIL;
+ }
+
+ ret = jtag_libusb_open(vids, pids, NULL, &dev);
+ if (ret != ERROR_OK)
+ return ret;
+
+ udev = libusb_get_device(dev);
+ libusb_get_active_config_descriptor(udev, &config);
+ configuration = config->bConfigurationValue;
+ libusb_free_config_descriptor (config);
+ libusb_set_configuration(dev, configuration);
+ ret = libusb_claim_interface(dev, 0);
+ if (ret)
+ {
+ LOG_ERROR("libusb_claim_interface failed: %d", ret);
+ libusb_close(dev);
+ return ERROR_FAIL;
+ }
+ else
+ {
+ LOG_DEBUG("usb interface claimed!");
+ }
+
+ cable_params.tap_info.dat = malloc(sizeof(dat_dat) * DAT_SZ);
+ if (!cable_params.tap_info.dat)
+ {
+ LOG_ERROR("malloc(%"PRIzd") fails", sizeof(dat_dat) * DAT_SZ);
+ libusb_release_interface(dev, 0);
+ libusb_close(dev);
+ return ERROR_FAIL;
+ }
+
+ /* Initialize receive data array to unused */
+ for (i = 0; i < DAT_SZ; ++i)
+ {
+ cable_params.tap_info.dat[i].idx = -1;
+ cable_params.tap_info.dat[i].pos = -1;
+ }
+
+ cable_params.usb_handle = dev;
+ cable_params.tap_info.bit_pos = 0x80;
+ cable_params.tap_info.num_dat = DAT_SZ;
+ cable_params.tap_info.rcv_dat = -1;
+ cable_params.tap_info.cur_dat = -1;
+
+ cable_params.default_scanlen = ICE_DEFAULT_SCAN_LEN;
+ cable_params.trigger_scanlen = ICE_TRIGGER_SCAN_LEN;
+ cable_params.wr_ep = ICE_1000_WRITE_ENDPOINT;
+ cable_params.r_ep = ICE_1000_READ_ENDPOINT;
+ cable_params.wr_timeout = ICE_1000_USB_WRITE_TIMEOUT;
+ cable_params.r_timeout = ICE_1000_USB_READ_TIMEOUT;
+ cable_params.wr_buf_sz = ICE_1000_WRITE_BUFFER_SIZE;
+ cable_params.r_buf_sz = ICE_1000_READ_BUFFER_SIZE;
+
+ cable_params.version = do_host_cmd(HOST_GET_FW_VERSION, 0, 1);
+
+ LOG_INFO("%s firmware version is %d.%d.%d",
+ cable_name,
+ ((cable_params.version >> 8) & 0xFF),
+ ((cable_params.version >> 4) & 0x0F),
+ ((cable_params.version) & 0x0F));
+
+ if (cable_params.version <= 0x0101)
+ LOG_WARNING("This firmware version is obsolete. Please update to the latest version.");
+
+ if (firmware_filename)
+ {
+ ret = ice1000_update_firmware(firmware_filename);
+ if (ret == ERROR_OK)
+ LOG_INFO("The firmware has been updated successfully. "
+ "Please unplug the %s cable and reconnect it to finish the update process.", cable_name);
+ else
+ LOG_ERROR("The firmware failed to update.");
+ return ERROR_JTAG_INIT_FAILED;
+ }
+
+ /* Set frequency to lowest value */
+ if (strcmp (cable_name, "ICE-2000") == 0)
+ {
+ /* Turn on the voltage regulators */
+ do_host_cmd(HOST_SET_2000_VOLTAGE, 1, 0);
+
+ do_host_cmd(HOST_SET_INTERFACE_MODE, swd_mode ? 1 : 0, 0);
+
+ /* If user has not set the voltage, default it to 3.3V. */
+ if (cable_params.cur_voltage == 0)
+ cable_params.cur_voltage = 3;
+
+ if (cable_params.cur_voltage == 1)
+ LOG_INFO("%s voltage 1.8V", cable_name);
+ else if (cable_params.cur_voltage == 2)
+ LOG_INFO("%s voltage 2.5V", cable_name);
+ else /* cable_params.cur_voltage == 3 */
+ LOG_INFO("%s voltage 3.3V", cable_name);
+
+ /* Set the frequency to the lowest. */
+ cable_params.cur_freq = avail_freqs_2000[0];
+
+ /* Set the delay to 0. */
+ ice2000_set_voltage_freq_delay(cable_params.cur_voltage, freq_set_2000[0], 0);
+ }
+ else if (strcmp (cable_name, "ICE-1000") == 0)
+ {
+ do_host_cmd(HOST_SET_INTERFACE_MODE, swd_mode ? 1 : 0, 0);
+
+ ice1000_set_freq(avail_freqs_1000[0]);
+ }
+
+ /* HOST_HARD_RESET_JTAG_CTRLR will toggle TRST. This command has to be
+ sent after voltage regulators are turned on for ICE-2000. */
+ do_host_cmd(HOST_HARD_RESET_JTAG_CTRLR, 0, 0);
+
+ /* There is a bug in implementation of HOST_HARD_RESET_JTAG_CTRLR command
+ in 1.0.1 or earlier version firmware which does not hold TRST for enough
+ time. The processors, which ICE-1000/2000 usually work with, like legacy
+ Blackfin and ADSP-SC589 requires at least 4 JTAG CLKs. As a workaround,
+ we hold TRST low for 4 us, which should be enough even for the lowest
+ frequecy we can set, 1 MHz. */
+ if (cable_params.version <= 0x0101)
+ {
+ do_host_cmd(HOST_SET_TRST, 1, 0);
+ usleep(4);
+ do_host_cmd(HOST_SET_TRST, 0, 0);
+ }
+
+ cable_params.tap_pair_start_idx = SELECTIVE_RAW_SCAN_HDR_SZ;
+ cable_params.max_raw_data_tx_items = cable_params.wr_buf_sz - cable_params.tap_pair_start_idx;
+ cable_params.num_rcv_hdr_bytes = cable_params.tap_pair_start_idx;
+
+ if (strcmp (cable_name, "ICE-1000") == 0 || strcmp (cable_name, "ICE-2000") == 0) {
+ if (swd_mode)
+ ice1000_swd_switch_seq(NULL, JTAG_TO_SWD);
+ else
+ ice1000_swd_switch_seq(NULL, SWD_TO_JTAG);
+ ice1000_swd_run_queue(NULL);
+ }
+
+ return ERROR_OK;
+}
+
+/*
+ * takes tdi and tms and sends it out right away
+ */
+static int adi_clock(int32_t tms, int32_t tdi, int32_t cnt)
+{
+ num_tap_pairs *tap_info = &cable_params.tap_info;
+
+ if (tap_info->pairs == NULL)
+ {
+ unsigned char *cmd;
+ int32_t new_sz = cable_params.default_scanlen;
+ uint8_t bit_set;
+ int i, j;
+
+ cmd = malloc((sizeof (tap_pairs) * new_sz) + 1 + cable_params.tap_pair_start_idx);
+ if (cmd == NULL)
+ {
+ LOG_ERROR("malloc(%"PRIzd") fails",
+ (sizeof (tap_pairs) * new_sz) + 1 + cable_params.tap_pair_start_idx);
+ return ERROR_FAIL;
+ }
+
+ tap_info->cmd = cmd;
+ /* point our pairs to the space that was allocated */
+ tap_info->pairs = (tap_pairs *)(cmd + cable_params.tap_pair_start_idx); /* new pointer */
+
+ /* initialize some of our structure */
+
+ bit_set = 0x80;
+ i = 0;
+ tap_info->pairs[i].tms = 0;
+ tap_info->pairs[i].tdi = 0;
+
+ /* go through and set tms and tdi to the appropriate values */
+ for (j = 0; j < cnt; j++)
+ {
+ tap_info->pairs[i].tms |= tms ? bit_set : 0;
+ tap_info->pairs[i].tdi |= tdi ? bit_set : 0;
+ bit_set >>= 1;
+ if (!bit_set)
+ {
+ /* start over again */
+ bit_set = 0x80;
+ i++;
+ tap_info->pairs[i].tms = 0;
+ tap_info->pairs[i].tdi = 0;
+ }
+ }
+
+ tap_info->total = new_sz;
+ tap_info->cur_idx = cnt / 8; /* we scan in multiples of 32 */
+ tap_info->bit_pos = bit_set;
+
+ return ERROR_OK;
+ }
+ else
+ {
+ int i, j;
+ uint8_t bit_set;
+
+ bit_set = tap_info->bit_pos;
+ i = tap_info->cur_idx;
+
+ for (j = 0; j < cnt; j++)
+ {
+ tap_info->pairs[i].tms |= tms ? bit_set : 0;
+ tap_info->pairs[i].tdi |= tdi ? bit_set : 0;
+ bit_set >>= 1;
+ if (!bit_set)
+ {
+ /* start over again */
+ bit_set = 0x80;
+ i++;
+ tap_info->pairs[i].tms = 0;
+ tap_info->pairs[i].tdi = 0;
+ }
+ }
+
+ tap_info->cur_idx = i;
+ tap_info->bit_pos = bit_set;
+
+ return ERROR_OK;
+ }
+}
+
+static int ice1000_init(void)
+{
+ const uint16_t vids[] = { 0x064b, 0 };
+ const uint16_t pids[] = { 0x0617, 0 };
+
+ int retval;
+
+ retval = adi_connect(vids, pids);
+ if (retval != ERROR_OK)
+ {
+ if (retval == -ENODEV)
+ LOG_ERROR("ICE-1000 emulator not found");
+
+ LOG_ERROR("cannot connect to ICE-1000 emulator");
+ }
+
+ return retval;
+}
+
+static int ice2000_init(void)
+{
+ const uint16_t vids[] = { 0x064b, 0 };
+ const uint16_t pids[] = { 0x0283, 0 };
+
+ int retval;
+
+ retval = adi_connect(vids, pids);
+ if (retval != ERROR_OK)
+ {
+ if (retval == -ENODEV)
+ LOG_ERROR("ICE-2000 emulator not found");
+
+ LOG_ERROR("cannot connect to ICE-2000 emulator");
+ }
+
+ return retval;
+}
+
+static int ice1000_quit(void)
+{
+ do_host_cmd(HOST_DISCONNECT, 0, 0);
+
+ if (cable_params.usb_handle != NULL)
+ {
+ libusb_release_interface(cable_params.usb_handle, 0);
+ libusb_close(cable_params.usb_handle);
+ }
+
+ free(cable_params.tap_info.dat);
+
+ return ERROR_OK;
+}
+
+static int ice2000_quit(void)
+{
+ /* Turn off the voltage regulators */
+ do_host_cmd(HOST_SET_2000_VOLTAGE, 0, 0);
+
+ do_host_cmd(HOST_DISCONNECT, 0, 0);
+
+ if (cable_params.usb_handle != NULL)
+ {
+ libusb_release_interface(cable_params.usb_handle, 0);
+ libusb_close(cable_params.usb_handle);
+ }
+
+ free(cable_params.tap_info.dat);
+
+ return ERROR_OK;
+}
+
+static int ice1000_speed(int speed)
+{
+ if (speed >= MAX_FREQ_1000 && speed < 0)
+ {
+ LOG_ERROR("bad speed %d, should between %d and %d.",
+ speed, 0, MAX_FREQ_1000 - 1);
+ return ERROR_FAIL;
+ }
+
+ ice1000_set_freq(avail_freqs_1000[speed]);
+
+ return ERROR_OK;
+}
+
+static int ice1000_speed_div(int speed, int *khz)
+{
+ *khz = avail_freqs_1000[speed] / 1000;
+ return ERROR_OK;
+}
+
+static int ice1000_khz(int khz, int *speed)
+{
+ *speed = adi_get_freq(khz * 1000, MAX_FREQ_1000, &avail_freqs_1000[0]);
+ return ERROR_OK;
+}
+
+static int ice2000_speed(int speed)
+{
+ if (speed >= MAX_FREQ_2000 && speed < 0)
+ {
+ LOG_ERROR("bad speed %d, should between %d and %d.",
+ speed, 0, MAX_FREQ_2000 - 1);
+ return ERROR_FAIL;
+ }
+
+ return ice2000_set_freq(avail_freqs_2000[speed]);
+}
+
+static int ice2000_speed_div(int speed, int *khz)
+{
+ *khz = avail_freqs_2000[speed] / 1000;
+ return ERROR_OK;
+}
+
+static int ice2000_khz(int khz, int *speed)
+{
+ *speed = adi_get_freq(khz * 1000, MAX_FREQ_2000, &avail_freqs_2000[0]);
+ return ERROR_OK;
+}
+
+/*
+ * Takes Data received (rcv_dataptr) and puts it in
+ * todo date out transfer
+ */
+static uint8_t *get_recv_data(int32_t len, int32_t idx_dat, uint8_t *rcv_data)
+{
+ uint8_t *buf;
+ num_tap_pairs *tap_info = &cable_params.tap_info;
+ int32_t dat_idx = tap_info->dat[idx_dat].idx;
+ uint8_t *rcvBuf = rcv_data + cable_params.num_rcv_hdr_bytes + dat_idx;
+ int32_t bit_set = tap_info->dat[idx_dat].pos;
+ int32_t i;
+
+#ifdef DUMP_EACH_RCV_DATA
+ DEBUG("Idx = %d; Read len = %d\n", dat_idx, len);
+#endif
+
+ buf = (uint8_t *)calloc(DIV_ROUND_UP(len, 8), 1);
+
+ if (buf == NULL)
+ LOG_ERROR("malloc(%d) fails", DIV_ROUND_UP(len, 8));
+
+ if (idx_dat < 0)
+ {
+ DEBUG("get_recv_data(): No Received Data\n");
+ return NULL;
+ }
+
+ for (i = 0; i < len; i++)
+ {
+ buf[i/8] |= ((*rcvBuf & bit_set) ? 1 : 0) << (i % 8);
+
+#ifdef DUMP_EACH_RCV_DATA
+ if (i % 8 == 0 && i != 0)
+ DEBUG("%d", buf[i/8 - 1]);
+ if (((i + 1) % 64) == 0)
+ putchar('\n');
+ else if (((i + 1) % 8) == 0)
+ putchar(' ');
+#endif
+ bit_set >>= 1;
+
+ if (!bit_set)
+ {
+ bit_set = 0x80;
+ rcvBuf++;
+ dat_idx++;
+ }
+ }
+
+ /* this is set for getting the extra TDO bits */
+ tap_info->dat[idx_dat].idx = dat_idx;
+ tap_info->dat[idx_dat].pos = bit_set;
+
+ return buf;
+}
+
+static int ice1000_tap_execute(void)
+{
+ num_tap_pairs *tap_info = &cable_params.tap_info;
+ uint8_t *buf;
+ int i, retval;
+
+ if (tap_info->cur_idx == 0 && tap_info->bit_pos == 0x80
+ && tap_info->cur_dat == -1)
+ return ERROR_OK;
+
+ buf = NULL;
+ perform_scan(&buf);
+
+ retval = ERROR_OK;
+
+ for (i = 0; i <= tap_info->cur_dat; i++)
+ {
+ uint8_t *buffer;
+ struct scan_command *command = tap_info->dat[i].ptr;
+
+ buffer = get_recv_data(jtag_scan_size(command), tap_info->rcv_dat, buf);
+ tap_info->rcv_dat++;
+ if (jtag_read_buffer(buffer, command) != ERROR_OK)
+ return ERROR_JTAG_QUEUE_FAILED;
+
+ free(buffer);
+ }
+
+ free(buf);
+ if (tap_info->pairs)
+ {
+ free(tap_info->cmd);
+ tap_info->pairs = NULL;
+ tap_info->cmd = NULL;
+ }
+ tap_info->total = 0;
+ tap_info->cur_idx = 0;
+ tap_info->bit_pos = 0x80;
+ tap_info->cur_dat = -1;
+ tap_info->rcv_dat = -1;
+
+ return retval;
+}
+
+static int ice1000_execute_reset(struct jtag_command *cmd)
+{
+ int retval;
+
+ retval = ice1000_tap_execute();
+ if (retval != ERROR_OK)
+ return retval;
+
+ 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);
+ }
+
+ do_host_cmd(HOST_SET_TRST, cmd->cmd.reset->trst ? 0 : 1, 0);
+ return ERROR_OK;
+}
+
+static void ice1000_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 valid end state", tap_state_name(state));
+ exit(-1);
+ }
+}
+
+static int ice1000_tap_ensure_space(unsigned int bits)
+{
+ int retval = ERROR_OK;
+
+ if (cable_params.tap_info.cur_idx + DIV_ROUND_UP(bits, 8) >= cable_params.trigger_scanlen)
+ retval = ice1000_tap_execute();
+
+ return retval;
+}
+
+static int ice1000_tap_append_step(int tms, int tdi)
+{
+ int retval;
+ retval = adi_clock(tms, tdi, 1);
+ return retval;
+}
+
+static void ice1000_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;
+ ice1000_tap_append_step(tms, 0);
+ }
+
+ tap_set_state(tap_get_end_state());
+}
+
+static void ice1000_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))
+ {
+ ice1000_tap_append_step(0, 0);
+ }
+ else if (path[i] == tap_state_transition(tap_get_state(), true))
+ {
+ ice1000_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 int ice1000_runtest(int num_cycles)
+{
+ int retval, i;
+ tap_state_t saved_end_state = tap_get_end_state();
+
+ retval = ice1000_tap_ensure_space(num_cycles + 16);
+ if (retval != ERROR_OK)
+ return retval;
+
+ if (tap_get_state() != TAP_IDLE)
+ {
+ ice1000_end_state(TAP_IDLE);
+ ice1000_state_move();
+ }
+
+ for (i = 0; i < num_cycles; i++)
+ ice1000_tap_append_step(0, 0);
+
+ /* finish in end_state */
+ ice1000_end_state(saved_end_state);
+ if (tap_get_state() != tap_get_end_state())
+ {
+ ice1000_state_move();
+ }
+
+ return ERROR_OK;
+}
+
+static int ice1000_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);
+
+ ice1000_end_state(cmd->cmd.runtest->end_state);
+
+ ice1000_runtest(cmd->cmd.runtest->num_cycles);
+
+ return ERROR_OK;
+}
+
+static int ice1000_execute_tlr_reset(struct jtag_command *cmd)
+{
+ DEBUG_JTAG_IO("statemove end in %i", cmd->cmd.statemove->end_state);
+
+ ice1000_end_state(cmd->cmd.statemove->end_state);
+ ice1000_state_move();
+
+ /* Move to Run-Test/Idle */
+ ice1000_tap_append_step(0, 0);
+ tap_set_state(TAP_IDLE);
+
+ return ERROR_OK;
+}
+
+static int ice1000_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]);
+
+ ice1000_path_move(cmd->cmd.pathmove->num_states,
+ cmd->cmd.pathmove->path);
+
+ return ERROR_OK;
+}
+
+/*
+ * This function takes CABLE_TRANSFER todo data,
+ * and adds it to the tms/tdi scan structure
+ * If reading data, sets that up too
+ */
+static int add_scan_data(int32_t num_bits, uint8_t *in, bool out, struct scan_command *command)
+{
+ int32_t bit_cnt = num_bits % 8;
+ int32_t byte_cnt = (num_bits >> 3) + (bit_cnt ? 1 : 0);
+ int32_t i, bit_set;
+ tap_pairs *tap_scan = NULL;
+ int32_t idx;
+ num_tap_pairs *tap_info = &cable_params.tap_info;
+
+ if (in == NULL)
+ LOG_WARNING("NO IN DATA!!!%s", out ? " BUT there is out data!" : "");
+
+ if (tap_info->pairs == NULL)
+ { /* really should never get here, but must not crash system. Would be rude */
+ int32_t new_sz = cable_params.default_scanlen + 4;
+ unsigned char *cmd;
+
+ cmd = malloc((sizeof (tap_pairs) * new_sz) + 1 + cable_params.tap_pair_start_idx);
+ if (cmd == NULL)
+ {
+ LOG_ERROR("malloc(%"PRIzd") fails",
+ (sizeof (tap_pairs) * new_sz) + 1 + cable_params.tap_pair_start_idx);
+ return ERROR_FAIL;
+ }
+
+ tap_info->cur_dat = -1;
+ tap_info->rcv_dat = -1;
+ tap_info->bit_pos = 0x80;
+ tap_info->total = new_sz;
+ tap_info->cmd = cmd; /* new pointer */
+ tap_info->pairs = (tap_pairs *)(cmd + cable_params.tap_pair_start_idx); /* new pointer */
+
+ tap_scan = tap_info->pairs;
+ tap_scan->tms = 0;
+ tap_scan->tdi = 0;
+ idx = tap_info->cur_idx = 1; /* first pair is 0 */
+ tap_scan++;
+ tap_scan->tdi = 0;
+ tap_scan->tms = 0;
+ }
+ else if ((tap_info->total - tap_info->cur_idx) < byte_cnt)
+ { /* to small, increase size! */
+ unsigned char *cmd;
+ int32_t new_sz;
+
+ DEBUG("Reallocating scan_data\n");
+
+ new_sz = tap_info->total + byte_cnt + 8;
+ cmd = realloc(tap_info->cmd, (sizeof (tap_pairs) * new_sz) + 4 + cable_params.tap_pair_start_idx);
+ if (cmd == NULL)
+ {
+ LOG_ERROR("realloc(%"PRIzd") fails",
+ (sizeof (tap_pairs) * new_sz) + 4 + cable_params.tap_pair_start_idx);
+ return ERROR_FAIL;
+ }
+
+ tap_info->total = new_sz; /* resize size */
+ tap_info->cmd = cmd; /* new pointer */
+ tap_info->pairs = (tap_pairs *)(cmd + cable_params.tap_pair_start_idx); /* new pointer */
+
+ tap_scan = tap_info->pairs;
+ idx = tap_info->cur_idx; /* to add on */
+ tap_scan = &tap_info->pairs[idx];
+ }
+ else
+ {
+ idx = tap_info->cur_idx; /* to add on */
+ tap_scan = &tap_info->pairs[idx];
+ }
+
+ bit_set = tap_info->bit_pos;
+
+ if (out)
+ { /* Setup where we start to read, can be more than 1 */
+ if (tap_info->rcv_dat == -1)
+ {
+ tap_info->rcv_dat = 0;
+ }
+ tap_info->cur_dat++;
+ if (tap_info->cur_dat >= tap_info->num_dat)
+ {
+ int32_t new_sz;
+ dat_dat *datPtr;
+
+ new_sz = tap_info->num_dat + DAT_SZ_INC;
+ datPtr = realloc(tap_info->dat, sizeof (dat_dat) * new_sz);
+ if (datPtr == NULL)
+ {
+ LOG_ERROR("realloc(%"PRIzd") fails",
+ sizeof (dat_dat) * new_sz);
+ return ERROR_FAIL;
+ }
+ tap_info->dat = datPtr;
+ tap_info->num_dat = new_sz;
+
+ }
+ tap_info->dat[tap_info->cur_dat].idx = idx;
+ tap_info->dat[tap_info->cur_dat].pos = bit_set;
+ tap_info->dat[tap_info->cur_dat].ptr = command;
+ }
+
+ /* Build Scan. If command is NULL, IN is TMS. Otherwise,
+ TMS will always be zero except the last bit! */
+ for (i = 0; i < num_bits; i++)
+ {
+ if (command != NULL)
+ {
+ tap_scan->tdi |= (in[i / 8] >> (i % 8)) & 0x1 ? bit_set : 0;
+ if (i == num_bits - 1)
+ tap_scan->tms |= bit_set;
+ }
+ else
+ tap_scan->tms |= (in[i / 8] >> (i % 8)) & 0x1 ? bit_set : 0;
+
+ bit_set >>= 1;
+ if (!bit_set)
+ {
+ bit_set = 0x80;
+ idx++;
+ tap_scan++;
+ tap_scan->tdi = 0;
+ tap_scan->tms = 0;
+ }
+ }
+
+ tap_info->cur_idx = idx;
+ tap_info->bit_pos = bit_set;
+
+ return ERROR_OK;
+}
+
+static int ice1000_scan(bool ir_scan, enum scan_type type, uint8_t *buffer,
+ int scan_size, struct scan_command *command)
+{
+ tap_state_t saved_end_state;
+ int retval;
+
+ retval = ice1000_tap_ensure_space(scan_size + 16);
+ if (retval != ERROR_OK)
+ return retval;
+
+ saved_end_state = tap_get_end_state();
+
+ /* Move to appropriate scan state */
+ ice1000_end_state(ir_scan ? TAP_IRSHIFT : TAP_DRSHIFT);
+
+ /* Only move if we're not already there */
+ if (tap_get_state() != tap_get_end_state())
+ ice1000_state_move();
+
+ ice1000_end_state(saved_end_state);
+
+ /* Scan */
+ add_scan_data(scan_size, buffer, type != SCAN_OUT, command);
+
+ /* We are in Exit1, go to Pause */
+ ice1000_tap_append_step(0, 0);
+
+ tap_set_state(ir_scan ? TAP_IRPAUSE : TAP_DRPAUSE);
+
+ if (tap_get_state() != tap_get_end_state())
+ {
+ ice1000_state_move();
+ }
+
+ return ERROR_OK;
+}
+
+static int ice1000_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));
+
+ ice1000_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);
+
+ type = jtag_scan_type(cmd->cmd.scan);
+ ice1000_scan(cmd->cmd.scan->ir_scan,
+ type, buffer, scan_size, cmd->cmd.scan);
+
+ free(buffer);
+
+ return ERROR_OK;
+}
+
+static int ice1000_execute_sleep(struct jtag_command *cmd)
+{
+ int retval;
+
+ retval = ice1000_tap_execute();
+ if (retval != ERROR_OK)
+ return retval;
+
+ DEBUG_JTAG_IO("sleep %" PRIi32 "", cmd->cmd.sleep->us);
+
+ jtag_sleep(cmd->cmd.sleep->us);
+ return ERROR_OK;
+}
+
+static int ice1000_execute_stableclocks(struct jtag_command *cmd)
+{
+ int tms;
+
+ switch (tap_get_state()) {
+ case TAP_RESET:
+ /* tms must be '1' to stay
+ * n TAP_RESET mode
+ */
+ tms = 1;
+ break;
+ case TAP_DRSHIFT:
+ case TAP_IDLE:
+ case TAP_DRPAUSE:
+ case TAP_IRSHIFT:
+ case TAP_IRPAUSE:
+ /* else, tms should be '0' */
+ tms = 0;
+ break;
+ default:
+ return ERROR_FAIL;
+ }
+
+ adi_clock(tms, 0, cmd->cmd.stableclocks->num_cycles);
+
+ return ERROR_OK;
+}
+
+static int ice1000_execute_tms(struct jtag_command *cmd)
+{
+ int num_bits = cmd->cmd.tms->num_bits;
+ uint8_t *bits = (uint8_t *)cmd->cmd.tms->bits;
+ int count = DIV_ROUND_UP(num_bits, 8);
+ int retval;
+
+ retval = ice1000_tap_ensure_space(count);
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = add_scan_data(num_bits, bits, false, NULL);
+
+ return retval;
+}
+
+static int ice1000_execute_command(struct jtag_command *cmd)
+{
+ int retval;
+
+ switch (cmd->type)
+ {
+ case JTAG_RESET:
+ retval = ice1000_execute_reset(cmd);
+ break;
+ case JTAG_RUNTEST:
+ retval = ice1000_execute_runtest(cmd);
+ break;
+ case JTAG_TLR_RESET:
+ retval = ice1000_execute_tlr_reset(cmd);
+ break;
+ case JTAG_PATHMOVE:
+ retval = ice1000_execute_pathmove(cmd);
+ break;
+ case JTAG_SCAN:
+ retval = ice1000_execute_scan(cmd);
+ break;
+ case JTAG_SLEEP:
+ retval = ice1000_execute_sleep(cmd);
+ break;
+ case JTAG_STABLECLOCKS:
+ retval = ice1000_execute_stableclocks(cmd);
+ break;
+ case JTAG_TMS:
+ retval = ice1000_execute_tms(cmd);
+ break;
+ default:
+ LOG_ERROR("BUG: unknown JTAG command type encountered");
+ retval = ERROR_JTAG_QUEUE_FAILED;
+ break;
+ }
+ return retval;
+}
+
+static int ice1000_execute_queue(void)
+{
+ struct jtag_command *cmd = jtag_command_queue;
+ int retval = ERROR_OK;
+
+ /* TODO add blink */
+ while (cmd != NULL)
+ {
+ if (ice1000_execute_command(cmd) != ERROR_OK)
+ retval = ERROR_JTAG_QUEUE_FAILED;
+ cmd = cmd->next;
+ }
+
+ if (retval != ERROR_OK)
+ return retval;
+
+ return ice1000_tap_execute();
+}
+
+/*
+ * Read & Write Registers
+ *
+ * XXX: error handling doesn't quite work with this return
+ * XXX: probably needs converting from memory arrays to byte shifts
+ * so we work regardless of host endian
+ */
+static uint32_t do_single_reg_value(uint8_t reg, int32_t r_data, int32_t wr_data, uint32_t data)
+{
+ usb_command_block usb_cmd_blk;
+ union {
+ uint8_t b[24];
+ uint32_t l[6];
+ } cmd_buffer;
+ uint32_t count = 0;
+ int32_t i, size = wr_data ? 8 : 4;
+
+ usb_cmd_blk.command = HOST_REQUEST_TX_DATA;
+ usb_cmd_blk.count = size;
+ usb_cmd_blk.buffer = 0;
+
+ adi_usb_write_or_ret(&usb_cmd_blk, sizeof(usb_cmd_blk));
+ i = 0;
+
+ /* send HOST_SET_SINGLE_REG command */
+ cmd_buffer.b[i++] = 1;
+ cmd_buffer.b[i++] = 0;
+ cmd_buffer.b[i++] = wr_data ? HOST_SET_SINGLE_REG : HOST_GET_SINGLE_REG;
+ cmd_buffer.b[i++] = reg;
+ if (wr_data)
+ {
+ cmd_buffer.l[i / 4] = data;
+ }
+
+ adi_usb_write_or_ret(cmd_buffer.b, size);
+
+ if (r_data)
+ adi_usb_read_or_ret(&count, sizeof (count));
+
+ return count;
+}
+
+/*
+ * Send Host Command.
+ *
+ * XXX: error handling doesn't quite work with this return
+ * XXX: probably needs converting from memory arrays to byte shifts
+ * so we work regardless of host endian
+ */
+static uint16_t do_host_cmd(uint8_t cmd, uint8_t param, int32_t r_data)
+{
+ usb_command_block usb_cmd_blk;
+ uint16_t results = 0;
+ union {
+ uint8_t b[20];
+ uint32_t l[20/4];
+ } cmd_buffer;
+ int32_t size = 5;
+
+ usb_cmd_blk.command = HOST_REQUEST_TX_DATA;
+ usb_cmd_blk.count = size;
+ usb_cmd_blk.buffer = 0;
+
+ adi_usb_write_or_ret(&usb_cmd_blk, sizeof(usb_cmd_blk));
+
+ /* send command */
+ cmd_buffer.b[0] = 0;
+ cmd_buffer.b[1] = 0;
+ cmd_buffer.b[2] = cmd;
+ cmd_buffer.b[3] = 0;
+ cmd_buffer.b[4] = 0;
+
+ if (cmd == HOST_SET_TRST)
+ cmd_buffer.b[0] = param;
+ else
+ cmd_buffer.b[4] = param;
+
+ adi_usb_write_or_ret(cmd_buffer.b, size);
+
+ if (r_data)
+ {
+ usb_cmd_blk.command = HOST_REQUEST_RX_DATA;
+ usb_cmd_blk.count = 2;
+ usb_cmd_blk.buffer = 0;
+
+ adi_usb_write_or_ret(&usb_cmd_blk, sizeof (usb_cmd_blk));
+
+ adi_usb_read_or_ret (&results, sizeof (results));
+ }
+
+ return results;
+}
+
+/*
+ * Controlling function to do a scan.
+ * rdata is a pointer to storage for the pointer
+ * allocated here to return data if needed
+ */
+static int perform_scan(uint8_t **rdata)
+{
+ num_tap_pairs *tap_info = &cable_params.tap_info;
+ uint8_t firstpkt = 1, lastpkt = 0, *in = NULL, *out = NULL;
+ int32_t idx, collect_data = 0;
+ uint32_t cur_len = tap_info->cur_idx;
+ uint32_t rem_len;
+
+ /* Data is scan as 32 bit words, so boundaries are adjusted here */
+ if (tap_info->bit_pos != 0x80) /* meaning no dangling bits? */
+ { /* yes, so straighten out! */
+ cur_len++;
+ tap_info->pairs[cur_len].tms = 0;
+ tap_info->pairs[cur_len].tdi = 0;
+ }
+
+ /* Pad with zeros */
+ cur_len++;
+ tap_info->pairs[cur_len].tms = 0;
+ tap_info->pairs[cur_len].tdi = 0;
+
+ while (cur_len & 0x03)
+ { /* expect to be in 32 bit words */
+ cur_len++;
+ tap_info->pairs[cur_len].tms = 0;
+ tap_info->pairs[cur_len].tdi = 0;
+ }
+
+ tap_info->cur_idx = cur_len;
+ rem_len = cur_len * sizeof (tap_pairs);
+
+ if (cur_len > cable_params.default_scanlen)
+ {
+ LOG_ERROR("TAP Scan length %d is greater than DIF Memory",
+ tap_info->cur_idx);
+ return ERROR_FAIL;
+ }
+
+ if (tap_info->cur_dat != -1)
+ { /* yes we have data, so allocate for data plus header */
+ size_t len;
+
+ len = cur_len + cable_params.tap_pair_start_idx + 16;
+ if (tap_info->dat[0].idx > 12)
+ len -= tap_info->dat[0].idx;
+
+ out = malloc(len);
+ if (out == NULL)
+ {
+ LOG_ERROR("malloc(%"PRIzd") fails", len);
+ return ERROR_FAIL;
+ }
+ *rdata = out;
+ collect_data = 1;
+ }
+ else
+ { /* no data, so allocate for just header */
+ out = malloc(cable_params.tap_pair_start_idx + 16);
+ if (out == NULL)
+ {
+ LOG_ERROR("malloc(%d) fails", cable_params.tap_pair_start_idx + 16);
+ return ERROR_FAIL;
+ }
+ collect_data = 0;
+ }
+
+ in = (uint8_t *)tap_info->pairs;
+ idx = 0;
+
+ /* Here if data is too large, we break it up into manageable chunks */
+ do
+ {
+ cur_len = (rem_len >= cable_params.max_raw_data_tx_items) ? cable_params.max_raw_data_tx_items : rem_len;
+
+ if (cur_len == rem_len)
+ lastpkt = 1;
+
+ do_rawscan(firstpkt, lastpkt, collect_data, cur_len, &in[idx] - cable_params.tap_pair_start_idx, out);
+
+ rem_len -= cur_len;
+ idx += cur_len;
+ firstpkt = 0;
+
+ } while (rem_len);
+
+ if (tap_info->cur_dat == -1)
+ { /* no data to return, so free it */
+ free(out);
+ }
+
+ return ERROR_OK;
+}
+
+/*
+ * description of raw scan packet structure:
+ *
+ * [0] : first packet flag (do setup work if needed)
+ * [1] : last packet flag (start the scan and cleanup if needed)
+ * [2] : command ID
+ * [3] : collect DOF flag (need to read DOF)
+ * [4-5] : DIF count
+ * [6-7] : scan length count
+ * [8-9] : first scan pair
+ * [10...] : more scan pairs
+ *
+ * Data input:
+ *
+ * firstpkt : Is this the first packet of the scan? 0 = NO
+ * lastpkt : Is this the last packet of the scan? 0 = NO
+ * collect_dof: Are we collecting data? 0 = NO
+ * dif_cnt : Number of bytes to send
+ * *raw_buf : Pointer to Scan Data buffer * cmd to send
+ * *out : Pointer to Scan Data buffer to receive
+ *
+ * XXX: probably needs converting from memory arrays to byte shifts
+ * so we work regardless of host endian
+ */
+static int do_rawscan(uint8_t firstpkt, uint8_t lastpkt,
+ int32_t collect_dof, int32_t dif_cnt,
+ uint8_t *raw_buf, uint8_t *out)
+{
+ usb_command_block usb_cmd_blk;
+ num_tap_pairs *tap_info = &cable_params.tap_info;
+ int32_t i, dof_start = 0;
+ uint32_t data;
+ uint32_t size = cable_params.tap_pair_start_idx + dif_cnt;
+
+ usb_cmd_blk.command = HOST_REQUEST_TX_DATA;
+ usb_cmd_blk.count = size;
+ usb_cmd_blk.buffer = 0;
+
+ /* first send Xmit request with the count of what will be sent */
+ adi_usb_write_or_ret(&usb_cmd_blk, sizeof (usb_cmd_blk));
+ i = 0;
+
+ /* send HOST_DO_SELECTIVE_RAW_SCAN command */
+ raw_buf[i++] = firstpkt;
+ raw_buf[i++] = lastpkt;
+ raw_buf[i++] = HOST_DO_SELECTIVE_RAW_SCAN;
+ if ((collect_dof && lastpkt) && (tap_info->dat[0].idx > 12))
+ {
+ int32_t j, offset;
+
+ dof_start = tap_info->dat[0].idx;
+ offset = dof_start & 7;
+ dof_start -= offset & 7;
+ tap_info->dat[0].idx = offset;
+
+ for (j = 1; j <= tap_info->cur_dat; j++)
+ {
+ tap_info->dat[j].idx -= dof_start;
+ }
+ }
+
+ raw_buf[i++] = collect_dof ? 1 : 0;
+ data = dif_cnt / 4; /* dif count in longs */
+ memcpy(raw_buf + i, &data, 4);
+ data = tap_info->cur_idx / 4; /* count in longs */
+ memcpy(raw_buf + i + 2, &data, 4);
+
+ { /* only Ice emulators use this */
+ memcpy(raw_buf + i + 4, &dof_start, 4);
+ }
+
+ adi_usb_write_or_ret(raw_buf, size);
+
+ if (lastpkt)
+ {
+ int32_t cur_rd_bytes = 0, tot_bytes_rd = 0, rd_bytes_left;
+
+ rd_bytes_left = cable_params.num_rcv_hdr_bytes + ((collect_dof) ? (tap_info->cur_idx - dof_start) : 0);
+
+ while (tot_bytes_rd < rd_bytes_left)
+ {
+ cur_rd_bytes = ((rd_bytes_left - tot_bytes_rd) > cable_params.r_buf_sz) ?
+ cable_params.r_buf_sz : (rd_bytes_left - tot_bytes_rd);
+
+ adi_usb_read_or_ret(out + tot_bytes_rd, cur_rd_bytes);
+ tot_bytes_rd += cur_rd_bytes;
+ }
+
+ if (out[0] != 2)
+ {
+ LOG_ERROR("Scan Error!");
+ return ERROR_FAIL;
+ }
+ }
+
+ return ERROR_OK;
+}
+
+static int ice1000_swd_init(void)
+{
+ LOG_INFO("%s SWD mode enabled", adi_cable_name());
+ swd_mode = true;
+ return ERROR_OK;
+}
+
+static int_least32_t ice1000_swd_frequency(struct adiv5_dap *dap, int_least32_t hz)
+{
+ if (hz > 0)
+ ice1000_set_freq(hz);
+
+ return hz;
+}
+
+static int_least32_t ice2000_swd_frequency(struct adiv5_dap *dap, int_least32_t hz)
+{
+ if (hz > 0)
+ ice2000_set_freq(hz);
+
+ return hz;
+}
+
+/* If DATA != NULL, this is for out. Otherwise, this is for in. */
+
+static int ice1000_swd_queue_packet(struct swd_packet *packet)
+{
+ uint32_t i, bit_set;
+ tap_pairs *tap_scan;
+ int32_t idx;
+ num_tap_pairs *tap_info = &cable_params.tap_info;
+
+ if (tap_info->pairs == NULL)
+ {
+ int32_t new_sz = cable_params.default_scanlen;
+ unsigned char *cmd;
+
+ cmd = malloc((sizeof (tap_pairs) * new_sz) + 1 + cable_params.tap_pair_start_idx);
+ if (cmd == NULL)
+ {
+ LOG_ERROR("malloc(%"PRIzd") fails",
+ (sizeof (tap_pairs) * new_sz) + 1 + cable_params.tap_pair_start_idx);
+ return ERROR_FAIL;
+ }
+
+ tap_info->cur_dat = -1;
+ tap_info->rcv_dat = -1;
+ tap_info->bit_pos = 0x80;
+ tap_info->total = new_sz;
+ tap_info->cmd = cmd;
+ tap_info->pairs = (tap_pairs *)(cmd + cable_params.tap_pair_start_idx);
+
+ tap_scan = tap_info->pairs;
+ tap_scan->tms = 0;
+ tap_scan->tdi = 0;
+ idx = tap_info->cur_idx = 1; /* first pair is 0 ??? */
+ tap_scan++;
+ tap_scan->tdi = 0;
+ tap_scan->tms = 0;
+ }
+ else
+ {
+ idx = tap_info->cur_idx;
+ tap_scan = &tap_info->pairs[idx];
+ }
+
+ bit_set = tap_info->bit_pos;
+
+ if (!packet->is_out)
+ {
+ if (tap_info->rcv_dat == -1)
+ {
+ tap_info->rcv_dat = 0;
+ }
+ tap_info->cur_dat++;
+ if (tap_info->cur_dat >= tap_info->num_dat)
+ {
+ int32_t new_sz;
+ dat_dat *datPtr;
+
+ new_sz = tap_info->num_dat + DAT_SZ_INC;
+ datPtr = realloc(tap_info->dat, sizeof (dat_dat) * new_sz);
+ if (datPtr == NULL)
+ {
+ LOG_ERROR("realloc(%"PRIzd") fails",
+ sizeof (dat_dat) * new_sz);
+ return ERROR_FAIL;
+ }
+ tap_info->dat = datPtr;
+ tap_info->num_dat = new_sz;
+
+ }
+ tap_info->dat[tap_info->cur_dat].idx = idx;
+ tap_info->dat[tap_info->cur_dat].pos = bit_set;
+ tap_info->dat[tap_info->cur_dat].ptr = packet;
+ }
+
+
+ for (i = 0; i < packet->length; i++)
+ {
+ if (packet->is_out)
+ tap_scan->tms |= (packet->out[i / 8] >> (i % 8)) & 0x1 ? bit_set : 0;
+ else
+ tap_scan->tdi |= bit_set;
+
+ bit_set >>= 1;
+ if (!bit_set)
+ {
+ bit_set = 0x80;
+ idx++;
+ tap_scan++;
+ tap_scan->tdi = 0;
+ tap_scan->tms = 0;
+ }
+ }
+
+ tap_info->cur_idx = idx;
+ tap_info->bit_pos = bit_set;
+
+ return ERROR_OK;
+}
+
+static int ice1000_swd_queue_data_out(const uint8_t *out, uint32_t len)
+{
+ struct swd_packet packet;
+ int retval;
+
+ memset(&packet, 0, sizeof(packet));
+
+ packet.is_out = true;
+ packet.out = out;
+ packet.length = len;
+
+ retval = ice1000_swd_queue_packet(&packet);
+
+ return retval;
+}
+
+static int ice1000_swd_queue_idle_cycles(uint32_t len)
+{
+ uint8_t *buffer;
+ int retval;
+
+ buffer = calloc(DIV_ROUND_UP(len, 8), 1);
+ if (buffer == NULL)
+ {
+ LOG_ERROR("malloc(%"PRIu32") fails", DIV_ROUND_UP(len, 8));
+ return ERROR_FAIL;
+ }
+
+ retval = ice1000_swd_queue_data_out(buffer, len);
+
+ free(buffer);
+
+ return retval;
+}
+
+static int ice1000_swd_run_queue(struct adiv5_dap *dap)
+{
+ num_tap_pairs *tap_info = &cable_params.tap_info;
+ uint8_t *buf;
+ int i, retval;
+
+ if (tap_info->cur_idx == 0 && tap_info->bit_pos == 0x80
+ && tap_info->cur_dat == -1)
+ return ERROR_OK;
+
+ /* A transaction must be followed by another transaction or at least
+ 8 idle cycles to ensure that data is clocked through the AP. */
+ ice1000_swd_queue_idle_cycles(8);
+
+ buf = NULL;
+ perform_scan(&buf);
+
+ retval = ERROR_OK;
+
+ for (i = 0; i <= tap_info->cur_dat; i++)
+ {
+ uint8_t *buffer;
+ struct swd_packet *packet = tap_info->dat[i].ptr;
+
+ buffer = get_recv_data(packet->length, tap_info->rcv_dat, buf);
+ int ack = buf_get_u32(buffer, packet->ack_pos, 3);
+
+ if (ack != SWD_ACK_OK)
+ {
+ free(buffer);
+ LOG_ERROR("SWD ack not OK: %d %s", ack,
+ ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK");
+ retval = ERROR_FAIL;
+ break;
+ }
+ else if (packet->in)
+ {
+ uint32_t data = buf_get_u32(buffer, packet->data_pos, 32);
+ int parity = buf_get_u32(buffer, packet->parity_pos, 1);
+
+ if (parity != parity_u32(data))
+ {
+ free(buffer);
+ LOG_ERROR("SWD Read data parity mismatch");
+ retval = ERROR_FAIL;
+ break;
+ }
+ else
+ {
+ uint32_t *p = packet->in;
+ *p = data;
+ }
+ }
+
+ free(buffer);
+ tap_info->rcv_dat++;
+ }
+
+ free(buf);
+ if (tap_info->pairs)
+ {
+ free(tap_info->cmd);
+ tap_info->pairs = NULL;
+ tap_info->cmd = NULL;
+ }
+ tap_info->total = 0;
+ tap_info->cur_idx = 0;
+ tap_info->bit_pos = 0x80;
+ tap_info->cur_dat = -1;
+ tap_info->rcv_dat = -1;
+
+ return retval;
+}
+
+static int ice1000_swd_switch_seq(struct adiv5_dap *dap, enum swd_special_seq seq)
+{
+ int retval;
+
+ switch (seq) {
+ case LINE_RESET:
+ LOG_DEBUG("SWD line reset");
+ retval = ice1000_swd_queue_data_out(swd_seq_line_reset, swd_seq_line_reset_len);
+ break;
+ case JTAG_TO_SWD:
+ LOG_DEBUG("JTAG-to-SWD");
+ retval = ice1000_swd_queue_data_out(swd_seq_jtag_to_swd, swd_seq_jtag_to_swd_len);
+ break;
+ case SWD_TO_JTAG:
+ LOG_DEBUG("SWD-to-JTAG");
+ retval = ice1000_swd_queue_data_out(swd_seq_swd_to_jtag, swd_seq_swd_to_jtag_len);
+ break;
+ default:
+ LOG_ERROR("Sequence %d not supported", seq);
+ retval = ERROR_FAIL;
+ }
+
+ return retval;
+}
+
+static int ice1000_swd_ensure_space(struct adiv5_dap *dap, unsigned int bits)
+{
+ int retval = ERROR_OK;
+
+ if (cable_params.tap_info.cur_idx + DIV_ROUND_UP(bits, 8) >= cable_params.trigger_scanlen)
+ retval = ice1000_swd_run_queue(dap);
+
+ return retval;
+}
+
+static int ice1000_swd_queue_cmd(struct adiv5_dap *dap, uint8_t cmd, uint32_t *dst, uint32_t data)
+{
+ uint8_t data_parity_trn[DIV_ROUND_UP(32 + 1, 8)];
+ struct swd_packet *packet;
+ int retval;
+
+ retval = ice1000_swd_ensure_space(dap, 8 + 38 + dap->memaccess_tck);
+ if (retval != ERROR_OK)
+ return retval;
+
+ packet = calloc(sizeof(struct swd_packet), 1);
+ if (packet == NULL)
+ return ERROR_FAIL;
+
+ cmd |= SWD_CMD_START | SWD_CMD_PARK;
+
+ retval = ice1000_swd_queue_data_out(&cmd, 8);
+ if (retval != ERROR_OK)
+ return retval;
+
+ if (cmd & SWD_CMD_RnW) {
+ /* Queue a read transaction */
+ packet->out = false;
+ packet->ack_pos = 0;
+ packet->data_pos = 3;
+ packet->parity_pos = 35;
+ packet->in = dst;
+ packet->length = 1 + 3 + 32 + 1 + 1;
+
+ retval = ice1000_swd_queue_packet(packet);
+ } else {
+ /* Queue a write transaction */
+ packet->out = false;
+ packet->ack_pos = 0;
+ packet->length = 1 + 3 + 1;
+
+ retval = ice1000_swd_queue_packet(packet);
+
+ buf_set_u32(data_parity_trn, 0, 32, data);
+ buf_set_u32(data_parity_trn, 32, 1, parity_u32(data));
+
+ if (retval == ERROR_OK)
+ retval = ice1000_swd_queue_data_out(data_parity_trn, 32 + 1);
+ }
+
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* Insert idle cycles after AP accesses to avoid WAIT */
+ if (cmd & SWD_CMD_APnDP)
+ retval = ice1000_swd_queue_idle_cycles(dap->memaccess_tck);
+
+ return retval;
+}
+
+static void ice1000_swd_write_reg(struct adiv5_dap *dap, uint8_t cmd, uint32_t value)
+{
+ int retval;
+ retval = ice1000_swd_queue_cmd(dap, cmd, NULL, value);
+ if (retval != ERROR_OK)
+ LOG_ERROR("%s SWD write register failed", adi_cable_name());
+}
+
+static void ice1000_swd_read_reg(struct adiv5_dap *dap, uint8_t cmd, uint32_t *value)
+{
+ int retval;
+ retval = ice1000_swd_queue_cmd(dap, cmd, value, 0);
+ if (retval != ERROR_OK)
+ LOG_ERROR("%s SWD read register failed", adi_cable_name());
+}
+
+COMMAND_HANDLER(ice2000_handle_voltage_command)
+{
+ uint32_t voltage;
+
+ if (CMD_ARGC != 1)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], voltage);
+
+ if (voltage == 0 || voltage > 3)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ /* This command can only be used before adi_connect */
+ if (cable_params.usb_handle)
+ return ERROR_FAIL;
+
+ cable_params.cur_voltage = voltage;
+
+ return ERROR_OK;
+}
+
+static const struct swd_driver ice1000_swd = {
+ .init = ice1000_swd_init,
+ .frequency = ice1000_swd_frequency,
+ .switch_seq = ice1000_swd_switch_seq,
+ .read_reg = ice1000_swd_read_reg,
+ .write_reg = ice1000_swd_write_reg,
+ .run = ice1000_swd_run_queue,
+};
+
+struct jtag_interface ice1000_interface = {
+ .name = "ice1000",
+ .supported = DEBUG_CAP_TMS_SEQ,
+ .commands = NULL,
+ .transports = jtag_and_swd,
+ .swd = &ice1000_swd,
+
+ .init = ice1000_init,
+ .quit = ice1000_quit,
+ .speed = ice1000_speed,
+ .speed_div = ice1000_speed_div,
+ .khz = ice1000_khz,
+ .execute_queue = ice1000_execute_queue,
+};
+
+static const struct swd_driver ice2000_swd = {
+ .init = ice1000_swd_init,
+ .frequency = ice2000_swd_frequency,
+ .switch_seq = ice1000_swd_switch_seq,
+ .read_reg = ice1000_swd_read_reg,
+ .write_reg = ice1000_swd_write_reg,
+ .run = ice1000_swd_run_queue,
+};
+
+static const struct command_registration ice2000_command_handlers[] = {
+ {
+ .name = "ice2000_voltage",
+ .handler = &ice2000_handle_voltage_command,
+ .mode = COMMAND_CONFIG,
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
+struct jtag_interface ice2000_interface = {
+ .name = "ice2000",
+ .supported = DEBUG_CAP_TMS_SEQ,
+ .commands = ice2000_command_handlers,
+ .transports = jtag_and_swd,
+ .swd = &ice2000_swd,
+
+ .init = ice2000_init,
+ .quit = ice2000_quit,
+ .speed = ice2000_speed,
+ .speed_div = ice2000_speed_div,
+ .khz = ice2000_khz,
+ .execute_queue = ice1000_execute_queue,
+};
diff --git a/src/jtag/interface.h b/src/jtag/interface.h
index e7b2014..284659b 100644
--- a/src/jtag/interface.h
+++ b/src/jtag/interface.h
@@ -327,6 +327,7 @@ struct jtag_interface {
};
extern const char * const jtag_only[];
+extern const char * const jtag_and_swd[];
void adapter_assert_reset(void);
void adapter_deassert_reset(void);
diff --git a/src/jtag/interfaces.c b/src/jtag/interfaces.c
index 62c5d45..ee037ae 100644
--- a/src/jtag/interfaces.c
+++ b/src/jtag/interfaces.c
@@ -131,6 +131,12 @@ extern struct jtag_interface bcm2835gpio_interface;
#if BUILD_CMSIS_DAP == 1
extern struct jtag_interface cmsis_dap_interface;
#endif
+#ifdef BUILD_ICE_1000
+extern struct jtag_interface ice1000_interface;
+#endif
+#ifdef BUILD_ICE_2000
+extern struct jtag_interface ice2000_interface;
+#endif
#endif /* standard drivers */
/**
@@ -230,6 +236,12 @@ struct jtag_interface *jtag_interfaces[] = {
#if BUILD_CMSIS_DAP == 1
&cmsis_dap_interface,
#endif
+#if BUILD_ICE_1000 == 1
+ &ice1000_interface,
+#endif
+#if BUILD_ICE_2000 == 1
+ &ice2000_interface,
+#endif
#endif /* standard drivers */
NULL,
};
diff --git a/src/jtag/jtag.h b/src/jtag/jtag.h
index eda4ccd..2418a46 100644
--- a/src/jtag/jtag.h
+++ b/src/jtag/jtag.h
@@ -231,6 +231,7 @@ int jtag_unregister_event_callback(jtag_event_handler_t f, void *x);
int jtag_call_event_callbacks(enum jtag_event event);
+const char *jtag_get_name(void);
/** @returns The current JTAG speed setting. */
int jtag_get_speed(int *speed);
diff --git a/src/openocd.c b/src/openocd.c
index d17af20..f121dd3 100644
--- a/src/openocd.c
+++ b/src/openocd.c
@@ -48,7 +48,7 @@
#endif
#define OPENOCD_VERSION \
- "Open On-Chip Debugger " VERSION RELSTR " (" PKGBLDDATE ")"
+ "Open On-Chip Debugger " PKGVERSION VERSION
static const char openocd_startup_tcl[] = {
#include "startup_tcl.inc"
@@ -184,6 +184,16 @@ COMMAND_HANDLER(handle_add_script_search_dir_command)
return ERROR_OK;
}
+COMMAND_HANDLER(handle_firmware_command)
+{
+ if (CMD_ARGC != 1)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ set_firmware_filename(CMD_ARGV[0]);
+
+ return ERROR_OK;
+}
+
static const struct command_registration openocd_command_handlers[] = {
{
.name = "version",
@@ -215,6 +225,12 @@ static const struct command_registration openocd_command_handlers[] = {
.help = "dir to search for config files and scripts",
.usage = "<directory>"
},
+ {
+ .name = "firmware",
+ .handler = &handle_firmware_command,
+ .mode = COMMAND_CONFIG,
+ .help = "Set the firmware to be load.",
+ },
COMMAND_REGISTRATION_DONE
};
@@ -327,9 +343,7 @@ int openocd_main(int argc, char *argv[])
if (ioutil_init(cmd_ctx) != ERROR_OK)
return EXIT_FAILURE;
- LOG_OUTPUT("For bug reports, read\n\t"
- "http://openocd.org/doc/doxygen/bugs.html"
- "\n");
+ LOG_OUTPUT("Report bugs to %s\n", REPORT_BUGS_TO);
command_context_mode(cmd_ctx, COMMAND_CONFIG);
command_set_output_handler(cmd_ctx, configuration_output_handler, NULL);
diff --git a/src/pld/pld.c b/src/pld/pld.c
index fb5d32e..ced98f9 100644
--- a/src/pld/pld.c
+++ b/src/pld/pld.c
@@ -158,7 +158,7 @@ COMMAND_HANDLER(handle_pld_load_command)
gettimeofday(&end, NULL);
timeval_subtract(&duration, &end, &start);
- command_print(CMD_CTX, "loaded file %s to pld device %u in %jis %jius",
+ command_print(CMD_CTX, "loaded file %s to pld device %u in %"PRIjd"s %"PRIjd"us",
CMD_ARGV[1], dev_id,
(intmax_t)duration.tv_sec, (intmax_t)duration.tv_usec);
}
diff --git a/src/rtos/rtos.c b/src/rtos/rtos.c
index 3420d06..15b536a 100644
--- a/src/rtos/rtos.c
+++ b/src/rtos/rtos.c
@@ -359,8 +359,9 @@ int rtos_thread_packet(struct connection *connection, char const *packet, int pa
gdb_put_packet(connection, out_str, strlen(out_str));
free(out_str);
}
- } else
- gdb_put_packet(connection, "l", 1);
+ } else {
+ gdb_put_packet(connection, "m1", 2);
+ }
return ERROR_OK;
} else if (strncmp(packet, "qsThreadInfo", 12) == 0) {
@@ -384,7 +385,7 @@ int rtos_thread_packet(struct connection *connection, char const *packet, int pa
size = snprintf(buffer, 19, "QC%016" PRIx64, target->rtos->current_thread);
gdb_put_packet(connection, buffer, size);
} else
- gdb_put_packet(connection, "QC0", 3);
+ gdb_put_packet(connection, "QC1", 3);
return ERROR_OK;
} else if (packet[0] == 'T') { /* Is thread alive? */
threadid_t threadid;
@@ -399,7 +400,7 @@ int rtos_thread_packet(struct connection *connection, char const *packet, int pa
}
}
}
- if (found != -1)
+ if (found != -1 || target->rtos == NULL)
gdb_put_packet(connection, "OK", 2); /* thread alive */
else
gdb_put_packet(connection, "E01", 3); /* thread not found */
diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c
index 4a33a30..63cf796 100644
--- a/src/server/gdb_server.c
+++ b/src/server/gdb_server.c
@@ -80,11 +80,6 @@ struct gdb_connection {
* 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.
@@ -832,6 +827,8 @@ static void gdb_fileio_reply(struct target *target, struct connection *connectio
sprintf(fileio_command, "F%s,%" PRIx32 "/%" PRIx32, target->fileio_info->identifier,
target->fileio_info->param_1,
target->fileio_info->param_2);
+ else if (strcmp(target->fileio_info->identifier, "signal") == 0)
+ sprintf(fileio_command, "T%02x", target->fileio_info->param_1);
else if (strcmp(target->fileio_info->identifier, "exit") == 0) {
/* If target hits exit syscall, report to GDB the program is terminated.
* In addition, let target run its own exit syscall handler. */
@@ -842,7 +839,12 @@ static void gdb_fileio_reply(struct target *target, struct connection *connectio
/* encounter unknown syscall, continue */
gdb_connection->frontend_state = TARGET_RUNNING;
- target_resume(target, 1, 0x0, 0, 0);
+
+ if (gdb_running_type == 'c')
+ target_resume(target, 1, 0x0, 1, 0);
+ else if (gdb_running_type == 's')
+ target_step(target, 1, 0x0, 0);
+
return;
}
@@ -932,7 +934,6 @@ static int gdb_new_connection(struct connection *connection)
gdb_connection->busy = 0;
gdb_connection->noack_mode = 0;
gdb_connection->sync = false;
- gdb_connection->mem_write_error = false;
gdb_connection->attached = true;
gdb_connection->target_desc.tdesc = NULL;
gdb_connection->target_desc.tdesc_length = 0;
@@ -966,6 +967,12 @@ static int gdb_new_connection(struct connection *connection)
gdb_putback_char(connection, initial_ack);
target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_ATTACH);
+ /* If target is halted, e.g. there is a halt command in gdb-attach
+ * event in the config file, we don't need sync.
+ */
+ if (gdb_service->target->state == TARGET_HALTED)
+ gdb_connection->sync = false;
+
if (gdb_use_memory_map) {
/* Connect must fail if the memory map can't be set up correctly.
*
@@ -1490,31 +1497,20 @@ static int gdb_write_memory_binary_packet(struct connection *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;
+ }
+
+ if (retval != ERROR_OK)
+ {
+ LOG_ERROR("Memory write failure!");
+ gdb_put_packet(connection, "E00", 3);
+ }
+ else
+ {
+ gdb_put_packet(connection, "OK", 2);
}
return ERROR_OK;
@@ -1539,7 +1535,7 @@ static int gdb_step_continue_packet(struct connection *connection,
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);
+ retval = target_resume(target, current, address, 1, 0);
} else if (packet[0] == 's') {
LOG_DEBUG("step");
/* step at current or address, don't handle breakpoints */
@@ -2591,7 +2587,7 @@ static int gdb_fileio_response_packet(struct connection *connection,
/* After File-I/O ends, keep continue or step */
if (gdb_running_type == 'c')
- retval = target_resume(target, 1, 0x0, 0, 0);
+ retval = target_resume(target, 1, 0x0, 1, 0);
else if (gdb_running_type == 's')
retval = target_step(target, 1, 0x0, 0);
else
@@ -2717,14 +2713,6 @@ static int gdb_input_inner(struct connection *connection)
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) {
diff --git a/src/server/server.c b/src/server/server.c
index 7e90d89..0ce5c9c 100644
--- a/src/server/server.c
+++ b/src/server/server.c
@@ -443,27 +443,6 @@ int server_loop(struct command_context *command_context)
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;
@@ -489,6 +468,27 @@ int server_loop(struct command_context *command_context)
c = c->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);
+ }
+ }
}
#ifdef _WIN32
@@ -540,6 +540,8 @@ int server_preinit(void)
SetConsoleCtrlHandler(ControlHandler, TRUE);
signal(SIGBREAK, sig_handler);
+#else
+ signal(SIGHUP, sig_handler);
#endif
signal(SIGINT, sig_handler);
signal(SIGTERM, sig_handler);
diff --git a/src/svf/svf.c b/src/svf/svf.c
index cf0cfae..e03fd94 100644
--- a/src/svf/svf.c
+++ b/src/svf/svf.c
@@ -532,7 +532,7 @@ COMMAND_HANDLER(handle_svf_command)
time_measure_s %= 60;
if (time_measure_ms < 1000)
command_print(CMD_CTX,
- "\r\nTime used: %dm%ds%lldms ",
+ "\r\nTime used: %dm%ds%"PRIlld"ms ",
time_measure_m,
time_measure_s,
time_measure_ms);
diff --git a/src/target/Makefile.am b/src/target/Makefile.am
index 2cec491..80ee5ea 100644
--- a/src/target/Makefile.am
+++ b/src/target/Makefile.am
@@ -36,6 +36,7 @@ libtarget_la_SOURCES = \
$(MIPS32_SRC) \
$(NDS32_SRC) \
$(INTEL_IA32_SRC) \
+ $(BLACKFIN_SRC) \
avrt.c \
dsp563xx.c \
dsp563xx_once.c \
@@ -50,7 +51,8 @@ TARGET_CORE_SRC = \
target.c \
target_request.c \
testee.c \
- smp.c
+ smp.c \
+ xml_support.c
ARMV4_5_SRC = \
armv4_5.c \
@@ -82,7 +84,8 @@ ARMV7_SRC = \
armv7m_trace.c \
cortex_m.c \
armv7a.c \
- cortex_a.c
+ cortex_a.c \
+ cortex_a_memory_map.c
ARM_DEBUG_SRC = \
arm_dpm.c \
@@ -106,6 +109,14 @@ AVR32_SRC = \
avr32_mem.c \
avr32_regs.c
+BLACKFIN_SRC = \
+ blackfin.c \
+ blackfin_config.c \
+ blackfin_insn.c \
+ blackfin_jtag.c \
+ blackfin_mem.c \
+ blackfin_memory_map.c
+
MIPS32_SRC = \
mips32.c \
mips_m4k.c \
@@ -157,12 +168,19 @@ noinst_HEADERS = \
armv7m.h \
armv7m_trace.h \
avrt.h \
+ blackfin.h \
+ blackfin_config.h \
+ blackfin_insn.h \
+ blackfin_jtag.h \
+ blackfin_mem.h \
+ blackfin_memory_map.h \
dsp563xx.h \
dsp563xx_once.h \
dsp5680xx.h \
breakpoints.h \
cortex_m.h \
cortex_a.h \
+ cortex_a_memory_map.h \
embeddedice.h \
etb.h \
etm.h \
@@ -199,7 +217,8 @@ noinst_HEADERS = \
nds32_v3m.h \
nds32_aice.h \
lakemont.h \
- x86_32_common.h
+ x86_32_common.h \
+ xml_support.h
ocddatadir = $(pkglibdir)
nobase_dist_ocddata_DATA =
diff --git a/src/target/adi_v5_jtag.c b/src/target/adi_v5_jtag.c
index c1e1286..3f6f9be 100644
--- a/src/target/adi_v5_jtag.c
+++ b/src/target/adi_v5_jtag.c
@@ -115,8 +115,6 @@ static int adi_jtag_dp_scan(struct adiv5_dap *dap,
* 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);
diff --git a/src/target/arm.h b/src/target/arm.h
index 27636cc..25227df 100644
--- a/src/target/arm.h
+++ b/src/target/arm.h
@@ -40,6 +40,11 @@
* support has not yet been integrated, affecting Cortex-M parts.
*/
+enum {
+ ARM_SP = 13,
+ ARM_PC = 15,
+};
+
/**
* Represent state of an ARM core.
*
@@ -131,9 +136,27 @@ struct arm {
/** Flag reporting whether semihosting is active. */
bool is_semihosting;
+ /** Flag reporting whether continue/step hits syscall or not. */
+ bool hit_syscall;
+
/** Value to be returned by semihosting SYS_ERRNO request. */
int semihosting_errno;
+ /** Flag reporting whether syscall is aborted. */
+ bool semihosting_ctrl_c;
+
+ /** Record syscall ID for other operations to do special processing for target. */
+ uint32_t active_syscall_id;
+
+ /** Semihosting result for some specific ARM system calls. */
+ uint32_t semihosting_result;
+
+ /** Values to be set by semihosting SYS_HEAPINFO operation. */
+ uint32_t heap_base;
+ uint32_t heap_limit;
+ uint32_t stack_base;
+ uint32_t stack_limit;
+
int (*setup_semihosting)(struct target *target, int enable);
/** Backpointer to the target. */
diff --git a/src/target/arm7_9_common.c b/src/target/arm7_9_common.c
index 617ee78..9b40bd1 100644
--- a/src/target/arm7_9_common.c
+++ b/src/target/arm7_9_common.c
@@ -829,9 +829,6 @@ int arm7_9_poll(struct target *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;
diff --git a/src/target/arm_adi_v5.c b/src/target/arm_adi_v5.c
index f7e58d0..09904db 100644
--- a/src/target/arm_adi_v5.c
+++ b/src/target/arm_adi_v5.c
@@ -77,6 +77,7 @@
#include "arm_adi_v5.h"
#include <helper/time_support.h>
+#if 0
/* ARM ADI Specification requires at least 10 bits used for TAR autoincrement */
/*
@@ -87,6 +88,7 @@ static uint32_t max_tar_block_size(uint32_t tar_autoincr_block, uint32_t address
{
return tar_autoincr_block - ((tar_autoincr_block - 1) & address);
}
+#endif
/***************************************************************************
* *
@@ -333,7 +335,7 @@ int mem_ap_write(struct adiv5_dap *dap, const uint8_t *buffer, uint32_t size, ui
while (nbytes > 0) {
uint32_t this_size = size;
-
+#if 0
/* Select packed transfer if possible */
if (addrinc && dap->packed_transfers && nbytes >= 4
&& max_tar_block_size(dap->tar_autoincr_block, address) >= 4) {
@@ -342,7 +344,9 @@ int mem_ap_write(struct adiv5_dap *dap, const uint8_t *buffer, uint32_t size, ui
} else {
retval = dap_setup_accessport_csw(dap, csw_size | csw_addrincr);
}
-
+#else
+ retval = dap_setup_accessport_csw(dap, csw_size | csw_addrincr);
+#endif
if (retval != ERROR_OK)
break;
@@ -395,6 +399,21 @@ int mem_ap_write(struct adiv5_dap *dap, const uint8_t *buffer, uint32_t size, ui
if (retval == ERROR_OK)
retval = dap_run(dap);
+ if (addrinc) {
+ uint32_t tar;
+ retval = dap_queue_ap_read(dap, AP_REG_TAR, &tar);
+ if (retval == ERROR_OK)
+ retval = dap_run(dap);
+ if (retval != ERROR_OK)
+ return retval;
+ /* Update TAR to reflect incremented address */
+ dap->ap_tar_value = tar;
+#if 0
+ if (tar != address)
+ LOG_ERROR("TAR auto-increment does not work");
+#endif
+ }
+
if (retval != ERROR_OK) {
uint32_t tar;
if (dap_queue_ap_read(dap, AP_REG_TAR, &tar) == ERROR_OK
@@ -468,7 +487,7 @@ int mem_ap_read(struct adiv5_dap *dap, uint8_t *buffer, uint32_t size, uint32_t
* and alignment. */
while (nbytes > 0) {
uint32_t this_size = size;
-
+#if 0
/* Select packed transfer if possible */
if (addrinc && dap->packed_transfers && nbytes >= 4
&& max_tar_block_size(dap->tar_autoincr_block, address) >= 4) {
@@ -477,6 +496,9 @@ int mem_ap_read(struct adiv5_dap *dap, uint8_t *buffer, uint32_t size, uint32_t
} else {
retval = dap_setup_accessport_csw(dap, csw_size | csw_addrincr);
}
+#else
+ retval = dap_setup_accessport_csw(dap, csw_size | csw_addrincr);
+#endif
if (retval != ERROR_OK)
break;
@@ -498,34 +520,47 @@ int mem_ap_read(struct adiv5_dap *dap, uint8_t *buffer, uint32_t size, uint32_t
if (retval == ERROR_OK)
retval = dap_run(dap);
+ if (addrinc) {
+ uint32_t tar;
+ retval = dap_queue_ap_read(dap, AP_REG_TAR, &tar);
+ if (retval == ERROR_OK)
+ retval = dap_run(dap);
+ if (retval != ERROR_OK)
+ return retval;
+ /* Update TAR to reflect incremented address */
+ dap->ap_tar_value = tar;
+#if 0
+ if (tar != address)
+ LOG_ERROR("TAR auto-increment does not work");
+#endif
+ }
+
/* Restore state */
address = adr;
nbytes = size * count;
read_ptr = read_buf;
- /* If something failed, read TAR to find out how much data was successfully read, so we can
- * at least give the caller what we have. */
+ /* If something failed, read TAR to find out how much data was successfully read. */
if (retval != ERROR_OK) {
uint32_t tar;
if (dap_queue_ap_read(dap, AP_REG_TAR, &tar) == ERROR_OK
- && dap_run(dap) == ERROR_OK) {
+ && dap_run(dap) == ERROR_OK)
LOG_ERROR("Failed to read memory at 0x%08"PRIx32, tar);
- if (nbytes > tar - address)
- nbytes = tar - address;
- } else {
+ else
LOG_ERROR("Failed to read memory and, additionally, failed to find out where");
- nbytes = 0;
- }
+
+ nbytes = 0;
}
/* Replay loop to populate caller's buffer from the correct word and byte lane */
while (nbytes > 0) {
uint32_t this_size = size;
-
+#if 0
if (addrinc && dap->packed_transfers && nbytes >= 4
&& max_tar_block_size(dap->tar_autoincr_block, address) >= 4) {
this_size = 4;
}
+#endif
if (dap->ti_be_32_quirks) {
switch (this_size) {
@@ -663,6 +698,11 @@ int ahbap_debugport_init(struct adiv5_dap *dap)
*/
dap->ap_current = !0;
dap_ap_select(dap, 0);
+ /* Make sure CTRLSEL bit is cleared */
+ retval = dap_queue_dp_write(dap, DP_SELECT, 0);
+ if (retval != ERROR_OK)
+ return retval;
+
dap->last_read = NULL;
for (size_t i = 0; i < 10; i++) {
@@ -1576,6 +1616,98 @@ COMMAND_HANDLER(dap_apsel_command)
return retval;
}
+static int jim_dap_readmem(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) {
+ Jim_SetResultFormatted(goi.interp,
+ "usage: %s <ap> <address>", cmd_name);
+ return JIM_ERR;
+ }
+
+ int e;
+ jim_wide ap;
+ e = Jim_GetOpt_Wide(&goi, &ap);
+ if (e != JIM_OK)
+ return e;
+
+ jim_wide address;
+ e = Jim_GetOpt_Wide(&goi, &address);
+ if (e != JIM_OK)
+ return e;
+
+ /* all args must be consumed */
+ if (goi.argc != 0)
+ return JIM_ERR;
+
+ struct command_context *cmd_ctx = current_command_context(goi.interp);
+ struct target *target = get_current_target(cmd_ctx);
+ struct arm *arm = target_to_arm(target);
+ struct adiv5_dap *dap = arm->dap;
+
+ uint32_t value;
+ int retval;
+
+ retval = mem_ap_sel_read_atomic_u32(dap, (uint8_t)ap, (uint32_t)address, &value);
+ if (retval != ERROR_OK)
+ return JIM_ERR;
+
+ Jim_SetResult(goi.interp, Jim_NewIntObj(goi.interp, value));
+
+ return JIM_OK;
+}
+
+static int jim_dap_writemem(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 != 3) {
+ Jim_SetResultFormatted(goi.interp,
+ "usage: %s <ap> <address> <value>", cmd_name);
+ return JIM_ERR;
+ }
+
+ int e;
+ jim_wide ap;
+ e = Jim_GetOpt_Wide(&goi, &ap);
+ if (e != JIM_OK)
+ return e;
+
+ jim_wide address;
+ e = Jim_GetOpt_Wide(&goi, &address);
+ if (e != JIM_OK)
+ return e;
+
+ jim_wide value;
+ e = Jim_GetOpt_Wide(&goi, &value);
+ if (e != JIM_OK)
+ return e;
+
+ /* all args must be consumed */
+ if (goi.argc != 0)
+ return JIM_ERR;
+
+ struct command_context *cmd_ctx = current_command_context(goi.interp);
+ struct target *target = get_current_target(cmd_ctx);
+ struct arm *arm = target_to_arm(target);
+ struct adiv5_dap *dap = arm->dap;
+
+ int retval;
+
+ retval = mem_ap_sel_write_atomic_u32(dap, (uint8_t)ap, (uint32_t)address, (uint32_t)value);
+ if (retval != ERROR_OK)
+ return JIM_ERR;
+
+ return JIM_OK;
+}
+
COMMAND_HANDLER(dap_apcsw_command)
{
struct target *target = get_current_target(CMD_CTX);
@@ -1722,6 +1854,20 @@ static const struct command_registration dap_commands[] = {
.usage = "[cycles]",
},
{
+ .name = "readmem",
+ .jim_handler = jim_dap_readmem,
+ .mode = COMMAND_EXEC,
+ .help = "read memory using MEM-AP",
+ .usage = "ap address",
+ },
+ {
+ .name = "writemem",
+ .jim_handler = jim_dap_writemem,
+ .mode = COMMAND_EXEC,
+ .help = "write memory using MEM-AP",
+ .usage = "ap address value",
+ },
+ {
.name = "ti_be_32_quirks",
.handler = dap_ti_be_32_quirks_command,
.mode = COMMAND_CONFIG,
diff --git a/src/target/arm_adi_v5.h b/src/target/arm_adi_v5.h
index 8d12608..00d4585 100644
--- a/src/target/arm_adi_v5.h
+++ b/src/target/arm_adi_v5.h
@@ -219,6 +219,9 @@ struct adiv5_dap {
* should be performed before the next access.
*/
bool do_reconnect;
+
+ uint32_t ahb_mem_start_address;
+ uint32_t ahb_mem_end_address;
};
/**
diff --git a/src/target/arm_dpm.c b/src/target/arm_dpm.c
index 5df625f..9824006 100644
--- a/src/target/arm_dpm.c
+++ b/src/target/arm_dpm.c
@@ -264,6 +264,16 @@ int arm_dpm_read_current_registers(struct arm_dpm *dpm)
/* update core mode and state, plus shadow mapping for R8..R14 */
arm_set_cpsr(arm, cpsr);
+ if (arm->spsr) {
+ uint32_t spsr;
+ retval = dpm->instr_read_data_r0(dpm, ARMV4_5_MRS(0, 1), &spsr);
+ if (retval != ERROR_OK)
+ goto fail;
+ buf_set_u32(arm->spsr->value, 0, 32, spsr);
+ arm->spsr->dirty = 0;
+ arm->spsr->valid = 1;
+ }
+
/* REVISIT we can probably avoid reading R1..R14, saving time... */
for (unsigned i = 1; i < 16; i++) {
r = arm_reg_current(arm, i);
@@ -871,6 +881,22 @@ static int dpm_remove_watchpoint(struct target *target, struct watchpoint *wp)
return retval;
}
+static int dpm_hit_watchpoint(struct target *target, struct watchpoint **hit_watchpoint)
+{
+ struct arm *arm = target_to_arm(target);
+ struct arm_dpm *dpm = arm->dpm;
+
+ for (unsigned i = 0; i < dpm->nwp; i++) {
+ /* since we only support only 1 watchpoint, no need for matching */
+ if (dpm->dwp[i].wp) {
+ *hit_watchpoint = dpm->dwp[i].wp;
+ return ERROR_OK;
+ }
+ }
+
+ return ERROR_FAIL;
+}
+
void arm_dpm_report_wfar(struct arm_dpm *dpm, uint32_t addr)
{
switch (dpm->arm->core_state) {
@@ -902,20 +928,20 @@ void arm_dpm_report_dscr(struct arm_dpm *dpm, uint32_t dscr)
/* Examine debug reason */
switch (DSCR_ENTRY(dscr)) {
- case 6: /* Data abort (v6 only) */
- case 7: /* Prefetch abort (v6 only) */
+ case DSCR_ENTRY_D_SIDE_ABORT: /* v6 only */
+ case DSCR_ENTRY_I_SIDE_ABORT: /* v6 only */
/* FALL THROUGH -- assume a v6 core in abort mode */
- case 0: /* HALT request from debugger */
- case 4: /* EDBGRQ */
+ case DSCR_ENTRY_HALT_REQ:
+ case DSCR_ENTRY_EXT_DBG_REQ:
target->debug_reason = DBG_REASON_DBGRQ;
break;
- case 1: /* HW breakpoint */
- case 3: /* SW BKPT */
- case 5: /* vector catch */
+ case DSCR_ENTRY_BREAKPOINT:
+ case DSCR_ENTRY_BKPT_INSTR:
+ case DSCR_ENTRY_VECT_CATCH:
target->debug_reason = DBG_REASON_BREAKPOINT;
break;
- case 2: /* asynch watchpoint */
- case 10:/* precise watchpoint */
+ case DSCR_ENTRY_IMPRECISE_WATCHPT:
+ case DSCR_ENTRY_PRECISE_WATCHPT:
target->debug_reason = DBG_REASON_WATCHPOINT;
break;
default:
@@ -968,6 +994,7 @@ int arm_dpm_setup(struct arm_dpm *dpm)
/* watchpoint setup */
target->type->add_watchpoint = dpm_add_watchpoint;
target->type->remove_watchpoint = dpm_remove_watchpoint;
+ target->type->hit_watchpoint = dpm_hit_watchpoint;
/* FIXME add vector catch support */
@@ -985,6 +1012,10 @@ int arm_dpm_setup(struct arm_dpm *dpm)
LOG_INFO("%s: hardware has %d breakpoints, %d watchpoints",
target_name(target), dpm->nbp, dpm->nwp);
+ if (dpm->nwp > 1) {
+ dpm->nwp = 1;
+ LOG_INFO("%s: but you can only set 1 watchpoint", target_name(target));
+ }
/* REVISIT ... and some of those breakpoints could match
* execution context IDs...
diff --git a/src/target/arm_dpm.h b/src/target/arm_dpm.h
index 73ed1bc..090bdab 100644
--- a/src/target/arm_dpm.h
+++ b/src/target/arm_dpm.h
@@ -173,16 +173,16 @@ void arm_dpm_report_wfar(struct arm_dpm *, uint32_t wfar);
/* 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)
+#define DSCR_ENTRY_HALT_REQ 0x0
+#define DSCR_ENTRY_BREAKPOINT 0x1
+#define DSCR_ENTRY_IMPRECISE_WATCHPT 0x2
+#define DSCR_ENTRY_BKPT_INSTR 0x3
+#define DSCR_ENTRY_EXT_DBG_REQ 0x4
+#define DSCR_ENTRY_VECT_CATCH 0x5
+#define DSCR_ENTRY_D_SIDE_ABORT 0x6 /* v6 only */
+#define DSCR_ENTRY_I_SIDE_ABORT 0x7 /* v6 only */
+#define DSCR_ENTRY_OS_UNLOCK 0x8
+#define DSCR_ENTRY_PRECISE_WATCHPT 0xA
/* DTR modes */
#define DSCR_EXT_DCC_NON_BLOCKING (0x0 << 20)
diff --git a/src/target/arm_semihosting.c b/src/target/arm_semihosting.c
index 21b7809..cb73848 100644
--- a/src/target/arm_semihosting.c
+++ b/src/target/arm_semihosting.c
@@ -41,6 +41,7 @@
#include "armv4_5.h"
#include "arm7_9_common.h"
#include "armv7m.h"
+#include "armv7a.h"
#include "cortex_m.h"
#include "register.h"
#include "arm_semihosting.h"
@@ -48,267 +49,477 @@
#include <helper/log.h>
#include <sys/stat.h>
-static const 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)
+/* We will need a temporary workspace for SYS_FLEN and SYS_TIME. */
+#define ARM_SEMIHOSTING_TEMP_BUFFER_SIZE 128
+static uint8_t arm_semihosting_temp_buffer[ARM_SEMIHOSTING_TEMP_BUFFER_SIZE];
+static uint32_t arm_semihosting_work_addr;
+
+/**
+ * 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)
+{
+ struct arm *arm = target_to_arm(target);
+ uint32_t pc, lr, spsr;
+ struct reg *r;
+ int retval;
+
+ if (!arm->is_semihosting)
+ return 0;
+
+ if (is_arm7_9(target_to_arm7_9(target))
+ || is_armv7a(target_to_armv7a(target))) {
+ uint32_t vector_base;
+
+ if (arm->core_mode != ARM_MODE_SVC)
+ return 0;
+
+ /* MRC p15,0,<Rt>,c12,c0,0 ; Read Vector Base Register */
+ retval = arm->mrc(target, 15,
+ 0, 0, /* op1, op2 */
+ 12, 0, /* CRn, CRm */
+ &vector_base);
+ if (retval != ERROR_OK)
+ return 1;
+
+ /* Check Supervisor Call vector. */
+ r = arm->pc;
+ pc = buf_get_u32(r->value, 0, 32);
+ /* TODO We should check DBGVCR.V */
+ if (pc != vector_base + 0x8 && 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!");
+ return 0;
+ }
+
+ 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 0;
+ 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 0;
+ 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 0;
+
+ /* bkpt 0xAB */
+ if (insn != 0xBEAB)
+ return 0;
+ } else {
+ LOG_ERROR("Unsupported semi-hosting Target");
+ return 0;
+ }
+
+ return 1;
+}
+
+void arm_semihosting_step_over_svc(struct target *target)
+{
+ struct arm *arm = target_to_arm(target);
+
+ if (is_arm7_9(target_to_arm7_9(target))
+ || is_armv7a(target_to_armv7a(target))) {
+ uint32_t spsr, lr;
+
+ /* LR --> PC */
+ lr = buf_get_u32(arm_reg_current(arm, 14)->value, 0, 32);
+ buf_set_u32(arm->core_cache->reg_list[15].value, 0, 32, lr);
+ 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;
+
+ }
+}
+
+void arm_semihosting_step_over_bkpt(struct target *target)
+{
+ struct arm *arm = target_to_arm(target);
+
+ if (is_armv7m(target_to_armv7m(target))) {
+ uint32_t pc;
+
+ /* resume execution, this will be pc+2 to skip over the
+ * bkpt instruction */
+ pc = buf_get_u32(arm->pc->value, 0, 32);
+ buf_set_u32(arm->core_cache->reg_list[15].value, 0, 32, pc + 2);
+ arm->core_cache->reg_list[15].dirty = 1;
+ }
+}
+
+#define GDB_FILEIO_O_RDONLY 0x0
+#define GDB_FILEIO_O_WRONLY 0x1
+#define GDB_FILEIO_O_RDWR 0x2
+#define GDB_FILEIO_O_APPEND 0x8
+#define GDB_FILEIO_O_CREAT 0x200
+#define GDB_FILEIO_O_TRUNC 0x400
+#define GDB_FILEIO_O_EXCL 0x800
+
+#define GDB_FILEIO_S_IFREG 0100000
+#define GDB_FILEIO_S_IFDIR 040000
+#define GDB_FILEIO_S_IRUSR 0400
+#define GDB_FILEIO_S_IWUSR 0200
+#define GDB_FILEIO_S_IXUSR 0100
+#define GDB_FILEIO_S_IRGRP 040
+#define GDB_FILEIO_S_IWGRP 020
+#define GDB_FILEIO_S_IXGRP 010
+#define GDB_FILEIO_S_IROTH 04
+#define GDB_FILEIO_S_IWOTH 02
+#define GDB_FILEIO_S_IXOTH 01
+
+int arm_get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *fileio_info)
{
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.
- */
+ int retval;
+
+ if (fileio_info == NULL) {
+ LOG_ERROR("Target has not initial file-I/O data structure");
+ return ERROR_FAIL;
+ }
+
+ if (!arm->hit_syscall)
+ return ERROR_FAIL;
+
+ arm->active_syscall_id = r0;
+
+ LOG_DEBUG("hit syscall ID: 0x%x", r0);
+
+ /* free previous identifier storage */
+ if (NULL != fileio_info->identifier) {
+ free(fileio_info->identifier);
+ fileio_info->identifier = NULL;
+ }
+
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;
+
+ /* pointer to path string */
+ fileio_info->param_1 = target_buffer_get_u32(target, params+0);
+ /* length of path string */
+ fileio_info->param_2 = target_buffer_get_u32(target, params+8) + 1;
+ /* flags */
+ fileio_info->param_3 = target_buffer_get_u32(target, params+4);
+ /* mode */
+ fileio_info->param_4 = 0;
+
+ if (fileio_info->param_2 == 4) {
+ uint8_t fn[4];
+ int fd = -1;
+
+ retval = target_read_memory(target, fileio_info->param_1, 1, 4, fn);
+ if (retval != ERROR_OK)
+ return retval;
+
+ if (fn[0] == ':' && fn[1] == 't' && fn[2] == 't' && fn[3] == '\0') {
+ if (fileio_info->param_3 == 0)
+ fd = 0;
+ else if (fileio_info->param_3 == 4)
+ fd = 1;
+ else if (fileio_info->param_3 == 8)
+ fd = 2;
+ }
+
+ if (fd >= 0) {
+ buf_set_u32(arm->core_cache->reg_list[0].value, 0, 32, fd);
+ arm->core_cache->reg_list[0].dirty = 1;
+
+ fileio_info->identifier = (char *)malloc(8);
+ sprintf(fileio_info->identifier, "open012");
+ break;
}
}
+
+ uint32_t flags = fileio_info->param_3;
+ fileio_info->param_3 = 0;
+ if (flags & 2)
+ fileio_info->param_3 |= GDB_FILEIO_O_RDWR;
+ if (flags & 4)
+ fileio_info->param_3 |= GDB_FILEIO_O_CREAT | GDB_FILEIO_O_TRUNC;
+ if ((flags & 4) && !(flags & 2))
+ fileio_info->param_3 |= GDB_FILEIO_O_WRONLY;
+ if (flags & 8)
+ fileio_info->param_3 |= GDB_FILEIO_O_APPEND;
+
+ /* if O_CREAT, hard code mode to S_IRUSR | S_IWUSR */
+ if (fileio_info->param_3 & GDB_FILEIO_O_CREAT)
+ fileio_info->param_4 = GDB_FILEIO_S_IRUSR | GDB_FILEIO_S_IWUSR;
+
+ fileio_info->identifier = malloc(5);
+ sprintf(fileio_info->identifier, "open");
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;
- }
+
+ /* fd */
+ fileio_info->param_1 = target_buffer_get_u32(target, params+0);
+
+ fileio_info->identifier = malloc(6);
+ sprintf(fileio_info->identifier, "close");
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;
- }
+ /* fd, use stdout */
+ fileio_info->param_1 = 1;
+ /* pointer to buffer */
+ fileio_info->param_2 = r1;
+ /* count */
+ fileio_info->param_3 = 1;
+
+ arm->semihosting_result = fileio_info->param_3;
+
+ fileio_info->identifier = malloc(6);
+ sprintf(fileio_info->identifier, "write");
break;
case 0x04: /* SYS_WRITE0 */
+ /* fd, use stdout */
+ fileio_info->param_1 = 1;
+ /* pointer to buffer */
+ fileio_info->param_2 = r1;
+ /* count */
do {
- unsigned char c;
- retval = target_read_memory(target, r1++, 1, 1, &c);
+ retval = target_read_memory(target, r1, 1, 1, params);
if (retval != ERROR_OK)
return retval;
- if (!c)
- break;
- putchar(c);
- } while (1);
- result = 0;
+ r1++;
+ } while (params[0]);
+ fileio_info->param_3 = r1 - fileio_info->param_2;
+
+ arm->semihosting_result = fileio_info->param_3;
+
+ fileio_info->identifier = malloc(6);
+ sprintf(fileio_info->identifier, "write");
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);
- }
- }
+
+ /* fd */
+ fileio_info->param_1 = target_buffer_get_u32(target, params+0);
+ /* pointer to buffer */
+ fileio_info->param_2 = target_buffer_get_u32(target, params+4);
+ /* count */
+ fileio_info->param_3 = target_buffer_get_u32(target, params+8);
+
+ arm->semihosting_result = fileio_info->param_3;
+
+ fileio_info->identifier = malloc(6);
+ sprintf(fileio_info->identifier, "write");
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;
+ /* fd */
+ fileio_info->param_1 = target_buffer_get_u32(target, params+0);
+ /* pointer to buffer */
+ fileio_info->param_2 = target_buffer_get_u32(target, params+4);
+ /* count */
+ fileio_info->param_3 = target_buffer_get_u32(target, params+8);
- 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);
+ arm->semihosting_result = fileio_info->param_3;
+
+ fileio_info->identifier = malloc(5);
+ sprintf(fileio_info->identifier, "read");
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));
+
+ /* fd */
+ fileio_info->param_1 = target_buffer_get_u32(target, params+0);
+
+ fileio_info->identifier = (char *)malloc(7);
+ sprintf(fileio_info->identifier, "isatty");
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;
- }
+
+ /* fd */
+ fileio_info->param_1 = target_buffer_get_u32(target, params+0);
+ /* offset */
+ fileio_info->param_2 = target_buffer_get_u32(target, params+4);
+ /* flag */
+ fileio_info->param_3 = SEEK_SET;
+
+ fileio_info->identifier = (char *)malloc(6);
+ sprintf(fileio_info->identifier, "lseek");
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;
- }
+
+ /* fd */
+ fileio_info->param_1 = target_buffer_get_u32(target, params+0);
+ /* buf */
+ /* We use the stack for a temporary buffer. */
+ arm_semihosting_work_addr = buf_get_u32(arm_reg_current(arm, ARM_SP)->value, 0, 32);
+ arm_semihosting_work_addr -= ARM_SEMIHOSTING_TEMP_BUFFER_SIZE;
+ retval = target_read_memory(target, arm_semihosting_work_addr, 1,
+ ARM_SEMIHOSTING_TEMP_BUFFER_SIZE, arm_semihosting_temp_buffer);
+ if (retval != ERROR_OK)
+ return retval;
+
+ fileio_info->param_2 = arm_semihosting_work_addr;
+ fileio_info->identifier = (char *)malloc(6);
+ sprintf(fileio_info->identifier, "fstat");
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;
- }
- }
+
+ /* pointer to path string */
+ fileio_info->param_1 = target_buffer_get_u32(target, params+0);
+ /* length of path string */
+ fileio_info->param_2 = target_buffer_get_u32(target, params+4) + 1;
+
+ fileio_info->identifier = (char *)malloc(7);
+ sprintf(fileio_info->identifier, "unlink");
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;
- }
- }
+
+ /* pointer to old path string */
+ fileio_info->param_1 = target_buffer_get_u32(target, params+0);
+ /* length of old path string */
+ fileio_info->param_2 = target_buffer_get_u32(target, params+4) + 1;
+ /* pointer to new path string */
+ fileio_info->param_3 = target_buffer_get_u32(target, params+8);
+ /* length of new path string */
+ fileio_info->param_4 = target_buffer_get_u32(target, params+12) + 1;
+
+ fileio_info->identifier = (char *)malloc(7);
+ sprintf(fileio_info->identifier, "rename");
break;
case 0x11: /* SYS_TIME */
- result = time(NULL);
+ /* tv */
+ /* We use the stack for a temporary buffer. */
+ arm_semihosting_work_addr = buf_get_u32(arm_reg_current(arm, ARM_SP)->value, 0, 32);
+ arm_semihosting_work_addr -= ARM_SEMIHOSTING_TEMP_BUFFER_SIZE;
+ retval = target_read_memory(target, arm_semihosting_work_addr, 1,
+ ARM_SEMIHOSTING_TEMP_BUFFER_SIZE, arm_semihosting_temp_buffer);
+ if (retval != ERROR_OK)
+ return retval;
+ fileio_info->param_1 = arm_semihosting_work_addr;
+
+ /* tz */
+ fileio_info->param_2 = 0;
+
+ fileio_info->identifier = (char *)malloc(13);
+ sprintf(fileio_info->identifier, "gettimeofday");
+ break;
+
+ case 0x12: /* SYS_SYSTEM */
+ retval = target_read_memory(target, r1, 4, 2, params);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* pointer to the command string */
+ fileio_info->param_1 = target_buffer_get_u32(target, params+0);
+ /* length of the command string */
+ fileio_info->param_2 = target_buffer_get_u32(target, params+4) + 1;
+
+ fileio_info->identifier = (char *)malloc(7);
+ sprintf(fileio_info->identifier, "system");
break;
case 0x13: /* SYS_ERRNO */
- result = arm->semihosting_errno;
+ buf_set_u32(arm->core_cache->reg_list[0].value, 0, 32, arm->semihosting_errno);
+ arm->core_cache->reg_list[0].dirty = 1;
+
+ fileio_info->identifier = (char *)malloc(6);
+ sprintf(fileio_info->identifier, "errno");
break;
case 0x15: /* SYS_GET_CMDLINE */
@@ -321,13 +532,17 @@ static int do_semihosting(struct target *target)
char *arg = "foobar";
uint32_t s = strlen(arg) + 1;
if (l < s)
- result = -1;
- else {
- retval = target_write_buffer(target, a, s, (uint8_t *)arg);
- if (retval != ERROR_OK)
- return retval;
- result = 0;
- }
+ return ERROR_FAIL;
+
+ retval = target_write_buffer(target, a, s, (void *)arg);
+ if (retval != ERROR_OK)
+ return retval;
+
+ buf_set_u32(arm->core_cache->reg_list[0].value, 0, 32, 0);
+ arm->core_cache->reg_list[0].dirty = 1;
+
+ fileio_info->identifier = (char *)malloc(16);
+ sprintf(fileio_info->identifier, "get_commandline");
}
break;
@@ -337,22 +552,38 @@ static int do_semihosting(struct target *target)
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);
+ target_buffer_set_u32(target, params, arm->heap_base);
+ target_buffer_set_u32(target, params + 4, arm->heap_limit);
+ target_buffer_set_u32(target, params + 8, arm->stack_base);
+ target_buffer_set_u32(target, params + 12, arm->stack_limit);
retval = target_write_memory(target, a, 4, 4, params);
if (retval != ERROR_OK)
return retval;
- result = 0;
+
+ buf_set_u32(arm->core_cache->reg_list[0].value, 0, 32, 0);
+ arm->core_cache->reg_list[0].dirty = 1;
+
+ fileio_info->identifier = (char *)malloc(9);
+ sprintf(fileio_info->identifier, "heapinfo");
}
break;
case 0x18: /* angel_SWIreason_ReportException */
+ fprintf(stderr, "semihosting: exception %#x\n", (unsigned) r1);
+
switch (r1) {
case 0x20026: /* ADP_Stopped_ApplicationExit */
- fprintf(stderr, "semihosting: *** application exited ***\n");
+ /* exit status is not passed down */
+ target->fileio_info->param_1 = 0;
+ fileio_info->identifier = (char *)malloc(5);
+ sprintf(fileio_info->identifier, "exit");
+ return ERROR_OK;
+
+ case 0x20001: /* ADP_Stopped_UndefinedInstr */
+ target->fileio_info->param_1 = 4 /* SIGILL */;
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 */
@@ -362,197 +593,101 @@ static int do_semihosting(struct target *target)
case 0x20020: /* ADP_Stopped_BreakPoint */
case 0x20021: /* ADP_Stopped_WatchPoint */
case 0x20022: /* ADP_Stopped_StepComplete */
- case 0x20023: /* ADP_Stopped_RunTimeErrorUnknown */
+ case 0x20023: /* ADP_Stopped_RunTimeError */
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);
+ /* TODO find better signal for each cause */
+ target->fileio_info->param_1 = 6 /* SIGABRT */;
+ break;
}
- return target_call_event_callbacks(target, TARGET_EVENT_HALTED);
- case 0x12: /* SYS_SYSTEM */
- /* Provide SYS_SYSTEM functionality. Uses the
- * libc system command, there may be a reason *NOT*
- * to use this, but as I can't think of one, I
- * implemented it this way.
- */
- retval = target_read_memory(target, r1, 4, 2, params);
- if (retval != ERROR_OK)
- return retval;
- else {
- uint32_t len = target_buffer_get_u32(target, params+4);
- uint32_t c_ptr = target_buffer_get_u32(target, params);
- uint8_t cmd[256];
- if (len > 255) {
- result = -1;
- arm->semihosting_errno = EINVAL;
- } else {
- memset(cmd, 0x0, 256);
- retval = target_read_memory(target, c_ptr, 1, len, cmd);
- if (retval != ERROR_OK)
- return retval;
- else
- result = system((const char *)cmd);
- }
- }
+ fileio_info->identifier = (char *)malloc(7);
+ sprintf(fileio_info->identifier, "signal");
break;
+
+ case 0x07: /* SYS_READC */
case 0x0d: /* SYS_TMPNAM */
case 0x10: /* SYS_CLOCK */
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;
+ fileio_info->identifier = (char *)malloc(8);
+ sprintf(fileio_info->identifier, "unknown");
+ break;
}
- return target_resume(target, 1, 0, 0, 0);
+ return ERROR_OK;
}
-/**
- * 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)
+int arm_gdb_fileio_end(struct target *target, int retcode, int fileio_errno, bool ctrl_c)
{
- struct arm *arm = target_to_arm(target);
- uint32_t pc, lr, spsr;
- struct reg *r;
+ uint32_t result;
+ int retval;
- if (!arm->is_semihosting)
- return 0;
+ LOG_DEBUG("syscall return code: 0x%x, errno: 0x%x, ctrl_c: %s",
+ retcode, fileio_errno, ctrl_c ? "true" : "false");
- 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);
+ struct arm *arm = target_to_arm(target);
- /* 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;
- }
+ switch (arm->active_syscall_id) {
+ case 0x05: /* SYS_WRITE */
+ case 0x06: /* SYS_READ */
+ if (retcode >= 0)
+ result = arm->semihosting_result - retcode;
+ else
+ result = arm->semihosting_result;
+ break;
+ case 0x0c: /* SYS_FLEN */
+ case 0x11: /* SYS_TIME */
+ result = arm->semihosting_result;
+ retval = target_write_memory(target, arm_semihosting_work_addr, 1,
+ ARM_SEMIHOSTING_TEMP_BUFFER_SIZE, arm_semihosting_temp_buffer);
+ if (retval != ERROR_OK)
+ return retval;
+ break;
+ default:
+ result = retcode;
+ }
- spsr = buf_get_u32(arm->spsr->value, 0, 32);
+ buf_set_u32(arm->core_cache->reg_list[0].value, 0, 32, result);
+ arm->core_cache->reg_list[0].dirty = 1;
- /* check instruction that triggered this trap */
- if (spsr & (1 << 5)) {
- /* was in Thumb (or ThumbEE) mode */
- uint8_t insn_buf[2];
- uint16_t insn;
+ arm->semihosting_errno = fileio_errno;
+ arm->semihosting_ctrl_c = ctrl_c;
+ arm->active_syscall_id = 0;
- *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);
+ return ERROR_OK;
+}
- /* 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);
+int arm_gdb_fileio_pre_write_buffer(struct target *target, uint32_t address,
+ uint32_t size, const uint8_t *buffer)
+{
+ struct arm *arm = target_to_arm(target);
- /* SVC 0x123456 */
- if (insn != 0xEF123456)
- return 0;
+ if (arm->hit_syscall) {
+ if (arm->active_syscall_id == 0x0c /* SYS_FLEN */) {
+ /* If doing GDB file-I/O, target should convert 'struct stat'
+ from gdb-format to target-format.
+ And we are only interested in st_size. */
+ /* st_size 4 */
+ arm->semihosting_result = buffer[35] | (buffer[34] << 8) | (buffer[33] << 16) | (buffer[32] << 24);
+
+ return ERROR_OK;
+ } else if (arm->active_syscall_id == 0x11 /* SYS_TIME */) {
+ /* If doing GDB file-I/O, target should convert 'struct timeval'
+ from gdb-format to target-format.
+ And we are only interested in tv_sec. */
+ arm->semihosting_result = buffer[3] | (buffer[2] << 8) | (buffer[1] << 16) | (buffer[0] << 24);
+
+ return ERROR_OK;
}
- } 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;
+ return ERROR_FAIL;
}
diff --git a/src/target/arm_semihosting.h b/src/target/arm_semihosting.h
index 58b3432..db7cb13 100644
--- a/src/target/arm_semihosting.h
+++ b/src/target/arm_semihosting.h
@@ -21,6 +21,11 @@
#ifndef ARM_SEMIHOSTING_H
#define ARM_SEMIHOSTING_H
-int arm_semihosting(struct target *target, int *retval);
+int arm_semihosting(struct target *target);
+void arm_semihosting_step_over_svc(struct target *target);
+void arm_semihosting_step_over_bkpt(struct target *target);
+int arm_get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *fileio_info);
+int arm_gdb_fileio_end(struct target *target, int retcode, int fileio_errno, bool ctrl_c);
+int arm_gdb_fileio_pre_write_buffer(struct target *target, uint32_t address, uint32_t size, const uint8_t *buffer);
#endif
diff --git a/src/target/armv4_5.c b/src/target/armv4_5.c
index e75fe99..05c8d30 100644
--- a/src/target/armv4_5.c
+++ b/src/target/armv4_5.c
@@ -616,7 +616,10 @@ struct reg_cache *arm_build_reg_cache(struct target *target, struct arm *arm)
reg_list[i].exist = true;
/* This really depends on the calling convention in use */
- reg_list[i].caller_save = false;
+ if (reg_list[i].number < 16)
+ reg_list[i].caller_save = true;
+ else
+ reg_list[i].caller_save = false;
/* Registers data type, as used by GDB target description */
reg_list[i].reg_data_type = malloc(sizeof(struct reg_data_type));
@@ -1026,6 +1029,7 @@ COMMAND_HANDLER(handle_arm_semihosting_command)
if (CMD_ARGC > 0) {
int semihosting;
+ unsigned int i;
COMMAND_PARSE_ENABLE(CMD_ARGV[0], semihosting);
@@ -1041,6 +1045,21 @@ COMMAND_HANDLER(handle_arm_semihosting_command)
/* FIXME never let that "catch" be dropped! */
arm->is_semihosting = semihosting;
+
+ arm->heap_base = arm->heap_limit = 0;
+ arm->stack_base = arm->stack_limit = 0;
+ for (i = 1; i < CMD_ARGC; i++) {
+ if (strncasecmp ("heap_base=", CMD_ARGV[i], 10) == 0)
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[i] + 10, arm->heap_base);
+ else if (strncasecmp ("heap_limit=", CMD_ARGV[i], 11) == 0)
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[i] + 11, arm->heap_limit);
+ else if (strncasecmp ("stack_base=", CMD_ARGV[i], 11) == 0)
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[i] + 11, arm->stack_base);
+ else if (strncasecmp ("stack_limit=", CMD_ARGV[i], 12) == 0)
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[i] + 12, arm->stack_limit);
+ else
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
}
command_print(CMD_CTX, "semihosting is %s",
diff --git a/src/target/armv7a.c b/src/target/armv7a.c
index 170cfcc..7816370 100644
--- a/src/target/armv7a.c
+++ b/src/target/armv7a.c
@@ -208,7 +208,7 @@ int armv7a_mmu_translate_va(struct target *target, uint32_t va, uint32_t *val)
}
retval = dpm->prepare(dpm);
if (retval != ERROR_OK)
- goto done;
+ return retval;
/* MRC p15,0,<Rt>,c2,c0,ttb */
retval = dpm->instr_read_data_r0(dpm,
@@ -226,19 +226,19 @@ int armv7a_mmu_translate_va(struct target *target, uint32_t va, uint32_t *val)
/* 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) {
+ if ((first_lvl_descriptor & 0x3) == 0
+ || (first_lvl_descriptor & 0x3) == 3) {
LOG_ERROR("Address translation failure");
return ERROR_TARGET_TRANSLATION_FAULT;
}
-
if ((first_lvl_descriptor & 0x40002) == 2) {
/* section descriptor */
*val = (first_lvl_descriptor & 0xfff00000) | (va & 0x000fffff);
return ERROR_OK;
} else if ((first_lvl_descriptor & 0x40002) == 0x40002) {
/* supersection descriptor */
- if (first_lvl_descriptor & 0x00f001e0) {
+ if ((first_lvl_descriptor & 0x00f001e0) != 0) {
LOG_ERROR("Physical address does not fit into 32 bits");
return ERROR_TARGET_TRANSLATION_FAULT;
}
@@ -272,9 +272,6 @@ int armv7a_mmu_translate_va(struct target *target, uint32_t va, uint32_t *val)
}
return ERROR_OK;
-
-done:
- return retval;
}
/* V7 method VA TO PA */
@@ -453,6 +450,168 @@ static int armv7a_flush_all_data(struct target *target)
return retval;
}
+int armv7a_invalidate_instruction_cache(struct target *target,
+ uint32_t address, uint32_t size, uint32_t count)
+{
+ struct armv7a_common *armv7a = target_to_armv7a(target);
+ struct arm_dpm *dpm = armv7a->arm.dpm;
+ uint32_t cacheline_size = armv7a->armv7a_mmu.armv7a_cache.i_size.linelen;
+ int retval;
+
+ if (target->state != TARGET_HALTED) {
+ LOG_ERROR("target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ /* check that cache data is on at target halt */
+ if (!armv7a->armv7a_mmu.armv7a_cache.i_cache_enabled) {
+ LOG_DEBUG("instruction cache invalidation not performed : cache not on at target halt");
+ return ERROR_OK;
+ }
+
+ retval = dpm->prepare(dpm);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* ICIMVAU - Invalidate instruction cache by VA to PoU
+ * MCR p15, 0, r0, c7, c5, 1
+ */
+ for (uint32_t cacheline = address & ~(cacheline_size - 1);
+ cacheline < address + size * count;
+ cacheline += cacheline_size) {
+ retval = dpm->instr_write_data_r0(dpm,
+ ARMV4_5_MCR(15, 0, 0, 7, 5, 1), cacheline);
+ if (retval != ERROR_OK)
+ return retval;
+ }
+
+ /* (void) */ dpm->finish(dpm);
+
+ return retval;
+}
+
+int armv7a_clean_data_cache(struct target *target,
+ uint32_t address, uint32_t size, uint32_t count)
+{
+ struct armv7a_common *armv7a = target_to_armv7a(target);
+ struct arm_dpm *dpm = armv7a->arm.dpm;
+ uint32_t cacheline_size = armv7a->armv7a_mmu.armv7a_cache.d_u_size.linelen;
+ int retval;
+
+ if (target->state != TARGET_HALTED) {
+ LOG_ERROR("target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ /* check that cache is on at target halt */
+ if (!armv7a->armv7a_mmu.armv7a_cache.d_u_cache_enabled) {
+ LOG_DEBUG("data/unified cache clean not performed : cache not on at target halt");
+ return ERROR_OK;
+ }
+
+ retval = dpm->prepare(dpm);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* DCCMVAC - Clean data cache line to PoC by VA
+ * MCR p15, 0, r0, c7, c10, 1
+ */
+ for (uint32_t cacheline = address & ~(cacheline_size - 1);
+ cacheline < address + size * count;
+ cacheline += cacheline_size) {
+ retval = dpm->instr_write_data_r0(dpm,
+ ARMV4_5_MCR(15, 0, 0, 7, 10, 1), cacheline);
+ if (retval != ERROR_OK)
+ return retval;
+ }
+
+ /* (void) */ dpm->finish(dpm);
+
+ return retval;
+}
+
+int armv7a_invalidate_data_cache(struct target *target,
+ uint32_t address, uint32_t size, uint32_t count)
+{
+ struct armv7a_common *armv7a = target_to_armv7a(target);
+ struct arm_dpm *dpm = armv7a->arm.dpm;
+ uint32_t cacheline_size = armv7a->armv7a_mmu.armv7a_cache.d_u_size.linelen;
+ int retval;
+
+ if (target->state != TARGET_HALTED) {
+ LOG_ERROR("target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ /* check that cache is on at target halt */
+ if (!armv7a->armv7a_mmu.armv7a_cache.d_u_cache_enabled) {
+ LOG_DEBUG("data/unified cache invalidation not performed : cache not on at target halt");
+ return ERROR_OK;
+ }
+
+ retval = dpm->prepare(dpm);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* DCIMVAC - Invalidate data cache line by VA to PoC
+ * MCR p15, 0, r0, c7, c6, 1
+ */
+ for (uint32_t cacheline = address & ~(cacheline_size - 1);
+ cacheline < address + size * count;
+ cacheline += cacheline_size) {
+ 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;
+}
+
+int armv7a_clean_and_invalidate_data_cache(struct target *target,
+ uint32_t address, uint32_t size, uint32_t count)
+{
+ struct armv7a_common *armv7a = target_to_armv7a(target);
+ struct arm_dpm *dpm = armv7a->arm.dpm;
+ uint32_t cacheline_size = armv7a->armv7a_mmu.armv7a_cache.d_u_size.linelen;
+ int retval;
+
+ if (target->state != TARGET_HALTED) {
+ LOG_ERROR("target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ /* check that cache is on at target halt */
+ if (!armv7a->armv7a_mmu.armv7a_cache.d_u_cache_enabled) {
+ LOG_DEBUG("data/unified cache clean and invalidation not performed : cache not on at target halt");
+ return ERROR_OK;
+ }
+
+ retval = dpm->prepare(dpm);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* DCCIMVAC - Clean and invalidate data cache line by VA to PoC
+ * MCR p15, 0, r0, c7, c14, 1
+ */
+ for (uint32_t cacheline = address & ~(cacheline_size - 1);
+ cacheline < address + size * count;
+ cacheline += cacheline_size) {
+ retval = dpm->instr_write_data_r0(dpm,
+ ARMV4_5_MCR(15, 0, 0, 7, 14, 1),
+ cacheline);
+ if (retval != ERROR_OK)
+ return retval;
+ }
+
+ /* (void) */ dpm->finish(dpm);
+
+ return retval;
+
+}
+
/* L2 is not specific to armv7a a specific file is needed */
static int armv7a_l2x_flush_all_data(struct target *target)
{
@@ -465,14 +624,65 @@ static int armv7a_l2x_flush_all_data(struct target *target)
uint32_t base = l2x_cache->base;
uint32_t l2_way = l2x_cache->way;
uint32_t l2_way_val = (1 << l2_way) - 1;
+ uint8_t buf[4];
+
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);
+
+ target_buffer_set_u32(target, buf, l2_way_val);
+ retval = target->type->write_phys_memory(target, base + L2X0_CLEAN_INV_WAY, 4, 1, buf);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* poll cache maintenance register until operation is complete. */
+ while (l2_way_val & ((1 << l2_way) - 1)) {
+ retval = target->type->read_phys_memory(target, base + L2X0_CLEAN_INV_WAY, 4, 1, buf);
+ if (retval != ERROR_OK)
+ return retval;
+ l2_way_val = target_buffer_get_u32(target, buf);
+ }
+
+ return retval;
+}
+
+int armv7a_l2x_invalidate_all_data(struct target *target)
+{
+
+#define L2X0_CONTROL 0x100
+#define L2X0_INV_WAY 0x77C
+ 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;
+ uint32_t l2_control;
+ uint8_t buf[4];
+
+ retval = target->type->read_phys_memory(target, base + L2X0_CONTROL, 4, 1, buf);
+ if (retval != ERROR_OK)
+ return retval;
+ l2_control = target_buffer_get_u32(target, buf);
+
+ /* if L2 cache is disabled, do nothing */
+ if ((l2_control & 0x1) == 0)
+ return ERROR_OK;
+
+ target_buffer_set_u32(target, buf, l2_way_val);
+ retval = target->type->write_phys_memory(target, base + L2X0_INV_WAY, 4, 1, buf);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* poll cache maintenance register until operation is complete. */
+ while (l2_way_val & ((1 << l2_way) - 1)) {
+ retval = target->type->read_phys_memory(target, base + L2X0_INV_WAY, 4, 1, buf);
+ if (retval != ERROR_OK)
+ return retval;
+ l2_way_val = target_buffer_get_u32(target, buf);
+ }
+
return retval;
}
@@ -833,7 +1043,7 @@ static const struct command_registration l2_cache_commands[] = {
{
.name = "l2x",
.handler = handle_cache_l2x,
- .mode = COMMAND_EXEC,
+ .mode = COMMAND_ANY,
.help = "configure l2x cache "
"",
.usage = "[base_addr] [number_of_way]",
@@ -845,7 +1055,7 @@ static const struct command_registration l2_cache_commands[] = {
const struct command_registration l2x_cache_command_handlers[] = {
{
.name = "cache_config",
- .mode = COMMAND_EXEC,
+ .mode = COMMAND_ANY,
.help = "cache configuration for a target",
.usage = "",
.chain = l2_cache_commands,
diff --git a/src/target/armv7a.h b/src/target/armv7a.h
index 4341aca..3fb1fc2 100644
--- a/src/target/armv7a.h
+++ b/src/target/armv7a.h
@@ -26,11 +26,6 @@
#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*/
@@ -127,6 +122,10 @@ target_to_armv7a(struct target *target)
return container_of(target->arch_info, struct armv7a_common, arm);
}
+static inline bool is_armv7a(struct armv7a_common *armv7a)
+{
+ return armv7a->common_magic == ARMV7_COMMON_MAGIC;
+}
/* register offsets from armv7a.debug_base */
/* See ARMv7a arch spec section C10.2 */
@@ -150,7 +149,8 @@ target_to_armv7a(struct target *target)
#define CPUDBG_BCR_BASE 0x140
#define CPUDBG_WVR_BASE 0x180
#define CPUDBG_WCR_BASE 0x1C0
-#define CPUDBG_VCR 0x01C
+#define CPUDBG_VCR 0x01C
+#define VCR_SVC 0x4
/* See ARMv7a arch spec section C10.6 */
#define CPUDBG_OSLAR 0x300
@@ -171,6 +171,17 @@ 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_invalidate_instruction_cache(struct target *target,
+ uint32_t address, uint32_t size, uint32_t count);
+int armv7a_clean_data_cache(struct target *target,
+ uint32_t address, uint32_t size, uint32_t count);
+int armv7a_invalidate_data_cache(struct target *target,
+ uint32_t address, uint32_t size, uint32_t count);
+int armv7a_clean_and_invalidate_data_cache(struct target *target,
+ uint32_t address, uint32_t size, uint32_t count);
+
+int armv7a_l2x_invalidate_all_data(struct target *target);
+
int armv7a_handle_cache_info_command(struct command_context *cmd_ctx,
struct armv7a_cache_common *armv7a_cache);
diff --git a/src/target/blackfin.c b/src/target/blackfin.c
new file mode 100644
index 0000000..33e1de5
--- /dev/null
+++ b/src/target/blackfin.c
@@ -0,0 +1,1445 @@
+/***************************************************************************
+ * Copyright (C) 2011 by Analog Devices, Inc. *
+ * Written by Jie Zhang <***@analog.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 "helper/log.h"
+#include "helper/types.h"
+#include "helper/binarybuffer.h"
+
+#include "breakpoints.h"
+#include "register.h"
+#include "target.h"
+#include "target_type.h"
+#include "blackfin.h"
+#include "blackfin_jtag.h"
+#include "blackfin_mem.h"
+#include "blackfin_memory_map.h"
+#include "blackfin_config.h"
+
+#include "jtag/jtag.h"
+#include "jtag/drivers/ft2232.h"
+
+#undef UPSTREAM_GDB_SUPPORT
+
+/* Core Registers
+ BFIN_R0_REGNUM = 0,
+ BFIN_R1_REGNUM,
+ BFIN_R2_REGNUM,
+ BFIN_R3_REGNUM,
+ BFIN_R4_REGNUM,
+ BFIN_R5_REGNUM,
+ BFIN_R6_REGNUM,
+ BFIN_R7_REGNUM,
+ BFIN_P0_REGNUM,
+ BFIN_P1_REGNUM,
+ BFIN_P2_REGNUM,
+ BFIN_P3_REGNUM,
+ BFIN_P4_REGNUM,
+ BFIN_P5_REGNUM,
+ BFIN_SP_REGNUM,
+ BFIN_FP_REGNUM,
+ BFIN_I0_REGNUM,
+ BFIN_I1_REGNUM,
+ BFIN_I2_REGNUM,
+ BFIN_I3_REGNUM,
+ BFIN_M0_REGNUM,
+ BFIN_M1_REGNUM,
+ BFIN_M2_REGNUM,
+ BFIN_M3_REGNUM,
+ BFIN_B0_REGNUM,
+ BFIN_B1_REGNUM,
+ BFIN_B2_REGNUM,
+ BFIN_B3_REGNUM,
+ BFIN_L0_REGNUM,
+ BFIN_L1_REGNUM,
+ BFIN_L2_REGNUM,
+ BFIN_L3_REGNUM,
+ BFIN_A0_DOT_X_REGNUM,
+ BFIN_AO_DOT_W_REGNUM,
+ BFIN_A1_DOT_X_REGNUM,
+ BFIN_A1_DOT_W_REGNUM,
+ BFIN_ASTAT_REGNUM,
+ BFIN_RETS_REGNUM,
+ BFIN_LC0_REGNUM,
+ BFIN_LT0_REGNUM,
+ BFIN_LB0_REGNUM,
+ BFIN_LC1_REGNUM,
+ BFIN_LT1_REGNUM,
+ BFIN_LB1_REGNUM,
+ BFIN_CYCLES_REGNUM,
+ BFIN_CYCLES2_REGNUM,
+ BFIN_USP_REGNUM,
+ BFIN_SEQSTAT_REGNUM,
+ BFIN_SYSCFG_REGNUM,
+ BFIN_RETI_REGNUM,
+ BFIN_RETX_REGNUM,
+ BFIN_RETN_REGNUM,
+ BFIN_RETE_REGNUM,
+*/
+
+struct blackfin_core_reg
+{
+ uint32_t num;
+ struct target *target;
+ /* can we remove the following line. */
+ struct blackfin_common *blackfin_common;
+};
+
+/* This enum was copied from GDB. */
+enum gdb_regnum
+{
+ /* Core Registers */
+ BFIN_R0_REGNUM = 0,
+ BFIN_R1_REGNUM,
+ BFIN_R2_REGNUM,
+ BFIN_R3_REGNUM,
+ BFIN_R4_REGNUM,
+ BFIN_R5_REGNUM,
+ BFIN_R6_REGNUM,
+ BFIN_R7_REGNUM,
+ BFIN_P0_REGNUM,
+ BFIN_P1_REGNUM,
+ BFIN_P2_REGNUM,
+ BFIN_P3_REGNUM,
+ BFIN_P4_REGNUM,
+ BFIN_P5_REGNUM,
+ BFIN_SP_REGNUM,
+ BFIN_FP_REGNUM,
+ BFIN_I0_REGNUM,
+ BFIN_I1_REGNUM,
+ BFIN_I2_REGNUM,
+ BFIN_I3_REGNUM,
+ BFIN_M0_REGNUM,
+ BFIN_M1_REGNUM,
+ BFIN_M2_REGNUM,
+ BFIN_M3_REGNUM,
+ BFIN_B0_REGNUM,
+ BFIN_B1_REGNUM,
+ BFIN_B2_REGNUM,
+ BFIN_B3_REGNUM,
+ BFIN_L0_REGNUM,
+ BFIN_L1_REGNUM,
+ BFIN_L2_REGNUM,
+ BFIN_L3_REGNUM,
+ BFIN_A0_DOT_X_REGNUM,
+ BFIN_AO_DOT_W_REGNUM,
+ BFIN_A1_DOT_X_REGNUM,
+ BFIN_A1_DOT_W_REGNUM,
+ BFIN_ASTAT_REGNUM,
+ BFIN_RETS_REGNUM,
+ BFIN_LC0_REGNUM,
+ BFIN_LT0_REGNUM,
+ BFIN_LB0_REGNUM,
+ BFIN_LC1_REGNUM,
+ BFIN_LT1_REGNUM,
+ BFIN_LB1_REGNUM,
+ BFIN_CYCLES_REGNUM,
+ BFIN_CYCLES2_REGNUM,
+ BFIN_USP_REGNUM,
+ BFIN_SEQSTAT_REGNUM,
+ BFIN_SYSCFG_REGNUM,
+ BFIN_RETI_REGNUM,
+ BFIN_RETX_REGNUM,
+ BFIN_RETN_REGNUM,
+ BFIN_RETE_REGNUM,
+
+ /* Pseudo Registers */
+ BFIN_PC_REGNUM,
+#ifndef UPSTREAM_GDB_SUPPORT
+ BFIN_CC_REGNUM,
+ BFIN_TEXT_ADDR, /* Address of .text section. */
+ BFIN_TEXT_END_ADDR, /* Address of the end of .text section. */
+ BFIN_DATA_ADDR, /* Address of .data section. */
+
+ BFIN_FDPIC_EXEC_REGNUM,
+ BFIN_FDPIC_INTERP_REGNUM,
+
+ /* MMRs */
+ BFIN_IPEND_REGNUM,
+#endif
+
+ /* LAST ENTRY SHOULD NOT BE CHANGED. */
+ BFIN_NUM_REGS /* The number of all registers. */
+};
+
+/* Map gdb register number to core register number. */
+static enum core_regnum map_gdb_core[] = {
+ /* Core Registers */
+ REG_R0, REG_R1, REG_R2, REG_R3, REG_R4, REG_R5, REG_R6, REG_R7,
+ REG_P0, REG_P1, REG_P2, REG_P3, REG_P4, REG_P5, REG_SP, REG_FP,
+ REG_I0, REG_I1, REG_I2, REG_I3, REG_M0, REG_M1, REG_M2, REG_M3,
+ REG_B0, REG_B1, REG_B2, REG_B3, REG_L0, REG_L1, REG_L2, REG_L3,
+ REG_A0x, REG_A0w, REG_A1x, REG_A1w, REG_ASTAT, REG_RETS,
+ REG_LC0, REG_LT0, REG_LB0, REG_LC1, REG_LT1, REG_LB1,
+ REG_CYCLES, REG_CYCLES2,
+ REG_USP, REG_SEQSTAT, REG_SYSCFG, REG_RETI, REG_RETX, REG_RETN, REG_RETE,
+
+ /* Pseudo Registers */
+ REG_RETE,
+#ifndef UPSTREAM_GDB_SUPPORT
+ -1 /* REG_CC */,
+ -1 /* REG_TEXT_ADDR */,
+ -1 /* REG_TEXT_END_ADDR */,
+ -1 /* REG_DATA_ADDR */,
+ -1 /* REG_FDPIC_EXEC_REGNUM */,
+ -1 /* REG_FDPIC_INTERP_REGNUM */,
+
+ /* MMRs */
+ -1 /* REG_IPEND */
+#endif
+};
+
+static char* blackfin_core_reg_list[] =
+{
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+ "p0", "p1", "p2", "p3", "p4", "p5", "sp", "fp",
+ "i0", "i1", "i2", "i3", "m0", "m1", "m2", "m3",
+ "b0", "b1", "b2", "b3", "l0", "l1", "l2", "l3",
+ "a0.x", "a0.w", "a1.x", "a1.w", "astat", "rets",
+ "lc0", "lt0", "lb0", "lc1", "lt1", "lb1",
+ "cycles", "cycles2", "usp", "seqstat", "syscfg",
+ "reti", "retx", "retn", "rete"
+};
+
+static struct blackfin_core_reg blackfin_core_reg_list_arch_info[BLACKFINNUMCOREREGS] =
+{
+ {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},
+ {38, NULL, NULL},
+ {39, NULL, NULL},
+ {40, NULL, NULL},
+ {41, NULL, NULL},
+ {42, NULL, NULL},
+ {43, NULL, NULL},
+ {44, NULL, NULL},
+ {45, NULL, NULL},
+ {46, NULL, NULL},
+ {47, NULL, NULL},
+ {48, NULL, NULL},
+ {49, NULL, NULL},
+ {50, NULL, NULL},
+ {51, NULL, NULL},
+ {52, NULL, NULL},
+};
+
+static uint8_t blackfin_gdb_dummy_value[] = {0, 0, 0, 0};
+
+static struct reg blackfin_gdb_dummy_reg =
+{
+ .name = "GDB dummy register",
+ .value = blackfin_gdb_dummy_value,
+ .dirty = 0,
+ .valid = 1,
+ .size = 32,
+ .arch_info = NULL,
+};
+
+#define EMUCAUSE_EMUEXCPT 0x0
+#define EMUCAUSE_EMUIN 0x1
+#define EMUCAUSE_WATCHPOINT 0x2
+#define EMUCAUSE_PM0_OVERFLOW 0x4
+#define EMUCAUSE_PM1_OVERFLOW 0x5
+#define EMUCAUSE_SINGLE_STEP 0x8
+
+#define WPDA_DISABLE 0
+#define WPDA_WRITE 1
+#define WPDA_READ 2
+#define WPDA_ALL 3
+
+static const uint8_t blackfin_breakpoint_16[] = { 0x25, 0x0 };
+static const uint8_t blackfin_breakpoint_32[] = { 0x25, 0x0, 0x0, 0x0 };
+
+int blackfin_wait_clocks = -1;
+
+/* This function reads hardware register and update the value in cache. */
+static int blackfin_get_core_reg(struct reg *reg)
+{
+ struct blackfin_core_reg *blackfin_reg = reg->arch_info;
+ struct target *target = blackfin_reg->target;
+ struct blackfin_common *blackfin = target_to_blackfin(target);
+ struct blackfin_jtag *jtag_info = &blackfin->jtag_info;
+ uint32_t value;
+
+ if (target->state != TARGET_HALTED)
+ {
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ value = blackfin_register_get(jtag_info, map_gdb_core[blackfin_reg->num]);
+ buf_set_u32(reg->value, 0, 32, value);
+ reg->valid = 1;
+ reg->dirty = 0;
+
+ return ERROR_OK;
+}
+
+/* This function does not set hardware register. It just sets the register in
+ the cache and set it's dirty flag. When restoring context, all dirty
+ registers will be written back to the hardware. */
+static int blackfin_set_core_reg(struct reg *reg, uint8_t *buf)
+{
+ struct blackfin_core_reg *blackfin_reg = reg->arch_info;
+ struct target *target = blackfin_reg->target;
+ uint32_t value;
+
+ if (target->state != TARGET_HALTED)
+ {
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ value = buf_get_u32(buf, 0, 32);
+ buf_set_u32(reg->value, 0, 32, value);
+ reg->dirty = 1;
+ reg->valid = 1;
+
+ return ERROR_OK;
+}
+
+static const struct reg_arch_type blackfin_reg_type =
+{
+ .get = blackfin_get_core_reg,
+ .set = blackfin_set_core_reg,
+};
+
+
+/* We does not actually save all registers here. We just invalidate
+ all registers in the cache. When an invalid register in the cache
+ is read, its value will then be fetched from hardware. */
+static void blackfin_save_context(struct target *target)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(target);
+ int i;
+
+ for (i = 0; i < BLACKFINNUMCOREREGS; i++)
+ {
+ blackfin->core_cache->reg_list[i].valid = 0;
+ blackfin->core_cache->reg_list[i].dirty = 0;
+ }
+}
+
+/* Write dirty registers to hardware. */
+static void blackfin_restore_context(struct target *target)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(target);
+ struct blackfin_jtag *jtag_info = &blackfin->jtag_info;
+ int i;
+
+ for (i = 0; i < BLACKFINNUMCOREREGS; i++)
+ {
+ struct reg *reg = &blackfin->core_cache->reg_list[i];
+ struct blackfin_core_reg *blackfin_reg = reg->arch_info;
+
+ if (reg->dirty)
+ {
+ uint32_t value = buf_get_u32(reg->value, 0, 32);
+ blackfin_register_set(jtag_info, map_gdb_core[blackfin_reg->num], value);
+ }
+ }
+}
+
+static void blackfin_debug_entry(struct target *target)
+{
+ blackfin_save_context(target);
+}
+
+static int blackfin_poll(struct target *target)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(target);
+ struct blackfin_jtag *jtag_info = &blackfin->jtag_info;
+ enum target_state prev_target_state = target->state;
+
+ blackfin_emupc_get(jtag_info);
+ /* If the core is already in fault, don't reset EMUPC. */
+ if (!blackfin_dbgstat_is_core_fault(jtag_info))
+ blackfin_emupc_reset(jtag_info);
+ blackfin_read_dbgstat(jtag_info);
+
+ if (blackfin_dbgstat_is_in_reset(jtag_info))
+ target->state = TARGET_RESET;
+ else if (blackfin_dbgstat_is_core_fault(jtag_info))
+ {
+ if (prev_target_state != TARGET_HALTED)
+ {
+ LOG_WARNING("%s: a double fault has occurred at EMUPC [0x%08X]",
+ target_name(target), jtag_info->emupc);
+ target->state = TARGET_HALTED;
+ target->debug_reason = DBG_REASON_UNDEFINED;
+ blackfin->is_corefault = 1;
+ }
+
+ if (prev_target_state == TARGET_RUNNING
+ || prev_target_state == TARGET_RESET)
+ {
+ target_call_event_callbacks(target, TARGET_EVENT_HALTED);
+ }
+ else if (prev_target_state == TARGET_DEBUG_RUNNING)
+ {
+ target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED);
+ }
+ }
+ else if (blackfin_dbgstat_is_emuready(jtag_info))
+
+ {
+ if (prev_target_state != TARGET_HALTED)
+ {
+ uint16_t cause;
+
+ LOG_DEBUG("Target halted");
+ target->state = TARGET_HALTED;
+
+ cause = blackfin_dbgstat_emucause(jtag_info);
+
+ blackfin_wpstat_get(jtag_info);
+
+ if ((jtag_info->wpstat & 0x3f) && !(jtag_info->wpstat & 0xc0))
+ {
+ target->debug_reason = DBG_REASON_BREAKPOINT;
+ }
+ else if (!(jtag_info->wpstat & 0x3f) && (jtag_info->wpstat & 0xc0))
+ {
+ target->debug_reason = DBG_REASON_WATCHPOINT;
+ }
+ else if ((jtag_info->wpstat & 0x3f) && (jtag_info->wpstat & 0xc0))
+ {
+ target->debug_reason = DBG_REASON_WPTANDBKPT;
+ }
+ else
+ switch (cause)
+ {
+ case EMUCAUSE_EMUEXCPT:
+ target->debug_reason = DBG_REASON_BREAKPOINT;
+ break;
+
+ case EMUCAUSE_SINGLE_STEP:
+ target->debug_reason = DBG_REASON_SINGLESTEP;
+ break;
+
+ case EMUCAUSE_WATCHPOINT:
+ abort();
+ break;
+
+ case EMUCAUSE_EMUIN:
+ target->debug_reason = DBG_REASON_DBGRQ;
+ break;
+
+ case EMUCAUSE_PM0_OVERFLOW:
+ case EMUCAUSE_PM1_OVERFLOW:
+ default:
+ target->debug_reason = DBG_REASON_UNDEFINED;
+ break;
+ }
+
+ if (jtag_info->wpstat & 0xff)
+ {
+ if (jtag_info->wpstat & 0xc0)
+ blackfin_single_step(jtag_info, blackfin->is_stepping);
+ blackfin_wpstat_clear(jtag_info);
+ }
+
+ blackfin_debug_entry(target);
+
+ if (prev_target_state == TARGET_RUNNING
+ || prev_target_state == TARGET_RESET)
+ {
+ target_call_event_callbacks(target, TARGET_EVENT_HALTED);
+ }
+ else if (prev_target_state == TARGET_DEBUG_RUNNING)
+ {
+ target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED);
+ }
+ }
+ }
+ else
+ {
+ target->state = TARGET_RUNNING;
+ target->debug_reason = DBG_REASON_NOTHALTED;
+ }
+
+ if (prev_target_state != target->state)
+ LOG_DEBUG("target->state: ==> %s", target_state_name(target));
+
+ return ERROR_OK;
+}
+
+static int blackfin_arch_state(struct target *target)
+{
+ return ERROR_FAIL;
+}
+
+static int blackfin_target_request_data(struct target *target,
+ uint32_t size, uint8_t *buffer)
+{
+ return ERROR_FAIL;
+}
+
+static int blackfin_halt(struct target *target)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(target);
+ struct blackfin_jtag *jtag_info = &blackfin->jtag_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)
+ {
+ /* FIXME it might be possible to halt while in reset,
+ see other targets for a example. */
+ LOG_ERROR("can't request a halt while in reset");
+ return ERROR_TARGET_FAILURE;
+ }
+
+ blackfin_emulation_enable(jtag_info);
+ blackfin_emulation_trigger(jtag_info);
+
+ target->debug_reason = DBG_REASON_DBGRQ;
+
+ return ERROR_OK;
+}
+
+static int blackfin_resume_1(struct target *target, int current,
+ uint32_t address, int handle_breakpoints, int debug_execution, bool step)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(target);
+ struct blackfin_jtag *jtag_info = &blackfin->jtag_info;
+
+ /* We don't handle this for now. */
+ assert(debug_execution == 0);
+
+ /* FIXME handle handle_breakpoints !!!*/
+
+ if (target->state != TARGET_HALTED)
+ {
+ LOG_WARNING("target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ if (!debug_execution)
+ {
+ target_free_all_working_areas(target);
+ }
+
+ blackfin_emupc_reset(jtag_info);
+
+ blackfin_restore_context(target);
+
+ if (!current)
+ {
+ blackfin_register_set(jtag_info, REG_RETE, address);
+ }
+
+ if (blackfin->status_pending_p && blackfin->pending_is_breakpoint)
+ {
+ int retval;
+ uint8_t buf[2];
+
+ retval = blackfin_read_mem(jtag_info, blackfin->pending_stop_pc, 2, buf);
+ assert(retval == ERROR_OK);
+
+ if (buf[0] != blackfin_breakpoint_16[0]
+ || buf[1] != blackfin_breakpoint_16[1])
+ {
+ /* The breakpoint is gone. Consume the pending status. */
+ blackfin->pending_is_breakpoint = 0;
+ blackfin->status_pending_p = 0;
+ }
+
+ if (blackfin->status_pending_p)
+ return ERROR_OK;
+ }
+
+ if (step && !blackfin->is_stepping)
+ {
+ blackfin_dbgctl_bit_set_esstep(jtag_info);
+ blackfin->is_stepping = 1;
+ }
+ else if (!step && blackfin->is_stepping)
+ {
+ blackfin_dbgctl_bit_clear_esstep(jtag_info);
+ blackfin->is_stepping = 0;
+ }
+
+ 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);
+ }
+
+ blackfin->is_running = 1;
+ blackfin->is_interrupted = 0;
+ blackfin->dmem_control_valid_p = 0;
+ blackfin->imem_control_valid_p = 0;
+ blackfin_emulation_return(jtag_info);
+
+ return ERROR_OK;
+}
+
+static int blackfin_resume(struct target *target, int current,
+ uint32_t address, int handle_breakpoints, int debug_execution)
+{
+ int retval;
+
+ retval = blackfin_resume_1(target, current, address, handle_breakpoints, debug_execution, false);
+
+ return retval;
+}
+
+static int blackfin_step(struct target *target, int current,
+ uint32_t address, int handle_breakpoints)
+{
+ int retval;
+
+ retval = blackfin_resume_1(target, current, address, handle_breakpoints, 0, true);
+
+ return retval;
+}
+
+static int blackfin_assert_reset(struct target *target)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(target);
+ struct blackfin_jtag *jtag_info = &blackfin->jtag_info;
+
+ LOG_DEBUG("target->state: %s", target_state_name(target));
+
+ blackfin_system_reset(jtag_info);
+ blackfin_core_reset(jtag_info);
+
+ target->state = TARGET_HALTED;
+
+ /* Reset should bring the core out of core fault. */
+ blackfin->is_corefault = 0;
+
+ /* Reset should invalidate register cache. */
+ register_cache_invalidate(blackfin->core_cache);
+
+ if (!target->reset_halt)
+ {
+ blackfin_resume(target, 1, 0, 0, 0);
+ target->state = TARGET_RUNNING;
+ }
+
+ return ERROR_OK;
+}
+
+static int blackfin_deassert_reset(struct target *target)
+{
+ return ERROR_OK;
+}
+
+static int blackfin_get_gdb_reg_list(struct target *target, struct reg **reg_list[],
+ int *reg_list_size, enum target_register_class reg_class)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(target);
+ int i;
+
+ *reg_list_size = BFIN_NUM_REGS;
+ *reg_list = malloc(sizeof(struct reg*) * (*reg_list_size));
+
+ for (i = 0; i < BLACKFINNUMCOREREGS; i++)
+ (*reg_list)[i] = &blackfin->core_cache->reg_list[i];
+
+ for (i = BLACKFINNUMCOREREGS; i < BFIN_NUM_REGS; i++)
+ {
+ if (i == BFIN_PC_REGNUM)
+ (*reg_list)[i] = &blackfin->core_cache->reg_list[BFIN_RETE_REGNUM];
+ /* TODO handle CC */
+ else
+ (*reg_list)[i] = &blackfin_gdb_dummy_reg;
+ }
+
+ return ERROR_OK;
+}
+
+static int blackfin_read_memory(struct target *target, uint32_t address,
+ uint32_t size, uint32_t count, uint8_t *buffer)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(target);
+ struct blackfin_jtag *jtag_info = &blackfin->jtag_info;
+ 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;
+ }
+
+ retval = blackfin_read_mem(jtag_info, address, size * count, buffer);
+
+ return retval;
+}
+
+static int blackfin_write_memory(struct target *target, uint32_t address,
+ uint32_t size, uint32_t count, const uint8_t *buffer)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(target);
+ struct blackfin_jtag *jtag_info = &blackfin->jtag_info;
+ 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;
+ }
+
+ retval = blackfin_write_mem(jtag_info, address, size * count, buffer);
+
+ return retval;
+}
+
+static int blackfin_checksum_memory(struct target *target,
+ uint32_t address, uint32_t count, uint32_t* checksum)
+{
+ return ERROR_FAIL;
+}
+
+static int blackfin_blank_check_memory(struct target *target,
+ uint32_t address, uint32_t count, uint32_t* blank)
+{
+ return ERROR_FAIL;
+}
+
+static int blackfin_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 ERROR_FAIL;
+}
+
+static int blackfin_add_breakpoint(struct target *target, struct breakpoint *breakpoint)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(target);
+ struct blackfin_jtag *jtag_info = &blackfin->jtag_info;
+ int retval;
+
+ assert(breakpoint->set == 0);
+
+ blackfin_emupc_reset(jtag_info);
+
+ if (breakpoint->type == BKPT_SOFT)
+ {
+ const uint8_t *bp;
+
+ if (breakpoint->length == 2)
+ bp = blackfin_breakpoint_16;
+ else
+ bp = blackfin_breakpoint_32;
+
+ retval = blackfin_read_memory(target, breakpoint->address,
+ breakpoint->length, 1, breakpoint->orig_instr);
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = blackfin_write_memory(target, breakpoint->address,
+ breakpoint->length, 1, bp);
+ if (retval != ERROR_OK)
+ return retval;
+ }
+ else /* BKPT_HARD */
+ {
+ int i;
+ for (i = 0; i < BLACKFIN_MAX_HWBREAKPOINTS; i++)
+ if (jtag_info->hwbps[i] == (uint32_t) -1)
+ break;
+ if (i == BLACKFIN_MAX_HWBREAKPOINTS)
+ {
+ LOG_ERROR("%s: no more hardware breakpoint available for 0x%08x",
+ target_name(target), breakpoint->address);
+ return ERROR_FAIL;
+ }
+
+ jtag_info->hwbps[i] = breakpoint->address;
+ if (blackfin->is_locked)
+ {
+ LOG_WARNING("%s: target is locked, hardware breakpoint [0x%08x] will be set when it's unlocked", target_name(target), breakpoint->address);
+ }
+ else
+ {
+ blackfin_wpu_set_wpia(jtag_info, i, breakpoint->address, 1);
+ }
+ }
+
+ breakpoint->set = 1;
+
+ return ERROR_OK;
+}
+
+static int blackfin_remove_breakpoint(struct target *target, struct breakpoint *breakpoint)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(target);
+ struct blackfin_jtag *jtag_info = &blackfin->jtag_info;
+ int retval;
+
+ assert(breakpoint->set != 0);
+
+ blackfin_emupc_reset(jtag_info);
+
+ if (breakpoint->type == BKPT_SOFT)
+ {
+ retval = blackfin_write_memory(target, breakpoint->address,
+ breakpoint->length, 1, breakpoint->orig_instr);
+ if (retval != ERROR_OK)
+ return retval;
+ }
+ else /* BKPT_HARD */
+ {
+ int i;
+ for (i = 0; i < BLACKFIN_MAX_HWBREAKPOINTS; i++)
+ if (jtag_info->hwbps[i] == breakpoint->address)
+ break;
+
+ if (i == BLACKFIN_MAX_HWBREAKPOINTS)
+ {
+ LOG_ERROR("%s: no hardware breakpoint at 0x%08x",
+ target_name(target), breakpoint->address);
+ return ERROR_FAIL;
+ }
+
+ jtag_info->hwbps[i] = -1;
+ if (blackfin->is_locked)
+ {
+ /* The hardware breakpoint will only be set when target is
+ unlocked. Target cannot be locked again after it's unlocked.
+ So if we are removing a hardware breakpoint when target is
+ locked, that hardware breakpoint has never been set.
+ So we can just quietly remove it. */
+ }
+ else
+ {
+ blackfin_wpu_set_wpia(jtag_info, i, breakpoint->address, 0);
+ }
+ }
+
+ breakpoint->set = 0;
+
+ return ERROR_OK;
+}
+
+static int blackfin_add_watchpoint(struct target *target, struct watchpoint *watchpoint)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(target);
+ struct blackfin_jtag *jtag_info = &blackfin->jtag_info;
+ int i;
+ bool range;
+
+ /* TODO provide a method to always use range watchpoint. */
+
+ if (target->state != TARGET_HALTED)
+ return ERROR_TARGET_NOT_HALTED;
+
+ blackfin_emupc_reset(jtag_info);
+
+ if (watchpoint->length <= 4
+ && jtag_info->hwwps[0].used
+ && (jtag_info->hwwps[1].used
+ || jtag_info->hwwps[0].range))
+ {
+ LOG_ERROR("all hardware watchpoints are in use.");
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+ }
+
+ if (watchpoint->length > 4
+ && (jtag_info->hwwps[0].used
+ || jtag_info->hwwps[1].used))
+ {
+ LOG_ERROR("no enough hardware watchpoints.");
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+ }
+
+ if (watchpoint->length <= 4)
+ {
+ i = jtag_info->hwwps[0].used ? 1 : 0;
+ range = false;
+ }
+ else
+ {
+ i = 0;
+ range = true;
+ }
+
+ jtag_info->hwwps[i].addr = watchpoint->address;
+ jtag_info->hwwps[i].len = watchpoint->length;
+ jtag_info->hwwps[i].range = range;
+ jtag_info->hwwps[i].used = true;
+ switch (watchpoint->rw)
+ {
+ case WPT_READ:
+ jtag_info->hwwps[i].mode = WPDA_READ;
+ break;
+ case WPT_WRITE:
+ jtag_info->hwwps[i].mode = WPDA_WRITE;
+ break;
+ case WPT_ACCESS:
+ jtag_info->hwwps[i].mode = WPDA_ALL;
+ break;
+ }
+
+ if (blackfin->is_locked)
+ {
+ LOG_WARNING("%s: target is locked, hardware watchpoint [0x%08x] will be set when it's unlocked", target_name(target), watchpoint->address);
+ }
+ else
+ {
+ blackfin_wpu_set_wpda(jtag_info, i);
+ }
+
+ return ERROR_OK;
+}
+
+static int blackfin_remove_watchpoint(struct target *target, struct watchpoint *watchpoint)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(target);
+ struct blackfin_jtag *jtag_info = &blackfin->jtag_info;
+ int mode;
+ int i;
+
+ /* TODO provide a method to always use range watchpoint. */
+
+ if (target->state != TARGET_HALTED)
+ return ERROR_TARGET_NOT_HALTED;
+
+ blackfin_emupc_reset(jtag_info);
+
+ switch (watchpoint->rw)
+ {
+ case WPT_READ:
+ mode = WPDA_READ;
+ break;
+ case WPT_WRITE:
+ mode = WPDA_WRITE;
+ break;
+ case WPT_ACCESS:
+ mode = WPDA_ALL;
+ break;
+ default:
+ return ERROR_FAIL;
+ }
+
+ for (i = 0; i < BLACKFIN_MAX_HWWATCHPOINTS; i++)
+ if (jtag_info->hwwps[i].addr == watchpoint->address
+ && jtag_info->hwwps[i].len == watchpoint->length
+ && jtag_info->hwwps[i].mode == mode)
+ break;
+
+ if (i == BLACKFIN_MAX_HWWATCHPOINTS)
+ {
+ LOG_ERROR("no hardware watchpoint at 0x%08X length %d.",
+ watchpoint->address, watchpoint->length);
+ return ERROR_FAIL;
+ }
+
+ if (watchpoint->length > 4)
+ {
+ assert (i == 0 && jtag_info->hwwps[i].range);
+ }
+
+ jtag_info->hwwps[i].mode = WPDA_DISABLE;
+
+ if (blackfin->is_locked)
+ {
+ /* See the comment in blackfin_remove_breakpoint. */
+ }
+ else
+ {
+ blackfin_wpu_set_wpda(jtag_info, i);
+ }
+
+ jtag_info->hwwps[i].addr = 0;
+ jtag_info->hwwps[i].len = 0;
+ jtag_info->hwwps[i].range = false;
+ jtag_info->hwwps[i].used = false;
+
+ return ERROR_OK;
+}
+
+static int blackfin_target_create(struct target *target, Jim_Interp *interp)
+{
+ struct blackfin_common *blackfin = calloc(1, sizeof(struct blackfin_common));
+ struct Jim_Obj *objPtr;
+ const char *map, *config;
+ char *end;
+
+ target->arch_info = blackfin;
+
+ blackfin->common_magic = BLACKFIN_COMMON_MAGIC;
+ strcpy(blackfin->part, target_name(target));
+ end = strchr(blackfin->part, '.');
+ if (end)
+ *end = '\0';
+
+ objPtr = Jim_GetGlobalVariableStr(interp, "MEMORY_MAP", JIM_NONE);
+ map = Jim_GetString(objPtr, NULL);
+ parse_memory_map(target, map);
+
+ objPtr = Jim_GetGlobalVariableStr(interp, "BLACKFIN_CONFIG", JIM_NONE);
+ config = Jim_GetString(objPtr, NULL);
+ blackfin_parse_config(target, config);
+
+ objPtr = Jim_GetGlobalVariableStr(interp, "SDRRC", JIM_NONE);
+ if (objPtr)
+ {
+ struct blackfin_sdram_config *sdram_config;
+ long value;
+ int retval;
+ sdram_config = malloc(sizeof (blackfin->sdram_config));
+ if (!sdram_config)
+ {
+ LOG_ERROR("%s: malloc(%"PRIzu") failed",
+ target_name(target), sizeof (blackfin->sdram_config));
+ return ERROR_FAIL;
+ }
+ retval = Jim_GetLong(interp, objPtr, &value);
+ if (retval == JIM_OK)
+ sdram_config->sdrrc = value;
+ else
+ return ERROR_FAIL;
+
+ objPtr = Jim_GetGlobalVariableStr(interp, "SDBCTL", JIM_NONE);
+ if (!objPtr)
+ {
+ LOG_ERROR("%s: SDBCTL is not defined", target_name(target));
+ return ERROR_FAIL;
+ }
+ retval = Jim_GetLong(interp, objPtr, &value);
+ if (retval == JIM_OK)
+ sdram_config->sdbctl = value;
+ else
+ return ERROR_FAIL;
+
+ objPtr = Jim_GetGlobalVariableStr(interp, "SDGCTL", JIM_NONE);
+ if (!objPtr)
+ {
+ LOG_ERROR("%s: SDGCTL is not defined", target_name(target));
+ return ERROR_FAIL;
+ }
+ retval = Jim_GetLong(interp, objPtr, &value);
+ if (retval == JIM_OK)
+ sdram_config->sdgctl = value;
+ else
+ return ERROR_FAIL;
+
+ blackfin->sdram_config = sdram_config;
+ }
+ else
+ blackfin->sdram_config = NULL;
+
+ objPtr = Jim_GetGlobalVariableStr(interp, "DDRCTL0", JIM_NONE);
+ if (objPtr)
+ {
+ struct blackfin_ddr_config *ddr_config;
+ long value;
+ int retval;
+ ddr_config = malloc(sizeof (blackfin->ddr_config));
+ if (!ddr_config)
+ {
+ LOG_ERROR("%s: malloc(%"PRIzu") failed",
+ target_name(target), sizeof (blackfin->ddr_config));
+ return ERROR_FAIL;
+ }
+ retval = Jim_GetLong(interp, objPtr, &value);
+ if (retval == JIM_OK)
+ ddr_config->ddrctl0 = value;
+ else
+ return ERROR_FAIL;
+
+ objPtr = Jim_GetGlobalVariableStr(interp, "DDRCTL1", JIM_NONE);
+ if (!objPtr)
+ {
+ LOG_ERROR("%s: DDRCTL1 is not defined", target_name(target));
+ return ERROR_FAIL;
+ }
+ retval = Jim_GetLong(interp, objPtr, &value);
+ if (retval == JIM_OK)
+ ddr_config->ddrctl1 = value;
+ else
+ return ERROR_FAIL;
+
+ objPtr = Jim_GetGlobalVariableStr(interp, "DDRCTL2", JIM_NONE);
+ if (!objPtr)
+ {
+ LOG_ERROR("%s: DDRCTL2 is not defined", target_name(target));
+ return ERROR_FAIL;
+ }
+ retval = Jim_GetLong(interp, objPtr, &value);
+ if (retval == JIM_OK)
+ ddr_config->ddrctl2 = value;
+ else
+ return ERROR_FAIL;
+
+ blackfin->ddr_config = ddr_config;
+ }
+ else
+ blackfin->ddr_config = NULL;
+
+ blackfin->dmem_control_valid_p = 0;
+ blackfin->imem_control_valid_p = 0;
+ blackfin->dmem_control = 0;
+ blackfin->imem_control = 0;
+
+ return ERROR_OK;
+}
+
+static struct reg_cache *blackfin_build_reg_cache(struct target *target)
+{
+ /* get pointers to arch-specific information */
+ struct blackfin_common *blackfin = target_to_blackfin(target);
+
+ int num_regs = BLACKFINNUMCOREREGS;
+ 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 blackfin_core_reg *arch_info = malloc(sizeof(struct blackfin_core_reg) * num_regs);
+ int i;
+
+ register_init_dummy(&blackfin_gdb_dummy_reg);
+
+ /* Build the process context cache */
+ cache->name = "blackfin registers";
+ cache->next = NULL;
+ cache->reg_list = reg_list;
+ cache->num_regs = num_regs;
+ (*cache_p) = cache;
+ blackfin->core_cache = cache;
+
+ for (i = 0; i < num_regs; i++)
+ {
+ arch_info[i] = blackfin_core_reg_list_arch_info[i];
+ arch_info[i].target = target;
+ arch_info[i].blackfin_common = blackfin;
+ reg_list[i].name = blackfin_core_reg_list[i];
+ reg_list[i].feature = NULL;
+ 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 = &blackfin_reg_type;
+ reg_list[i].arch_info = &arch_info[i];
+ }
+
+ return cache;
+}
+
+static int blackfin_init_target(struct command_context *cmd_ctx,
+ struct target *target)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(target);
+
+ blackfin->jtag_info.target = target;
+ blackfin_build_reg_cache(target);
+ return ERROR_OK;
+}
+
+static int blackfin_calculate_wait_clocks(void)
+{
+ int clocks;
+ int frequency;
+
+ /* The following default numbers of wait clock for various cables are
+ tested on a BF537 stamp board, on which U-Boot is running.
+ CCLK is set to 62MHz and SCLK is set to 31MHz, which is the lowest
+ frequency I can set in BF537 stamp Linux kernel.
+
+ The test is done by dumping memory from 0x20000000 to 0x20000010 using
+ GDB and gdbproxy:
+
+ (gdb) dump memory u-boot.bin 0x20000000 0x20000010
+ (gdb) shell hexdump -C u-boot.bin
+
+ With an incorrect number of wait clocks, the first 4 bytes will be
+ duplicated by the second 4 bytes. */
+
+ clocks = -1;
+ frequency = jtag_get_speed_khz();
+
+ if (strcmp(jtag_get_name(), "ftdi") == 0)
+ {
+ /* For full speed ftdi device, we only need 3 wait clocks. For
+ high speed ftdi device, we need 5 wait clocks when its frequency
+ is less than or equal to 6000. We need a function like
+
+ bool ftdi_is_high_speed(void)
+
+ to distinguish them. But currently ftdi driver does not provide
+ such a function. So we just set wait clocks to 5 for both cases. */
+
+ if (frequency <= 6000)
+ clocks = 5;
+ else if (frequency <= 15000)
+ clocks = 12;
+ else
+ clocks = 21;
+ }
+ else if (strcmp(jtag_get_name(), "ice1000") == 0
+ || strcmp(jtag_get_name(), "ice2000") == 0)
+ {
+ if (frequency <= 5000)
+ clocks = 5;
+ else if (frequency <= 10000)
+ clocks = 11;
+ else if (frequency <= 17000)
+ clocks = 19;
+ else /* <= 25MHz */
+ clocks = 30;
+ }
+ else
+ {
+ /* intended empty */
+ }
+
+ if (clocks == -1)
+ {
+ clocks = 30;
+ LOG_WARNING("%s: untested cable running at %d KHz, set wait_clocks to %d",
+ jtag_get_name(), frequency, clocks);
+ }
+
+ return clocks;
+}
+
+static int blackfin_examine(struct target *target)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(target);
+ struct blackfin_jtag *jtag_info = &blackfin->jtag_info;
+ int i;
+
+ if (!target_was_examined(target))
+ {
+ target_set_examined(target);
+
+ jtag_info->dbgctl = 0;
+ jtag_info->dbgstat = 0;
+ jtag_info->emuir_a = BLACKFIN_INSN_ILLEGAL;
+ jtag_info->emuir_b = BLACKFIN_INSN_ILLEGAL;
+ jtag_info->emudat_out = 0;
+ jtag_info->emudat_in = 0;
+
+ jtag_info->wpiactl = 0;
+ jtag_info->wpdactl = 0;
+ jtag_info->wpstat = 0;
+ for (i = 0; i < BLACKFIN_MAX_HWBREAKPOINTS; i++)
+ jtag_info->hwbps[i] = -1;
+ for (i = 0; i < BLACKFIN_MAX_HWWATCHPOINTS; i++)
+ {
+ jtag_info->hwwps[i].addr = 0;
+ jtag_info->hwwps[i].len = 0;
+ jtag_info->hwwps[i].mode = WPDA_DISABLE;
+ jtag_info->hwwps[i].range = false;
+ jtag_info->hwwps[i].used = false;
+ }
+
+ jtag_info->emupc = -1;
+
+ blackfin_emulation_enable(jtag_info);
+ }
+
+ blackfin_wait_clocks = blackfin_calculate_wait_clocks();
+
+ return ERROR_OK;
+}
+
+COMMAND_HANDLER(blackfin_handle_wpu_init_command)
+{
+ struct target *target = get_current_target(CMD_CTX);
+ struct blackfin_common *blackfin = target_to_blackfin(target);
+ struct blackfin_jtag *jtag_info = &blackfin->jtag_info;
+
+ if (!target_was_examined(target))
+ {
+ LOG_ERROR("target not examined yet");
+ return ERROR_FAIL;
+ }
+
+ blackfin_wpu_init(jtag_info);
+ return ERROR_OK;
+}
+
+COMMAND_HANDLER(blackfin_handle_sdram_init_command)
+{
+ struct target *target = get_current_target(CMD_CTX);
+ struct blackfin_common *blackfin = target_to_blackfin(target);
+ struct blackfin_jtag *jtag_info = &blackfin->jtag_info;
+ int retval;
+
+ if (!target_was_examined(target))
+ {
+ LOG_ERROR("target not examined yet");
+ return ERROR_FAIL;
+ }
+ if (!blackfin->sdram_config)
+ {
+ LOG_ERROR("no SDRAM config");
+ return ERROR_FAIL;
+ }
+
+ retval = blackfin_sdram_init(jtag_info);
+ return retval;
+}
+
+COMMAND_HANDLER(blackfin_handle_ddr_init_command)
+{
+ struct target *target = get_current_target(CMD_CTX);
+ struct blackfin_common *blackfin = target_to_blackfin(target);
+ struct blackfin_jtag *jtag_info = &blackfin->jtag_info;
+ int retval;
+
+ if (!target_was_examined(target))
+ {
+ LOG_ERROR("target not examined yet");
+ return ERROR_FAIL;
+ }
+ if (!blackfin->ddr_config)
+ {
+ LOG_ERROR("no DDR config");
+ return ERROR_FAIL;
+ }
+
+ retval = blackfin_ddr_init(jtag_info);
+ return retval;
+}
+
+static const struct command_registration blackfin_exec_command_handlers[] = {
+ {
+ .name = "wpu_init",
+ .handler = blackfin_handle_wpu_init_command,
+ .mode = COMMAND_EXEC,
+ .help = "Initialize Watchpoint Unit",
+ },
+ {
+ .name = "sdram_init",
+ .handler = blackfin_handle_sdram_init_command,
+ .mode = COMMAND_EXEC,
+ .help = "Initialize SDRAM",
+ },
+ {
+ .name = "ddr_init",
+ .handler = blackfin_handle_ddr_init_command,
+ .mode = COMMAND_EXEC,
+ .help = "Initialize DDR",
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
+static const struct command_registration blackfin_command_handlers[] = {
+ {
+ .name = "blackfin",
+ .mode = COMMAND_ANY,
+ .help = "Blackfin command group",
+ .chain = blackfin_exec_command_handlers,
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
+struct target_type blackfin_target =
+{
+ .name = "blackfin",
+
+ .poll = blackfin_poll,
+ .arch_state = blackfin_arch_state,
+
+ .target_request_data = blackfin_target_request_data,
+
+ .halt = blackfin_halt,
+ .resume = blackfin_resume,
+ .step = blackfin_step,
+
+ .assert_reset = blackfin_assert_reset,
+ .deassert_reset = blackfin_deassert_reset,
+ .soft_reset_halt = NULL,
+
+ .get_gdb_reg_list = blackfin_get_gdb_reg_list,
+
+ .read_memory = blackfin_read_memory,
+ .write_memory = blackfin_write_memory,
+ .checksum_memory = blackfin_checksum_memory,
+ .blank_check_memory = blackfin_blank_check_memory,
+
+ .run_algorithm = blackfin_run_algorithm,
+
+ .add_breakpoint = blackfin_add_breakpoint,
+ .remove_breakpoint = blackfin_remove_breakpoint,
+ .add_watchpoint = blackfin_add_watchpoint,
+ .remove_watchpoint = blackfin_remove_watchpoint,
+
+ .commands = blackfin_command_handlers,
+ .target_create = blackfin_target_create,
+ .init_target = blackfin_init_target,
+ .examine = blackfin_examine,
+};
diff --git a/src/target/blackfin.h b/src/target/blackfin.h
new file mode 100644
index 0000000..18c9218
--- /dev/null
+++ b/src/target/blackfin.h
@@ -0,0 +1,78 @@
+/***************************************************************************
+ * Copyright (C) 2011 by Analog Devices, Inc. *
+ * Written by Jie Zhang <***@analog.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 BLACKFIN_H
+#define BLACKFIN_H
+
+#include "target.h"
+#include "blackfin_jtag.h"
+#include "blackfin_mem.h"
+
+#define BLACKFINNUMCOREREGS 53
+#define BLACKFIN_COMMON_MAGIC 0x05330533
+#define BLACKFIN_PART_MAXLEN 20
+
+struct blackfin_common
+{
+ uint32_t common_magic;
+ char part[BLACKFIN_PART_MAXLEN];
+ struct blackfin_jtag jtag_info;
+ const struct blackfin_mem_map *mem_map;
+ const struct blackfin_l1_map *l1_map;
+ const struct blackfin_sdram_config *sdram_config;
+ const struct blackfin_ddr_config *ddr_config;
+ uint32_t mdma_s0;
+ uint32_t mdma_d0;
+ struct reg_cache *core_cache;
+ // uint32_t core_regs[BLACKFINNUMCOREREGS];
+
+ unsigned int is_locked:1;
+ unsigned int is_running:1;
+ unsigned int is_interrupted:1;
+ unsigned int is_stepping:1;
+ unsigned int is_corefault:1;
+
+ unsigned int leave_stopped:1;
+ unsigned int status_pending_p:1;
+ unsigned int pending_is_breakpoint:1;
+
+ unsigned int l1_data_a_cache_enabled:1;
+ unsigned int l1_data_b_cache_enabled:1;
+ unsigned int l1_code_cache_enabled:1;
+
+ unsigned int dmem_control_valid_p:1;
+ unsigned int imem_control_valid_p:1;
+
+ int pending_signal;
+ uint32_t pending_stop_pc;
+
+ uint32_t dmem_control;
+ uint32_t imem_control;
+};
+
+static inline struct blackfin_common *
+target_to_blackfin(struct target *target)
+{
+ return (struct blackfin_common *)target->arch_info;
+}
+
+extern int blackfin_wait_clocks;
+
+#endif /* BLACKFIN_H */
diff --git a/src/target/blackfin_config.c b/src/target/blackfin_config.c
new file mode 100644
index 0000000..4830b89
--- /dev/null
+++ b/src/target/blackfin_config.c
@@ -0,0 +1,91 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "helper/log.h"
+
+#include "target.h"
+#include "blackfin.h"
+#include "blackfin_config.h"
+
+
+#if !defined(HAVE_LIBEXPAT)
+
+int blackfin_parse_config(struct target *target, const char *configs)
+{
+ LOG_WARNING("%s: cannot parse Blackfin XML config file; XML support was disabled at compile time", target_name(target));
+ return ERROR_FAIL;
+}
+
+#else /* HAVE_LIBEXPAT */
+
+#include "xml_support.h"
+
+/* Callback called by Expat on start of element.
+ This function handles the following elements:
+ * processor: unused now
+ * core: contains the memory map for the core
+ * memory: a memory region
+ * property: unused now
+ The target name is in format PROCESSOR or PROCESSOR.CORE */
+static void blackfin_config_start_element(void *data_, const XML_Char *name,
+ const XML_Char **attrs)
+{
+ struct blackfin_common *blackfin = data_;
+
+ if (strcmp(name, "processor") == 0)
+ {
+ /* not used for now */
+ }
+ else if (strcmp(name, "config") == 0)
+ {
+ const XML_Char *config_name;
+ uint32_t value;
+
+ config_name = xml_find_attribute(attrs, "name");
+ if (xml_parse_uint32(xml_find_attribute(attrs, "value"), &value) < 0)
+ return;
+ if (strcmp(config_name, "mdma_d0") == 0)
+ blackfin->mdma_d0 = value;
+ else if (strcmp(config_name, "mdma_s0") == 0)
+ blackfin->mdma_s0 = value;
+ }
+}
+
+static void blackfin_config_end_element(void *data_, const XML_Char *name)
+{
+ return;
+}
+
+static void blackfin_config_character_data(void *data_, const XML_Char *s, int len)
+{
+ return;
+}
+
+int blackfin_parse_config(struct target *target, const char *configs)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(target);
+ int retval;
+
+ XML_Parser parser = XML_ParserCreateNS(NULL, '!');
+ if (parser == NULL)
+ return ERROR_FAIL;
+
+ XML_SetElementHandler(parser, blackfin_config_start_element, blackfin_config_end_element);
+ XML_SetCharacterDataHandler(parser, blackfin_config_character_data);
+ XML_SetUserData(parser, blackfin);
+
+ retval = XML_Parse(parser, configs, strlen(configs), 1);
+ if (retval != XML_STATUS_OK)
+ {
+ enum XML_Error err = XML_GetErrorCode(parser);
+ LOG_ERROR("%s: cannot parse Blackfin XML config file [%s]",
+ target_name(target), XML_ErrorString(err));
+ return ERROR_FAIL;
+ }
+
+ return ERROR_OK;
+}
+
+#endif
+
diff --git a/src/target/blackfin_config.h b/src/target/blackfin_config.h
new file mode 100644
index 0000000..9803d85
--- /dev/null
+++ b/src/target/blackfin_config.h
@@ -0,0 +1,6 @@
+#ifndef BLACKFIN_CONFIG_H
+#define BLACKFIN_CONFIG_H
+
+extern int blackfin_parse_config(struct target *target, const char *configs);
+
+#endif /* BLACKFIN_CONFIG_H */
diff --git a/src/target/blackfin_insn.c b/src/target/blackfin_insn.c
new file mode 100644
index 0000000..73572f1
--- /dev/null
+++ b/src/target/blackfin_insn.c
@@ -0,0 +1,295 @@
+/***************************************************************************
+ * Copyright (C) 2011 by Analog Devices, Inc. *
+ * Written by Jie Zhang <***@analog.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 "blackfin_insn.h"
+
+uint32_t
+blackfin_gen_move (enum core_regnum dest, enum core_regnum src)
+{
+ uint32_t insn;
+
+ insn = 0x3000;
+ insn |= src & 0xf;
+ insn |= (dest & 0xf) << 3;
+ insn |= GROUP (src) << 6;
+ insn |= GROUP (dest) << 9;
+
+ return insn;
+}
+
+static uint32_t
+gen_ldstidxi (enum core_regnum reg,
+ enum core_regnum ptr, int32_t offset, int w, int sz)
+{
+ uint32_t insn;
+
+ insn = 0xe4000000;
+ insn |= (reg & 0xf) << 16;
+ insn |= (ptr & 0xf) << 19;
+
+ switch (sz)
+ {
+ case 0:
+ offset >>= 2;
+ break;
+ case 1:
+ offset >>= 1;
+ break;
+ case 2:
+ break;
+ default:
+ abort ();
+ }
+ if (offset > 32767 || offset < -32768)
+ abort ();
+ insn |= offset & 0xffff;
+
+ insn |= w << 25;
+ insn |= sz << 22;
+
+ return insn;
+}
+
+uint32_t
+blackfin_gen_load32_offset (enum core_regnum dest, enum core_regnum base, int32_t offset)
+{
+ return gen_ldstidxi (dest, base, offset, 0, 0);
+}
+
+uint32_t
+blackfin_gen_store32_offset (enum core_regnum base, int32_t offset, enum core_regnum src)
+{
+ return gen_ldstidxi (src, base, offset, 1, 0);
+}
+
+uint32_t
+blackfin_gen_load16z_offset (enum core_regnum dest, enum core_regnum base, int32_t offset)
+{
+ return gen_ldstidxi (dest, base, offset, 0, 1);
+}
+
+uint32_t
+blackfin_gen_store16_offset (enum core_regnum base, int32_t offset, enum core_regnum src)
+{
+ return gen_ldstidxi (src, base, offset, 1, 1);
+}
+
+uint32_t
+blackfin_gen_load8z_offset (enum core_regnum dest, enum core_regnum base, int32_t offset)
+{
+ return gen_ldstidxi (dest, base, offset, 0, 2);
+}
+
+uint32_t
+blackfin_gen_store8_offset (enum core_regnum base, int32_t offset, enum core_regnum src)
+{
+ return gen_ldstidxi (src, base, offset, 1, 2);
+}
+
+static uint32_t
+gen_ldst (enum core_regnum reg,
+ enum core_regnum ptr, int post_dec, int w, int sz)
+{
+ uint32_t insn;
+
+ insn = 0x9000;
+ insn |= reg & 0xf;
+ insn |= (ptr & 0xf) << 3;
+ insn |= post_dec << 7;
+ insn |= w << 9;
+ insn |= sz << 10;
+
+ return insn;
+}
+
+uint32_t
+blackfin_gen_load32pi (enum core_regnum dest, enum core_regnum base)
+{
+ return gen_ldst (dest, base, 0, 0, 0);
+}
+
+uint32_t
+blackfin_gen_store32pi (enum core_regnum base, enum core_regnum src)
+{
+ return gen_ldst (src, base, 0, 1, 0);
+}
+
+uint32_t
+blackfin_gen_load16zpi (enum core_regnum dest, enum core_regnum base)
+{
+ return gen_ldst (dest, base, 0, 0, 1);
+}
+
+uint32_t
+blackfin_gen_store16pi (enum core_regnum base, enum core_regnum src)
+{
+ return gen_ldst (src, base, 0, 1, 1);
+}
+
+uint32_t
+blackfin_gen_load8zpi (enum core_regnum dest, enum core_regnum base)
+{
+ return gen_ldst (dest, base, 0, 0, 2);
+}
+
+uint32_t
+blackfin_gen_store8pi (enum core_regnum base, enum core_regnum src)
+{
+ return gen_ldst (src, base, 0, 1, 2);
+}
+
+uint32_t
+blackfin_gen_load32 (enum core_regnum dest, enum core_regnum base)
+{
+ return gen_ldst (dest, base, 2, 0, 0);
+}
+
+uint32_t
+blackfin_gen_store32 (enum core_regnum base, enum core_regnum src)
+{
+ return gen_ldst (src, base, 2, 1, 0);
+}
+
+uint32_t
+blackfin_gen_load16z (enum core_regnum dest, enum core_regnum base)
+{
+ return gen_ldst (dest, base, 2, 0, 1);
+}
+
+uint32_t
+blackfin_gen_store16 (enum core_regnum base, enum core_regnum src)
+{
+ return gen_ldst (src, base, 2, 1, 1);
+}
+
+uint32_t
+blackfin_gen_load8z (enum core_regnum dest, enum core_regnum base)
+{
+ return gen_ldst (dest, base, 2, 0, 2);
+}
+
+uint32_t
+blackfin_gen_store8 (enum core_regnum base, enum core_regnum src)
+{
+ return gen_ldst (src, base, 2, 1, 2);
+}
+
+/* op
+ 0 prefetch
+ 1 flushinv
+ 2 flush
+ 3 iflush */
+static uint32_t
+gen_flush_insn (enum core_regnum addr, int op, int post_modify)
+{
+ uint32_t insn;
+
+ insn = 0x0240;
+ insn |= addr & 0xf;
+ insn |= op << 3;
+ insn |= post_modify << 5;
+
+ return insn;
+}
+
+uint32_t
+blackfin_gen_iflush (enum core_regnum addr)
+{
+ return gen_flush_insn (addr, 3, 0);
+}
+
+uint32_t
+blackfin_gen_iflush_pm (enum core_regnum addr)
+{
+ return gen_flush_insn (addr, 3, 1);
+}
+
+uint32_t
+blackfin_gen_flush (enum core_regnum addr)
+{
+ return gen_flush_insn (addr, 2, 0);
+}
+
+uint32_t
+blackfin_gen_flush_pm (enum core_regnum addr)
+{
+ return gen_flush_insn (addr, 2, 1);
+}
+
+uint32_t
+blackfin_gen_flushinv (enum core_regnum addr)
+{
+ return gen_flush_insn (addr, 1, 0);
+}
+
+uint32_t
+blackfin_gen_flushinv_pm (enum core_regnum addr)
+{
+ return gen_flush_insn (addr, 1, 1);
+}
+
+uint32_t
+blackfin_gen_prefetch (enum core_regnum addr)
+{
+ return gen_flush_insn (addr, 0, 0);
+}
+
+uint32_t
+blackfin_gen_prefetch_pm (enum core_regnum addr)
+{
+ return gen_flush_insn (addr, 0, 1);
+}
+
+uint32_t
+blackfin_gen_jump_reg (enum core_regnum addr)
+{
+ uint32_t insn;
+
+ insn = 0x0050;
+ insn |= addr & 0x7;
+
+ return insn;
+}
+
+uint32_t blackfin_gen_add_dreg_imm7 (enum core_regnum reg, int32_t imm7)
+{
+ uint32_t insn;
+
+ insn = 0x6400;
+ insn |= reg & 0x7;
+ insn |= (imm7 & 0x7f) << 3;
+
+ return insn;
+}
+
+uint32_t blackfin_gen_add_preg_imm7 (enum core_regnum reg, int32_t imm7)
+{
+ uint32_t insn;
+
+ insn = 0x6c00;
+ insn |= reg & 0x7;
+ insn |= (imm7 & 0x7f) << 3;
+
+ return insn;
+}
diff --git a/src/target/blackfin_insn.h b/src/target/blackfin_insn.h
new file mode 100644
index 0000000..8b3a88d
--- /dev/null
+++ b/src/target/blackfin_insn.h
@@ -0,0 +1,94 @@
+/***************************************************************************
+ * Copyright (C) 2011 by Analog Devices, Inc. *
+ * Written by Jie Zhang <***@analog.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 BLACKFIN_INSN_H
+#define BLACKFIN_INSN_H
+
+/* High-Nibble: group code, low nibble: register code. */
+#define T_REG_R 0x00
+#define T_REG_P 0x10
+#define T_REG_I 0x20
+#define T_REG_B 0x30
+#define T_REG_L 0x34
+#define T_REG_M 0x24
+#define T_REG_A 0x40
+
+enum core_regnum
+{
+ REG_R0 = T_REG_R, REG_R1, REG_R2, REG_R3, REG_R4, REG_R5, REG_R6, REG_R7,
+ REG_P0 = T_REG_P, REG_P1, REG_P2, REG_P3, REG_P4, REG_P5, REG_SP, REG_FP,
+ REG_I0 = T_REG_I, REG_I1, REG_I2, REG_I3,
+ REG_M0 = T_REG_M, REG_M1, REG_M2, REG_M3,
+ REG_B0 = T_REG_B, REG_B1, REG_B2, REG_B3,
+ REG_L0 = T_REG_L, REG_L1, REG_L2, REG_L3,
+ REG_A0x = T_REG_A, REG_A0w, REG_A1x, REG_A1w,
+ REG_ASTAT = 0x46,
+ REG_RETS = 0x47,
+ REG_LC0 = 0x60, REG_LT0, REG_LB0, REG_LC1, REG_LT1, REG_LB1,
+ REG_CYCLES, REG_CYCLES2,
+ REG_USP = 0x70, REG_SEQSTAT, REG_SYSCFG,
+ REG_RETI, REG_RETX, REG_RETN, REG_RETE, REG_EMUDAT,
+};
+
+#define CLASS_MASK 0xf0
+#define GROUP(x) (((x) & CLASS_MASK) >> 4)
+#define DREG_P(x) (((x) & CLASS_MASK) == T_REG_R)
+#define PREG_P(x) (((x) & CLASS_MASK) == T_REG_P)
+
+#define BLACKFIN_INSN_NOP 0x0000
+#define BLACKFIN_INSN_RTE 0x0014
+#define BLACKFIN_INSN_CSYNC 0x0023
+#define BLACKFIN_INSN_SSYNC 0x0024
+#define BLACKFIN_INSN_ILLEGAL 0xffffffff
+
+uint32_t blackfin_gen_move (enum core_regnum dest, enum core_regnum src);
+uint32_t blackfin_gen_load32_offset (enum core_regnum dest, enum core_regnum base, int32_t offset);
+uint32_t blackfin_gen_store32_offset (enum core_regnum base, int32_t offset, enum core_regnum src);
+uint32_t blackfin_gen_load16z_offset (enum core_regnum dest, enum core_regnum base, int32_t offset);
+uint32_t blackfin_gen_store16_offset (enum core_regnum base, int32_t offset, enum core_regnum src);
+uint32_t blackfin_gen_load8z_offset (enum core_regnum dest, enum core_regnum base, int32_t offset);
+uint32_t blackfin_gen_store8_offset (enum core_regnum base, int32_t offset, enum core_regnum src);
+uint32_t blackfin_gen_load32pi (enum core_regnum dest, enum core_regnum base);
+uint32_t blackfin_gen_store32pi (enum core_regnum base, enum core_regnum src);
+uint32_t blackfin_gen_load16zpi (enum core_regnum dest, enum core_regnum base);
+uint32_t blackfin_gen_store16pi (enum core_regnum base, enum core_regnum src);
+uint32_t blackfin_gen_load8zpi (enum core_regnum dest, enum core_regnum base);
+uint32_t blackfin_gen_store8pi (enum core_regnum base, enum core_regnum src);
+uint32_t blackfin_gen_load32 (enum core_regnum dest, enum core_regnum base);
+uint32_t blackfin_gen_store32 (enum core_regnum base, enum core_regnum src);
+uint32_t blackfin_gen_load16z (enum core_regnum dest, enum core_regnum base);
+uint32_t blackfin_gen_store16 (enum core_regnum base, enum core_regnum src);
+uint32_t blackfin_gen_load8z (enum core_regnum dest, enum core_regnum base);
+uint32_t blackfin_gen_store8 (enum core_regnum base, enum core_regnum src);
+uint32_t blackfin_gen_iflush (enum core_regnum addr);
+uint32_t blackfin_gen_iflush_pm (enum core_regnum addr);
+uint32_t blackfin_gen_flush (enum core_regnum addr);
+uint32_t blackfin_gen_flush_pm (enum core_regnum addr);
+uint32_t blackfin_gen_flushinv (enum core_regnum addr);
+uint32_t blackfin_gen_flushinv_pm (enum core_regnum addr);
+uint32_t blackfin_gen_prefetch (enum core_regnum addr);
+uint32_t blackfin_gen_prefetch_pm (enum core_regnum addr);
+uint32_t blackfin_gen_jump_reg (enum core_regnum addr);
+
+uint32_t blackfin_gen_add_dreg_imm7 (enum core_regnum reg, int32_t imm7);
+uint32_t blackfin_gen_add_preg_imm7 (enum core_regnum reg, int32_t imm7);
+
+#endif /* BLACKFIN_INSN_H */
diff --git a/src/target/blackfin_jtag.c b/src/target/blackfin_jtag.c
new file mode 100644
index 0000000..3b62034
--- /dev/null
+++ b/src/target/blackfin_jtag.c
@@ -0,0 +1,1011 @@
+/***************************************************************************
+ * Copyright (C) 2011 by Analog Devices, Inc. *
+ * Written by Jie Zhang <***@analog.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 <assert.h>
+#include <time.h>
+
+#include "helper/binarybuffer.h"
+#include "jtag/jtag.h"
+
+#include "blackfin.h"
+#include "blackfin_jtag.h"
+#include "blackfin_mem.h"
+
+/* tap instructions */
+#define BLACKFIN_IDCODE 0x02
+#define BLACKFIN_DBGCTL 0x04
+#define BLACKFIN_EMUIR 0x08
+#define BLACKFIN_DBGSTAT 0x0c
+#define BLACKFIN_EMUDAT 0x14
+#define BLACKFIN_EMUPC 0x1e
+#define BLACKFIN_BYPASS 0x1f
+
+static struct {
+ uint16_t dbgctl_sram_init;
+ uint16_t dbgctl_wakeup;
+ uint16_t dbgctl_sysrst;
+ uint16_t dbgctl_esstep;
+ uint16_t dbgctl_emudatsz_32;
+ uint16_t dbgctl_emudatsz_40;
+ uint16_t dbgctl_emudatsz_48;
+ uint16_t dbgctl_emudatsz_mask;
+ uint16_t dbgctl_emuirlpsz_2;
+ uint16_t dbgctl_emuirsz_64;
+ uint16_t dbgctl_emuirsz_48;
+ uint16_t dbgctl_emuirsz_32;
+ uint16_t dbgctl_emuirsz_mask;
+ uint16_t dbgctl_empen;
+ uint16_t dbgctl_emeen;
+ uint16_t dbgctl_emfen;
+ uint16_t dbgctl_empwr;
+
+ uint16_t dbgstat_lpdec1;
+ uint16_t dbgstat_core_fault;
+ uint16_t dbgstat_idle;
+ uint16_t dbgstat_in_reset;
+ uint16_t dbgstat_lpdec0;
+ uint16_t dbgstat_bist_done;
+ uint16_t dbgstat_emucause_mask;
+ uint16_t dbgstat_emuack;
+ uint16_t dbgstat_emuready;
+ uint16_t dbgstat_emudiovf;
+ uint16_t dbgstat_emudoovf;
+ uint16_t dbgstat_emudif;
+ uint16_t dbgstat_emudof;
+} bits = {
+ 0x1000, /* DBGCTL_SRAM_INIT */
+ 0x0800, /* DBGCTL_WAKEUP */
+ 0x0400, /* DBGCTL_SYSRST */
+ 0x0200, /* DBGCTL_ESSTEP */
+ 0x0000, /* DBGCTL_EMUDATSZ_32 */
+ 0x0080, /* DBGCTL_EMUDATSZ_40 */
+ 0x0100, /* DBGCTL_EMUDATSZ_48 */
+ 0x0180, /* DBGCTL_EMUDATSZ_MASK */
+ 0x0040, /* DBGCTL_EMUIRLPSZ_2 */
+ 0x0000, /* DBGCTL_EMUIRSZ_64 */
+ 0x0010, /* DBGCTL_EMUIRSZ_48 */
+ 0x0020, /* DBGCTL_EMUIRSZ_32 */
+ 0x0030, /* DBGCTL_EMUIRSZ_MASK */
+ 0x0008, /* DBGCTL_EMPEN */
+ 0x0004, /* DBGCTL_EMEEN */
+ 0x0002, /* DBGCTL_EMFEN */
+ 0x0001, /* DBGCTL_EMPWR */
+
+ 0x8000, /* DBGSTAT_LPDEC1 */
+ 0x4000, /* DBGSTAT_CORE_FAULT */
+ 0x2000, /* DBGSTAT_IDLE */
+ 0x1000, /* DBGSTAT_IN_RESET */
+ 0x0800, /* DBGSTAT_LPDEC0 */
+ 0x0400, /* DBGSTAT_BIST_DONE */
+ 0x03c0, /* DBGSTAT_EMUCAUSE_MASK */
+ 0x0020, /* DBGSTAT_EMUACK */
+ 0x0010, /* DBGSTAT_EMUREADY */
+ 0x0008, /* DBGSTAT_EMUDIOVF */
+ 0x0004, /* DBGSTAT_EMUDOOVF */
+ 0x0002, /* DBGSTAT_EMUDIF */
+ 0x0001, /* DBGSTAT_EMUDOF */
+};
+
+#define SWRST 0xffc00100
+
+#define WPIACTL 0xffe07000
+#define WPIACTL_WPAND 0x02000000
+#define WPIACTL_EMUSW5 0x01000000
+#define WPIACTL_EMUSW4 0x00800000
+#define WPIACTL_WPICNTEN5 0x00400000
+#define WPIACTL_WPICNTEN4 0x00200000
+#define WPIACTL_WPIAEN5 0x00100000
+#define WPIACTL_WPIAEN4 0x00080000
+#define WPIACTL_WPIRINV45 0x00040000
+#define WPIACTL_WPIREN45 0x00020000
+#define WPIACTL_EMUSW3 0x00010000
+#define WPIACTL_EMUSW2 0x00008000
+#define WPIACTL_WPICNTEN3 0x00004000
+#define WPIACTL_WPICNTEN2 0x00002000
+#define WPIACTL_WPIAEN3 0x00001000
+#define WPIACTL_WPIAEN2 0x00000800
+#define WPIACTL_WPIRINV23 0x00000400
+#define WPIACTL_WPIREN23 0x00000200
+#define WPIACTL_EMUSW1 0x00000100
+#define WPIACTL_EMUSW0 0x00000080
+#define WPIACTL_WPICNTEN1 0x00000040
+#define WPIACTL_WPICNTEN0 0x00000020
+#define WPIACTL_WPIAEN1 0x00000010
+#define WPIACTL_WPIAEN0 0x00000008
+#define WPIACTL_WPIRINV01 0x00000004
+#define WPIACTL_WPIREN01 0x00000002
+#define WPIACTL_WPPWR 0x00000001
+#define WPIA0 0xffe07040
+
+#define WPDACTL 0xffe07100
+#define WPDACTL_WPDACC1_R 0x00002000
+#define WPDACTL_WPDACC1_W 0x00001000
+#define WPDACTL_WPDACC1_A 0x00003000
+#define WPDACTL_WPDSRC1_1 0x00000800
+#define WPDACTL_WPDSRC1_0 0x00000400
+#define WPDACTL_WPDSRC1_A 0x00000c00
+#define WPDACTL_WPDACC0_R 0x00000200
+#define WPDACTL_WPDACC0_W 0x00000100
+#define WPDACTL_WPDACC0_A 0x00000300
+#define WPDACTL_WPDSRC0_1 0x00000080
+#define WPDACTL_WPDSRC0_0 0x00000040
+#define WPDACTL_WPDSRC0_A 0x000000c0
+#define WPDACTL_WPDCNTEN1 0x00000020
+#define WPDACTL_WPDCNTEN0 0x00000010
+#define WPDACTL_WPDAEN1 0x00000008
+#define WPDACTL_WPDAEN0 0x00000004
+#define WPDACTL_WPDRINV01 0x00000002
+#define WPDACTL_WPDREN01 0x00000001
+#define WPDA0 0xffe07140
+
+#define WPSTAT 0xffe07200
+
+static void buf_set(void *_buffer, unsigned first, unsigned num, uint32_t value)
+{
+ buf_set_u32(_buffer, first, num, flip_u32(value, num));
+}
+
+static uint32_t buf_get(const void *_buffer, unsigned first, unsigned num)
+{
+ return flip_u32(buf_get_u32(_buffer, first, num), num);
+}
+
+/* Force moving from Pause-DR to Shift-DR to go through Capture-DR.
+ Otherwise, it will go Exit2-DR, Shift-DR. Similar for IR scan.
+
+ The code is copied from arm11_dbgtap.c. We should move it to generic
+ code. */
+
+static const tap_state_t blackfin_move_pi_to_si_via_ci[] =
+{
+ TAP_IREXIT2, TAP_IRUPDATE, TAP_DRSELECT, TAP_IRSELECT, TAP_IRCAPTURE, TAP_IRSHIFT
+};
+
+static void blackfin_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(blackfin_move_pi_to_si_via_ci), blackfin_move_pi_to_si_via_ci);
+
+ jtag_add_ir_scan(tap, fields, state);
+}
+
+static const tap_state_t blackfin_move_pd_to_sd_via_cd[] =
+{
+ TAP_DREXIT2, TAP_DRUPDATE, TAP_DRSELECT, TAP_DRCAPTURE, TAP_DRSHIFT
+};
+
+void blackfin_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(blackfin_move_pd_to_sd_via_cd), blackfin_move_pd_to_sd_via_cd);
+
+ jtag_add_dr_scan(tap, num_fields, fields, state);
+}
+
+static void blackfin_add_wait_clocks(void)
+{
+ jtag_add_clocks(blackfin_wait_clocks);
+}
+
+void blackfin_set_instr(struct blackfin_jtag *jtag_info, uint8_t new_instr)
+{
+ struct jtag_tap *tap;
+
+ tap = jtag_info->target->tap;
+ assert(tap != NULL);
+
+ if (buf_get_u32(tap->cur_instr, 0, tap->ir_length) != 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;
+
+ blackfin_add_ir_scan_vc(tap, &field, TAP_IRPAUSE);
+ }
+}
+
+#define BLACKFIN_DBGCTL_BIT_SET(name) \
+ void blackfin_dbgctl_bit_set_##name(struct blackfin_jtag *jtag_info) \
+ { \
+ jtag_info->dbgctl |= bits.dbgctl_##name; \
+ }
+
+#define BLACKFIN_DBGCTL_BIT_CLEAR(name) \
+ void blackfin_dbgctl_bit_clear_##name(struct blackfin_jtag *jtag_info) \
+ { \
+ jtag_info->dbgctl &= ~bits.dbgctl_##name; \
+ }
+
+#define BLACKFIN_DBGCTL_IS(name) \
+ bool blackfin_dbgctl_is_##name(struct blackfin_jtag *jtag_info) \
+ { \
+ if (jtag_info->dbgctl & bits.dbgctl_##name) \
+ return true; \
+ else \
+ return false; \
+ }
+
+#define BLACKFIN_DBGCTL_BIT_OP(name) \
+ BLACKFIN_DBGCTL_BIT_SET(name) \
+ BLACKFIN_DBGCTL_BIT_CLEAR(name) \
+ BLACKFIN_DBGCTL_IS(name)
+
+BLACKFIN_DBGCTL_BIT_OP(sram_init)
+BLACKFIN_DBGCTL_BIT_OP(wakeup)
+BLACKFIN_DBGCTL_BIT_OP(sysrst)
+BLACKFIN_DBGCTL_BIT_OP(esstep)
+BLACKFIN_DBGCTL_BIT_OP(emudatsz_32)
+BLACKFIN_DBGCTL_BIT_OP(emudatsz_40)
+BLACKFIN_DBGCTL_BIT_OP(emudatsz_48)
+BLACKFIN_DBGCTL_BIT_OP(emuirlpsz_2)
+BLACKFIN_DBGCTL_BIT_OP(emuirsz_64)
+BLACKFIN_DBGCTL_BIT_OP(emuirsz_48)
+BLACKFIN_DBGCTL_BIT_OP(emuirsz_32)
+BLACKFIN_DBGCTL_BIT_OP(empen)
+BLACKFIN_DBGCTL_BIT_OP(emeen)
+BLACKFIN_DBGCTL_BIT_OP(emfen)
+BLACKFIN_DBGCTL_BIT_OP(empwr)
+
+#define BLACKFIN_DBGSTAT_BIT_IS(name) \
+ bool blackfin_dbgstat_is_##name(struct blackfin_jtag *jtag_info) \
+ { \
+ if (jtag_info->dbgstat & bits.dbgstat_##name) \
+ return true; \
+ else \
+ return false; \
+ }
+
+BLACKFIN_DBGSTAT_BIT_IS(lpdec1)
+BLACKFIN_DBGSTAT_BIT_IS(core_fault)
+BLACKFIN_DBGSTAT_BIT_IS(idle)
+BLACKFIN_DBGSTAT_BIT_IS(in_reset)
+BLACKFIN_DBGSTAT_BIT_IS(lpdec0)
+BLACKFIN_DBGSTAT_BIT_IS(bist_done)
+BLACKFIN_DBGSTAT_BIT_IS(emuack)
+BLACKFIN_DBGSTAT_BIT_IS(emuready)
+BLACKFIN_DBGSTAT_BIT_IS(emudiovf)
+BLACKFIN_DBGSTAT_BIT_IS(emudoovf)
+BLACKFIN_DBGSTAT_BIT_IS(emudif)
+BLACKFIN_DBGSTAT_BIT_IS(emudof)
+
+static void blackfin_shift_dbgctl(struct blackfin_jtag *jtag_info, int state)
+{
+ struct scan_field field;
+ uint8_t t[4];
+
+ LOG_DEBUG("shift DBGCTL = %04x end state is %s", (unsigned) jtag_info->dbgctl, tap_state_name(state));
+
+ field.num_bits = 16;
+ field.out_value = t;
+ buf_set(t, 0, field.num_bits, jtag_info->dbgctl);
+ field.in_value = NULL;
+ blackfin_add_dr_scan_vc(jtag_info->target->tap, 1, &field, state);
+
+ if (state == TAP_IDLE)
+ blackfin_add_wait_clocks();
+}
+
+static void blackfin_emuir_setup_field(struct scan_field *field, uint8_t *t, uint32_t insn)
+{
+ if ((insn & 0xffff0000) == 0)
+ insn <<= 16;
+
+ field->num_bits = 32;
+ field->out_value = t;
+ buf_set(t, 0, field->num_bits, insn);
+ field->in_value = NULL;
+}
+
+void blackfin_emuir_set(struct blackfin_jtag *jtag_info, uint32_t insn, int state)
+{
+ struct scan_field field;
+ uint8_t t[4];
+
+ /* If the EMUIRLPSZ_2 is set in DBGCTL, clear it. */
+ if (blackfin_dbgctl_is_emuirlpsz_2(jtag_info))
+ {
+ blackfin_set_instr(jtag_info, BLACKFIN_DBGCTL);
+ blackfin_dbgctl_bit_clear_emuirlpsz_2(jtag_info);
+ blackfin_shift_dbgctl(jtag_info, TAP_DRPAUSE);
+ }
+
+ blackfin_set_instr(jtag_info, BLACKFIN_EMUIR);
+
+ blackfin_emuir_setup_field(&field, t, insn);
+ blackfin_add_dr_scan_vc(jtag_info->target->tap, 1, &field, state);
+ jtag_info->emuir_a = insn;
+
+ if (state == TAP_IDLE)
+ blackfin_add_wait_clocks();
+}
+
+void blackfin_emuir_set_2(struct blackfin_jtag *jtag_info, uint32_t insn1, uint32_t insn2, int state)
+{
+ struct scan_field field1, field2;
+ uint8_t t[4];
+
+ /* If the EMUIRLPSZ_2 is clear in DBGCTL, set it. */
+ if (!blackfin_dbgctl_is_emuirlpsz_2(jtag_info))
+ {
+ blackfin_set_instr(jtag_info, BLACKFIN_DBGCTL);
+ blackfin_dbgctl_bit_set_emuirlpsz_2(jtag_info);
+ blackfin_shift_dbgctl(jtag_info, TAP_DRPAUSE);
+ }
+
+ blackfin_set_instr(jtag_info, BLACKFIN_EMUIR);
+
+ blackfin_emuir_setup_field(&field2, t, insn2);
+ blackfin_add_dr_scan_vc(jtag_info->target->tap, 1, &field2, TAP_DRPAUSE);
+ jtag_info->emuir_b = insn2;
+
+ blackfin_emuir_setup_field(&field1, t, insn1);
+ blackfin_add_dr_scan_vc(jtag_info->target->tap, 1, &field1, state);
+ jtag_info->emuir_a = insn1;
+
+ if (state == TAP_IDLE)
+ blackfin_add_wait_clocks();
+}
+
+/*
+static void blackfin_emuir_set_nop(struct blackfin_jtag *jtag_info)
+{
+ if (blackfin_dbgctl_is_emuirlpsz_2(jtag_info))
+ blackfin_emuir_set_2(jtag_info, BLACKFIN_INSN_NOP, BLACKFIN_INSN_NOP, TAP_DRPAUSE);
+ else
+ blackfin_emuir_set(jtag_info, BLACKFIN_INSN_NOP, TAP_DRPAUSE);
+}
+*/
+
+void blackfin_read_dbgstat(struct blackfin_jtag *jtag_info)
+{
+ struct scan_field field;
+ uint16_t dbgstat;
+ uint8_t t[4];
+ int retval;
+
+ blackfin_set_instr(jtag_info, BLACKFIN_DBGSTAT);
+
+ field.num_bits = 16;
+ field.out_value = NULL;
+ field.in_value = t;
+
+ blackfin_add_dr_scan_vc(jtag_info->target->tap, 1, &field, TAP_DRPAUSE);
+
+ retval = jtag_execute_queue();
+ assert(retval == ERROR_OK);
+
+ dbgstat = buf_get(t, 0, 16);
+
+ if (jtag_info->dbgstat != dbgstat)
+ LOG_DEBUG("DBGSTAT = %04x (OLD %04x)",
+ (unsigned) dbgstat,
+ (unsigned) jtag_info->dbgstat);
+
+ jtag_info->dbgstat = dbgstat;
+}
+
+uint16_t blackfin_dbgstat_emucause(struct blackfin_jtag *jtag_info)
+{
+ uint16_t mask, emucause;
+
+ mask = bits.dbgstat_emucause_mask;
+ emucause = jtag_info->dbgstat & mask;
+
+ while (!(mask & 0x1))
+ {
+ mask >>= 1;
+ emucause >>= 1;
+ }
+
+ return emucause;
+}
+
+void blackfin_wpstat_get(struct blackfin_jtag *jtag_info)
+{
+ uint32_t p0, r0;
+
+ p0 = blackfin_get_p0(jtag_info);
+ r0 = blackfin_get_r0(jtag_info);
+
+ blackfin_set_p0(jtag_info, WPSTAT);
+ blackfin_emuir_set(jtag_info, blackfin_gen_load32_offset(REG_R0, REG_P0, 0), TAP_IDLE);
+ jtag_info->wpstat = blackfin_register_get(jtag_info, REG_R0);
+
+ blackfin_set_p0(jtag_info, p0);
+ blackfin_set_r0(jtag_info, r0);
+}
+
+void blackfin_wpstat_clear(struct blackfin_jtag *jtag_info)
+{
+ uint32_t p0, r0;
+
+ p0 = blackfin_get_p0(jtag_info);
+ r0 = blackfin_get_r0(jtag_info);
+
+ blackfin_set_p0(jtag_info, WPSTAT);
+ blackfin_set_r0(jtag_info, jtag_info->wpstat);
+ blackfin_emuir_set(jtag_info, blackfin_gen_store32_offset(REG_P0, 0, REG_R0), TAP_IDLE);
+ jtag_info->wpstat = 0;
+
+ blackfin_set_p0(jtag_info, p0);
+ blackfin_set_r0(jtag_info, r0);
+}
+
+void blackfin_emulation_enable(struct blackfin_jtag *jtag_info)
+{
+ /* TODO check if emulation has already been enabled. */
+
+ blackfin_set_instr(jtag_info, BLACKFIN_DBGCTL);
+
+ blackfin_dbgctl_bit_set_empwr(jtag_info);
+ blackfin_shift_dbgctl(jtag_info, TAP_IDLE);
+
+ blackfin_dbgctl_bit_set_emfen(jtag_info);
+ blackfin_shift_dbgctl(jtag_info, TAP_IDLE);
+
+ blackfin_dbgctl_bit_set_emuirsz_32(jtag_info);
+ blackfin_shift_dbgctl(jtag_info, TAP_IDLE);
+}
+
+void blackfin_emulation_disable(struct blackfin_jtag *jtag_info)
+{
+ blackfin_set_instr(jtag_info, BLACKFIN_DBGCTL);
+ blackfin_dbgctl_bit_clear_empwr(jtag_info);
+ blackfin_shift_dbgctl(jtag_info, TAP_IDLE);
+}
+
+void blackfin_emulation_trigger(struct blackfin_jtag *jtag_info)
+{
+ /* TODO check if we have already been in emulation mode. */
+
+ blackfin_emuir_set(jtag_info, BLACKFIN_INSN_NOP, TAP_DRPAUSE);
+
+ blackfin_set_instr(jtag_info, BLACKFIN_DBGCTL);
+ blackfin_dbgctl_bit_set_wakeup(jtag_info);
+ blackfin_dbgctl_bit_set_emeen(jtag_info);
+ blackfin_shift_dbgctl(jtag_info, TAP_IDLE);
+}
+
+void blackfin_emulation_return(struct blackfin_jtag *jtag_info)
+{
+ blackfin_emuir_set(jtag_info, BLACKFIN_INSN_RTE, TAP_DRPAUSE);
+
+ blackfin_set_instr(jtag_info, BLACKFIN_DBGCTL);
+ blackfin_dbgctl_bit_clear_emeen(jtag_info);
+ blackfin_dbgctl_bit_clear_wakeup(jtag_info);
+ blackfin_shift_dbgctl(jtag_info, TAP_IDLE);
+}
+
+uint32_t blackfin_register_get(struct blackfin_jtag *jtag_info, enum core_regnum reg)
+{
+ struct scan_field field;
+ uint8_t t[4];
+ uint32_t r0 = 0;
+ int retval;
+
+ if (DREG_P(reg) || PREG_P(reg))
+ {
+ blackfin_emuir_set(jtag_info, blackfin_gen_move(REG_EMUDAT, reg), TAP_IDLE);
+ }
+ else
+ {
+ r0 = blackfin_get_r0(jtag_info);
+ blackfin_emuir_set_2(jtag_info, blackfin_gen_move(REG_R0, reg), blackfin_gen_move(REG_EMUDAT, REG_R0), TAP_IDLE);
+ }
+
+ blackfin_set_instr(jtag_info, BLACKFIN_EMUDAT);
+
+ field.num_bits = 32;
+ field.out_value = NULL;
+ field.in_value = t;
+ blackfin_add_dr_scan_vc(jtag_info->target->tap, 1, &field, TAP_DRPAUSE);
+
+ retval = jtag_execute_queue();
+ assert(retval == ERROR_OK);
+
+ if (!DREG_P(reg) && !PREG_P(reg))
+ blackfin_set_r0(jtag_info, r0);
+
+ return buf_get(t, 0, 32);
+}
+
+void blackfin_register_set(struct blackfin_jtag *jtag_info, enum core_regnum reg, uint32_t value)
+{
+ struct scan_field field;
+ uint8_t t[4];
+ uint32_t r0 = 0;
+
+ if (!DREG_P(reg) && !PREG_P(reg))
+ r0 = blackfin_get_r0(jtag_info);
+
+ blackfin_set_instr(jtag_info, BLACKFIN_EMUDAT);
+
+ field.num_bits = 32;
+ field.out_value = t;
+ buf_set(t, 0, field.num_bits, value);
+ field.in_value = NULL;
+ blackfin_add_dr_scan_vc(jtag_info->target->tap, 1, &field, TAP_DRPAUSE);
+
+ if (DREG_P(reg) || PREG_P(reg))
+ {
+ blackfin_emuir_set(jtag_info, blackfin_gen_move(reg, REG_EMUDAT), TAP_IDLE);
+ }
+ else
+ {
+ blackfin_emuir_set_2(jtag_info, blackfin_gen_move(REG_R0, REG_EMUDAT), blackfin_gen_move(reg, REG_R0), TAP_IDLE);
+ blackfin_set_r0(jtag_info, r0);
+ }
+}
+
+uint32_t blackfin_get_p0(struct blackfin_jtag *jtag_info)
+{
+ return blackfin_register_get(jtag_info, REG_P0);
+}
+
+uint32_t blackfin_get_r0(struct blackfin_jtag *jtag_info)
+{
+ return blackfin_register_get(jtag_info, REG_R0);
+}
+
+void blackfin_set_p0(struct blackfin_jtag *jtag_info, uint32_t value)
+{
+ blackfin_register_set(jtag_info, REG_P0, value);
+}
+
+void blackfin_set_r0(struct blackfin_jtag *jtag_info, uint32_t value)
+{
+ blackfin_register_set(jtag_info, REG_R0, value);
+}
+
+void blackfin_check_emuready(struct blackfin_jtag *jtag_info)
+{
+ int emuready;
+
+ blackfin_read_dbgstat(jtag_info);
+ if (blackfin_dbgstat_is_emuready(jtag_info))
+ emuready = 1;
+ else
+ emuready = 0;
+
+ assert(emuready);
+}
+
+/* system reset by writing to SWRST MMR */
+void blackfin_system_reset(struct blackfin_jtag *jtag_info)
+{
+ uint32_t p0, r0;
+
+ p0 = blackfin_get_p0(jtag_info);
+ r0 = blackfin_get_r0(jtag_info);
+
+ /*
+ * Flush all system events like cache line fills. Otherwise,
+ * when we reset the system side, any events that the core was
+ * waiting on no longer exist, and the core hangs.
+ */
+ blackfin_emuir_set(jtag_info, BLACKFIN_INSN_SSYNC, TAP_IDLE);
+
+ /* Write 0x7 to SWRST to start system reset. */
+ blackfin_set_p0(jtag_info, SWRST);
+ blackfin_set_r0(jtag_info, 0x7);
+ blackfin_emuir_set(jtag_info, blackfin_gen_store16_offset(REG_P0, 0, REG_R0), TAP_IDLE);
+
+ /*
+ * Delay at least 10 SCLKs instead of doing an SSYNC insn.
+ * Since the system is being reset, the sync signal might
+ * not be asserted, and so the core hangs waiting for it.
+ * The magic "10" number was given to us by ADI designers
+ * who looked at the schematic and ran some simulations.
+ */
+ usleep(100);
+
+ /* Write 0x0 to SWRST to stop system reset. */
+ blackfin_set_r0(jtag_info, 0);
+ blackfin_emuir_set(jtag_info, blackfin_gen_store16_offset(REG_P0, 0, REG_R0), TAP_IDLE);
+
+ /* Delay at least 1 SCLK; see comment above for more info. */
+ usleep(100);
+
+ blackfin_set_p0(jtag_info, p0);
+ blackfin_set_r0(jtag_info, r0);
+}
+
+static void blackfin_wait_in_reset(struct blackfin_jtag *jtag_info)
+{
+ int in_reset;
+ int waited = 0;
+ const struct timespec reset_wait = {0, 5000000};
+
+ try_again:
+
+ blackfin_read_dbgstat(jtag_info);
+ if (blackfin_dbgstat_is_in_reset(jtag_info))
+ in_reset = 1;
+ else
+ in_reset = 0;
+
+ if (waited)
+ assert(in_reset);
+
+ if (!in_reset)
+ {
+ nanosleep (&reset_wait, NULL);
+ waited = 1;
+ goto try_again;
+ }
+}
+
+static void blackfin_wait_reset(struct blackfin_jtag *jtag_info)
+{
+ int in_reset;
+ int waited = 0;
+ const struct timespec reset_wait = {0, 5000000};
+
+ try_again:
+
+ blackfin_read_dbgstat(jtag_info);
+ if (blackfin_dbgstat_is_in_reset(jtag_info))
+ in_reset = 1;
+ else
+ in_reset = 0;
+
+ if (waited)
+ assert(!in_reset);
+
+ if (in_reset)
+ {
+ nanosleep (&reset_wait, NULL);
+ waited = 1;
+ goto try_again;
+ }
+}
+
+/* core reset by setting SYSRST bit in DBGCTL */
+void blackfin_core_reset(struct blackfin_jtag *jtag_info)
+{
+ blackfin_emulation_disable(jtag_info);
+
+ blackfin_emuir_set(jtag_info, BLACKFIN_INSN_NOP, TAP_DRPAUSE);
+
+ blackfin_set_instr(jtag_info, BLACKFIN_DBGCTL);
+ blackfin_dbgctl_bit_set_sram_init(jtag_info);
+ blackfin_dbgctl_bit_set_sysrst(jtag_info);
+ blackfin_shift_dbgctl(jtag_info, TAP_IDLE);
+
+ blackfin_wait_in_reset(jtag_info);
+
+ blackfin_set_instr(jtag_info, BLACKFIN_DBGCTL);
+ blackfin_dbgctl_bit_clear_sysrst(jtag_info);
+ blackfin_shift_dbgctl(jtag_info, TAP_IDLE);
+
+ blackfin_wait_reset(jtag_info);
+
+ blackfin_emulation_enable(jtag_info);
+ blackfin_emulation_trigger(jtag_info);
+
+ blackfin_set_instr(jtag_info, BLACKFIN_DBGCTL);
+ blackfin_dbgctl_bit_clear_sram_init(jtag_info);
+ blackfin_shift_dbgctl(jtag_info, TAP_IDLE);
+}
+
+void blackfin_emupc_get(struct blackfin_jtag *jtag_info)
+{
+ struct scan_field field;
+ uint8_t t[4];
+ uint32_t value;
+ int retval;
+
+ blackfin_set_instr(jtag_info, BLACKFIN_EMUPC);
+
+ field.num_bits = 32;
+ field.out_value = NULL;
+ field.in_value = t;
+
+ blackfin_add_dr_scan_vc(jtag_info->target->tap, 1, &field, TAP_DRPAUSE);
+
+ retval = jtag_execute_queue();
+ assert(retval == ERROR_OK);
+
+ value = buf_get(t, 0, field.num_bits);
+ jtag_info->emupc = value;
+}
+
+void blackfin_emupc_reset(struct blackfin_jtag *jtag_info)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(jtag_info->target);
+ uint32_t p0;
+
+ p0 = blackfin_get_p0(jtag_info);
+ blackfin_set_p0(jtag_info, blackfin->l1_map->l1_code);
+ blackfin_emuir_set(jtag_info, blackfin_gen_jump_reg(REG_P0), TAP_IDLE);
+ blackfin_set_p0(jtag_info, p0);
+}
+
+void blackfin_emudat_set(struct blackfin_jtag *jtag_info, uint32_t value, tap_state_t state)
+{
+ struct scan_field field;
+ uint8_t t[4];
+
+ blackfin_set_instr(jtag_info, BLACKFIN_EMUDAT);
+
+ field.num_bits = 32;
+ field.out_value = t;
+ buf_set(t, 0, field.num_bits, value);
+ field.in_value = NULL;
+
+ blackfin_add_dr_scan_vc(jtag_info->target->tap, 1, &field, state);
+ jtag_info->emudat_in = value;
+
+ if (state == TAP_IDLE)
+ blackfin_add_wait_clocks();
+}
+
+uint32_t blackfin_emudat_get(struct blackfin_jtag *jtag_info, tap_state_t state)
+{
+ struct scan_field field;
+ uint8_t t[4];
+ uint32_t value;
+ const uint8_t seq = 0;
+ int retval;
+
+ if (state == TAP_IDLE)
+ {
+ if (cmd_queue_cur_state != TAP_RESET && cmd_queue_cur_state != TAP_IDLE)
+ jtag_add_statemove(TAP_IDLE);
+ else
+ jtag_add_tms_seq(1, &seq, TAP_IDLE);
+
+ blackfin_add_wait_clocks();
+ }
+
+ blackfin_set_instr(jtag_info, BLACKFIN_EMUDAT);
+
+ field.num_bits = 32;
+ field.out_value = NULL;
+ field.in_value = t;
+
+ blackfin_add_dr_scan_vc(jtag_info->target->tap, 1, &field, TAP_DRPAUSE);
+
+ retval = jtag_execute_queue();
+ assert(retval == ERROR_OK);
+
+ value = buf_get(t, 0, field.num_bits);
+ jtag_info->emudat_out = value;
+
+ return value;
+}
+
+void blackfin_wpu_init(struct blackfin_jtag *jtag_info)
+{
+ uint32_t p0, r0;
+ uint32_t wpiactl, wpdactl;
+
+ LOG_DEBUG("-");
+
+ p0 = blackfin_get_p0(jtag_info);
+ r0 = blackfin_get_r0(jtag_info);
+
+ blackfin_set_p0(jtag_info, WPIACTL);
+
+ wpiactl = WPIACTL_WPPWR;
+
+ blackfin_set_r0(jtag_info, wpiactl);
+
+ blackfin_emuir_set(jtag_info, blackfin_gen_store32_offset(REG_P0, 0, REG_R0), TAP_IDLE);
+
+ wpiactl |= WPIACTL_EMUSW5 | WPIACTL_EMUSW4 | WPIACTL_EMUSW3;
+ wpiactl |= WPIACTL_EMUSW2 | WPIACTL_EMUSW1 | WPIACTL_EMUSW0;
+
+ blackfin_set_r0(jtag_info, wpiactl);
+ blackfin_emuir_set(jtag_info, blackfin_gen_store32_offset(REG_P0, 0, REG_R0), TAP_IDLE);
+
+ wpdactl = WPDACTL_WPDSRC1_A | WPDACTL_WPDSRC0_A;
+
+ blackfin_set_r0(jtag_info, wpdactl);
+ blackfin_emuir_set(jtag_info, blackfin_gen_store32_offset(REG_P0, WPDACTL - WPIACTL, REG_R0),
+ TAP_IDLE);
+
+ blackfin_set_r0(jtag_info, 0);
+ blackfin_emuir_set(jtag_info, blackfin_gen_store32_offset(REG_P0, WPSTAT - WPIACTL, REG_R0),
+ TAP_IDLE);
+
+ jtag_info->wpiactl = wpiactl;
+ jtag_info->wpdactl = wpdactl;
+
+ blackfin_set_p0(jtag_info, p0);
+ blackfin_set_r0(jtag_info, r0);
+}
+
+static uint32_t wpiaen[] = {
+ WPIACTL_WPIAEN0,
+ WPIACTL_WPIAEN1,
+ WPIACTL_WPIAEN2,
+ WPIACTL_WPIAEN3,
+ WPIACTL_WPIAEN4,
+ WPIACTL_WPIAEN5,
+};
+
+void blackfin_wpu_set_wpia(struct blackfin_jtag *jtag_info, int n, uint32_t addr, int enable)
+{
+ uint32_t p0, r0;
+
+ p0 = blackfin_get_p0(jtag_info);
+ r0 = blackfin_get_r0(jtag_info);
+
+ blackfin_register_set(jtag_info, REG_P0, WPIACTL);
+ if (enable)
+ {
+ jtag_info->wpiactl += wpiaen[n];
+ blackfin_register_set(jtag_info, REG_R0, addr);
+ blackfin_emuir_set(jtag_info,
+ blackfin_gen_store32_offset(REG_P0, WPIA0 + 4 * n - WPIACTL, REG_R0),
+ TAP_IDLE);
+ }
+ else
+ {
+ jtag_info->wpiactl &= ~wpiaen[n];
+ }
+
+ blackfin_register_set(jtag_info, REG_R0, jtag_info->wpiactl);
+ blackfin_emuir_set(jtag_info,
+ blackfin_gen_store32_offset(REG_P0, 0, REG_R0),
+ TAP_IDLE);
+
+ blackfin_set_p0(jtag_info, p0);
+ blackfin_set_r0(jtag_info, r0);
+}
+
+void blackfin_wpu_set_wpda(struct blackfin_jtag *jtag_info, int n)
+{
+ uint32_t p0, r0;
+ uint32_t addr = jtag_info->hwwps[n].addr;
+ uint32_t len = jtag_info->hwwps[n].len;
+ int mode = jtag_info->hwwps[n].mode;
+ bool range = jtag_info->hwwps[n].range;
+
+ p0 = blackfin_get_p0(jtag_info);
+ r0 = blackfin_get_r0(jtag_info);
+
+ blackfin_register_set(jtag_info, REG_P0, WPDACTL);
+
+ /* Currently LEN > 4 iff RANGE. But in future, it can change. */
+ if (len > 4 || range)
+ {
+ assert (n == 0);
+
+ switch (mode)
+ {
+ case WPDA_DISABLE:
+ jtag_info->wpdactl &= ~WPDACTL_WPDREN01;
+ break;
+ case WPDA_WRITE:
+ jtag_info->wpdactl &= ~WPDACTL_WPDACC0_R;
+ jtag_info->wpdactl |= WPDACTL_WPDREN01 | WPDACTL_WPDACC0_W;
+ break;
+ case WPDA_READ:
+ jtag_info->wpdactl &= ~WPDACTL_WPDACC0_W;
+ jtag_info->wpdactl |= WPDACTL_WPDREN01 | WPDACTL_WPDACC0_R;
+ break;
+ case WPDA_ALL:
+ jtag_info->wpdactl |= WPDACTL_WPDREN01 | WPDACTL_WPDACC0_A;
+ break;
+ default:
+ abort ();
+ }
+
+ if (mode != WPDA_DISABLE)
+ {
+ blackfin_register_set(jtag_info, REG_R0, addr - 1);
+ blackfin_emuir_set(jtag_info,
+ blackfin_gen_store32_offset(REG_P0, WPDA0 - WPDACTL, REG_R0),
+ TAP_IDLE);
+ blackfin_register_set(jtag_info, REG_R0, addr + len - 1);
+ blackfin_emuir_set(jtag_info,
+ blackfin_gen_store32_offset(REG_P0, WPDA0 + 4 - WPDACTL, REG_R0),
+ TAP_IDLE);
+ }
+ }
+ else
+ {
+ if (n == 0)
+ switch (mode)
+ {
+ case WPDA_DISABLE:
+ jtag_info->wpdactl &= ~WPDACTL_WPDAEN0;
+ break;
+ case WPDA_WRITE:
+ jtag_info->wpdactl &= ~WPDACTL_WPDACC0_R;
+ jtag_info->wpdactl |= WPDACTL_WPDAEN0 | WPDACTL_WPDACC0_W;
+ break;
+ case WPDA_READ:
+ jtag_info->wpdactl &= ~WPDACTL_WPDACC0_W;
+ jtag_info->wpdactl |= WPDACTL_WPDAEN0 | WPDACTL_WPDACC0_R;
+ break;
+ case WPDA_ALL:
+ jtag_info->wpdactl |= WPDACTL_WPDAEN0 | WPDACTL_WPDACC0_A;
+ break;
+ default:
+ abort ();
+ }
+ else
+ switch (mode)
+ {
+ case WPDA_DISABLE:
+ jtag_info->wpdactl &= ~WPDACTL_WPDAEN1;
+ break;
+ case WPDA_WRITE:
+ jtag_info->wpdactl &= ~WPDACTL_WPDACC1_R;
+ jtag_info->wpdactl |= WPDACTL_WPDAEN1 | WPDACTL_WPDACC1_W;
+ break;
+ case WPDA_READ:
+ jtag_info->wpdactl &= ~WPDACTL_WPDACC1_W;
+ jtag_info->wpdactl |= WPDACTL_WPDAEN1 | WPDACTL_WPDACC1_R;
+ break;
+ case WPDA_ALL:
+ jtag_info->wpdactl |= WPDACTL_WPDAEN1 | WPDACTL_WPDACC1_A;
+ break;
+ default:
+ abort ();
+ }
+ if (mode != WPDA_DISABLE)
+ {
+ blackfin_register_set(jtag_info, REG_R0, addr);
+ blackfin_emuir_set(jtag_info,
+ blackfin_gen_store32_offset(REG_P0, WPDA0 + 4 * n - WPDACTL, REG_R0),
+ TAP_IDLE);
+ }
+ }
+
+ blackfin_register_set(jtag_info, REG_R0, jtag_info->wpdactl);
+ blackfin_emuir_set(jtag_info,
+ blackfin_gen_store32_offset(REG_P0, 0, REG_R0),
+ TAP_IDLE);
+
+ blackfin_set_p0(jtag_info, p0);
+ blackfin_set_r0(jtag_info, r0);
+}
+
+void blackfin_single_step(struct blackfin_jtag *jtag_info, bool in_stepping)
+{
+ if (!in_stepping)
+ {
+ blackfin_set_instr(jtag_info, BLACKFIN_DBGCTL);
+ blackfin_dbgctl_bit_set_esstep(jtag_info);
+ blackfin_shift_dbgctl(jtag_info, TAP_DRPAUSE);
+ }
+ blackfin_emuir_set(jtag_info, BLACKFIN_INSN_RTE, TAP_IDLE);
+ blackfin_check_emuready(jtag_info);
+ if (!in_stepping)
+ {
+ blackfin_set_instr(jtag_info, BLACKFIN_DBGCTL);
+ blackfin_dbgctl_bit_clear_esstep(jtag_info);
+ blackfin_shift_dbgctl(jtag_info, TAP_DRPAUSE);
+ }
+}
diff --git a/src/target/blackfin_jtag.h b/src/target/blackfin_jtag.h
new file mode 100644
index 0000000..818b997
--- /dev/null
+++ b/src/target/blackfin_jtag.h
@@ -0,0 +1,146 @@
+/***************************************************************************
+ * Copyright (C) 2011 by Analog Devices, Inc. *
+ * Written by Jie Zhang <***@analog.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 BLACKFIN_JTAG_H
+#define BLACKFIN_JTAG_H
+
+#include "jtag/jtag.h"
+#include "target.h"
+#include "blackfin_insn.h"
+
+#define WPDA_DISABLE 0
+#define WPDA_WRITE 1
+#define WPDA_READ 2
+#define WPDA_ALL 3
+
+struct blackfin_hwwpt
+{
+ uint32_t addr;
+ uint32_t len;
+ int mode;
+ /* If range is true, this hardware watchpoint is combined with the
+ next watchpoint to form a range watchpoint. */
+ bool range;
+ /* True if this hardware watchpoint has been used, otherwise false. */
+ bool used;
+};
+
+#define BLACKFIN_MAX_HWBREAKPOINTS 6
+#define BLACKFIN_MAX_HWWATCHPOINTS 2
+
+struct blackfin_jtag
+{
+ struct target *target;
+
+ uint16_t dbgctl;
+ uint16_t dbgstat;
+ uint64_t emuir_a;
+ uint64_t emuir_b;
+ uint64_t emudat_out;
+ uint64_t emudat_in;
+
+ uint32_t wpiactl;
+ uint32_t wpdactl;
+ uint32_t wpstat;
+
+ uint32_t hwbps[BLACKFIN_MAX_HWBREAKPOINTS];
+ struct blackfin_hwwpt hwwps[BLACKFIN_MAX_HWWATCHPOINTS];
+
+ uint32_t emupc;
+};
+
+extern void blackfin_set_instr(struct blackfin_jtag *, uint8_t);
+
+#define DECLARE_BLACKFIN_DBGCTL_BIT_SET(name) \
+ extern void blackfin_dbgctl_bit_set_##name(struct blackfin_jtag *);
+
+#define DECLARE_BLACKFIN_DBGCTL_BIT_CLEAR(name) \
+ extern void blackfin_dbgctl_bit_clear_##name(struct blackfin_jtag *);
+
+#define DECLARE_BLACKFIN_DBGCTL_BIT_IS(name) \
+ extern bool blackfin_dbgctl_bit_IS_##name(struct blackfin_jtag *);
+
+#define DECLARE_BLACKFIN_DBGCTL_BIT_OP(name) \
+ DECLARE_BLACKFIN_DBGCTL_BIT_SET(name) \
+ DECLARE_BLACKFIN_DBGCTL_BIT_CLEAR(name) \
+ DECLARE_BLACKFIN_DBGCTL_BIT_IS(name)
+
+DECLARE_BLACKFIN_DBGCTL_BIT_OP(sram_init)
+DECLARE_BLACKFIN_DBGCTL_BIT_OP(wakeup)
+DECLARE_BLACKFIN_DBGCTL_BIT_OP(sysrst)
+DECLARE_BLACKFIN_DBGCTL_BIT_OP(esstep)
+DECLARE_BLACKFIN_DBGCTL_BIT_OP(emudatsz_32)
+DECLARE_BLACKFIN_DBGCTL_BIT_OP(emudatsz_40)
+DECLARE_BLACKFIN_DBGCTL_BIT_OP(emudatsz_48)
+DECLARE_BLACKFIN_DBGCTL_BIT_OP(emuirlpsz_2)
+DECLARE_BLACKFIN_DBGCTL_BIT_OP(emuirsz_64)
+DECLARE_BLACKFIN_DBGCTL_BIT_OP(emuirsz_48)
+DECLARE_BLACKFIN_DBGCTL_BIT_OP(emuirsz_32)
+DECLARE_BLACKFIN_DBGCTL_BIT_OP(empen)
+DECLARE_BLACKFIN_DBGCTL_BIT_OP(emeen)
+DECLARE_BLACKFIN_DBGCTL_BIT_OP(emfen)
+DECLARE_BLACKFIN_DBGCTL_BIT_OP(empwr)
+
+#define DECLARE_BLACKFIN_DBGSTAT_BIT_IS(name) \
+ extern bool blackfin_dbgstat_is_##name(struct blackfin_jtag *);
+
+DECLARE_BLACKFIN_DBGSTAT_BIT_IS(lpdec1)
+DECLARE_BLACKFIN_DBGSTAT_BIT_IS(core_fault)
+DECLARE_BLACKFIN_DBGSTAT_BIT_IS(idle)
+DECLARE_BLACKFIN_DBGSTAT_BIT_IS(in_reset)
+DECLARE_BLACKFIN_DBGSTAT_BIT_IS(lpdec0)
+DECLARE_BLACKFIN_DBGSTAT_BIT_IS(bist_done)
+DECLARE_BLACKFIN_DBGSTAT_BIT_IS(emuack)
+DECLARE_BLACKFIN_DBGSTAT_BIT_IS(emuready)
+DECLARE_BLACKFIN_DBGSTAT_BIT_IS(emudiovf)
+DECLARE_BLACKFIN_DBGSTAT_BIT_IS(emudoovf)
+DECLARE_BLACKFIN_DBGSTAT_BIT_IS(emudif)
+DECLARE_BLACKFIN_DBGSTAT_BIT_IS(emudof)
+
+extern void blackfin_read_dbgstat(struct blackfin_jtag *);
+extern void blackfin_wpstat_get(struct blackfin_jtag *);
+extern void blackfin_wpstat_clear(struct blackfin_jtag *);
+extern uint16_t blackfin_dbgstat_emucause(struct blackfin_jtag *);
+extern void blackfin_emuir_set(struct blackfin_jtag *, uint32_t, tap_state_t);
+extern void blackfin_emuir_set_2(struct blackfin_jtag *, uint32_t, uint32_t, tap_state_t);
+extern void blackfin_emulation_enable(struct blackfin_jtag *);
+extern void blackfin_emulation_disable(struct blackfin_jtag *);
+extern void blackfin_emulation_trigger(struct blackfin_jtag *);
+extern void blackfin_emulation_return(struct blackfin_jtag *);
+
+extern void blackfin_register_set(struct blackfin_jtag *, enum core_regnum, uint32_t);
+extern uint32_t blackfin_register_get(struct blackfin_jtag *, enum core_regnum);
+extern uint32_t blackfin_get_p0(struct blackfin_jtag *);
+extern uint32_t blackfin_get_r0(struct blackfin_jtag *);
+extern void blackfin_set_p0(struct blackfin_jtag *, uint32_t);
+extern void blackfin_set_r0(struct blackfin_jtag *, uint32_t);
+extern void blackfin_check_emuready(struct blackfin_jtag *);
+extern void blackfin_system_reset(struct blackfin_jtag *);
+extern void blackfin_core_reset(struct blackfin_jtag *);
+extern void blackfin_emupc_get(struct blackfin_jtag *);
+extern void blackfin_emupc_reset(struct blackfin_jtag *);
+extern uint32_t blackfin_emudat_get(struct blackfin_jtag *, tap_state_t);
+extern void blackfin_emudat_set(struct blackfin_jtag *, uint32_t, tap_state_t);
+extern void blackfin_wpu_init(struct blackfin_jtag *);
+extern void blackfin_wpu_set_wpia(struct blackfin_jtag *, int, uint32_t, int);
+extern void blackfin_wpu_set_wpda(struct blackfin_jtag *, int);
+extern void blackfin_single_step(struct blackfin_jtag *, bool);
+#endif /* BLACKFIN_JTAG_H */
diff --git a/src/target/blackfin_mem.c b/src/target/blackfin_mem.c
new file mode 100644
index 0000000..6464d70
--- /dev/null
+++ b/src/target/blackfin_mem.c
@@ -0,0 +1,1628 @@
+/***************************************************************************
+ * Copyright (C) 2011 by Analog Devices, Inc. *
+ * Written by Jie Zhang <***@analog.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 <assert.h>
+
+#include "helper/log.h"
+#include "helper/types.h"
+#include "jtag/jtag.h"
+#include "blackfin.h"
+#include "blackfin_jtag.h"
+#include "blackfin_mem.h"
+
+#define DMA_CONFIG_FLOW_STOP 0x0000
+#define DMA_CONFIG_NDSIZE_0 0x0000
+#define DMA_CONFIG_DI_EN 0x0080
+#define DMA_CONFIG_DI_SEL 0x0040
+#define DMA_CONFIG_SYNC 0x0020
+#define DMA_CONFIG_DMA2D 0x0010
+#define DMA_CONFIG_WDSIZE_8 0x0000
+#define DMA_CONFIG_WDSIZE_16 0x0004
+#define DMA_CONFIG_WDSIZE_32 0x0008
+#define DMA_CONFIG_WDSIZE_MASK 0x000c
+#define DMA_CONFIG_WNR 0x0002
+#define DMA_CONFIG_DMAEN 0x0001
+
+#define DMA_IRQ_STATUS_DMA_RUN 0x0008
+#define DMA_IRQ_STATUS_DFETCH 0x0004
+#define DMA_IRQ_STATUS_DMA_ERR 0x0002
+#define DMA_IRQ_STATUS_DMA_DONE 0x0001
+
+#define EBIU_SDGCTL 0xffc00a10
+#define EBIU_SDBCTL 0xffc00a14
+#define EBIU_SDRRC 0xffc00a18
+#define EBIU_SDSTAT 0xffc00a1c
+
+#define EBIU_DDRCTL0 0xffc00a20
+#define EBIU_DDRCTL1 0xffc00a24
+#define EBIU_DDRCTL2 0xffc00a28
+#define EBIU_DDRCTL3 0xffc00a2c
+#define EBIU_RSTCTL 0xffc00a3c
+
+#define SICA_SYSCR 0xffc00104
+#define SICA_SYSCR_COREB_SRAM_INIT 0x0020
+
+#define DMEM_CONTROL 0xffe00004
+#define DCPLB_ADDR0 0xffe00100
+#define DCPLB_DATA0 0xffe00200
+#define IMEM_CONTROL 0xffe01004
+#define ICPLB_ADDR0 0xffe01100
+#define ICPLB_DATA0 0xffe01200
+
+#define ENICPLB 0x00000002
+#define IMC 0x00000004
+
+#define ENDCPLB 0x00000002
+#define DMC 0x0000000c
+#define ACACHE_BSRAM 0x00000008
+#define ACACHE_BCACHE 0x0000000c
+
+#define PAGE_SIZE_MASK 0x00030000
+#define PAGE_SIZE_4MB 0x00030000
+#define PAGE_SIZE_1MB 0x00020000
+#define PAGE_SIZE_4KB 0x00010000
+#define PAGE_SIZE_1KB 0x00000000
+#define CPLB_L1_AOW 0x00008000
+#define CPLB_WT 0x00004000
+#define CPLB_L1_CHBL 0x00001000
+#define CPLB_MEM_LEV 0x00000200
+#define CPLB_LRUPRIO 0x00000100
+#define CPLB_DIRTY 0x00000080
+#define CPLB_SUPV_WR 0x00000010
+#define CPLB_USER_WR 0x00000008
+#define CPLB_USER_RD 0x00000004
+#define CPLB_LOCK 0x00000002
+#define CPLB_VALID 0x00000001
+
+#define L1_DMEMORY (PAGE_SIZE_1MB | CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID)
+#define SDRAM_DNON_CHBL (PAGE_SIZE_4MB | CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID)
+#define SDRAM_DGEN_WB (PAGE_SIZE_4MB | CPLB_L1_CHBL | CPLB_DIRTY | CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID)
+#define SDRAM_DGEN_WT (PAGE_SIZE_4MB | CPLB_L1_CHBL | CPLB_WT | CPLB_L1_AOW | CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID)
+#define L1_IMEMORY (PAGE_SIZE_1MB | CPLB_USER_RD | CPLB_VALID)
+#define SDRAM_INON_CHBL (PAGE_SIZE_4MB | CPLB_USER_RD | CPLB_VALID)
+#define SDRAM_IGENERIC (PAGE_SIZE_4MB | CPLB_L1_CHBL | CPLB_MEM_LEV | CPLB_USER_RD | CPLB_VALID)
+/* The following DCPLB DATA are used by gdbproxy to prevent DCPLB missing exception. */
+#define DNON_CHBL_4MB (PAGE_SIZE_4MB | CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID)
+#define DNON_CHBL_1MB (PAGE_SIZE_1MB | CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID)
+#define DNON_CHBL_4KB (PAGE_SIZE_4KB | CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID)
+#define DNON_CHBL_1KB (PAGE_SIZE_1KB | CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID)
+
+#define CACHE_LINE_BYTES 32
+
+#define BFIN_DCPLB_NUM 16
+#define BFIN_ICPLB_NUM 16
+
+#define DTEST_COMMAND 0xffe00300
+#define DTEST_DATA0 0xffe00400
+#define DTEST_DATA1 0xffe00404
+
+#define ITEST_COMMAND 0xffe01300
+#define ITEST_DATA0 0xffe01400
+#define ITEST_DATA1 0xffe01404
+
+#define IN_RANGE(addr, lo, hi) ((addr) >= (lo) && (addr) < (hi))
+#define IN_MAP(addr, map) IN_RANGE (addr, map, map##_end)
+#define MAP_LEN(map) ((map##_end) - (map))
+
+struct blackfin_dma
+{
+ uint32_t next_desc_ptr;
+ uint32_t start_addr;
+ uint16_t config;
+ uint16_t x_count;
+ uint16_t x_modify;
+ uint16_t y_count;
+ uint16_t y_modify;
+ uint32_t curr_desc_ptr;
+ uint32_t curr_addr;
+ uint16_t irq_status;
+ uint16_t peripheral_map;
+ uint16_t curr_x_count;
+ uint16_t curr_y_count;
+};
+
+struct blackfin_test_data
+{
+ uint32_t command_addr, data0_addr, data1_addr;
+ uint32_t data0_off, data1_off;
+ uint32_t data0;
+ uint32_t data1;
+};
+
+#define RTI_LIMIT(blackfin) ((blackfin->l1_map->l1_code_end - blackfin->l1_map->l1_code) / 8)
+
+
+static uint32_t mmr_read_clobber_r0(struct blackfin_jtag *jtag_info, int32_t offset, uint32_t size)
+{
+ uint32_t value;
+
+ assert(size == 2 || size == 4);
+
+ if (offset == 0)
+ {
+ if (size == 2)
+ blackfin_emuir_set_2(jtag_info,
+ blackfin_gen_load16z(REG_R0, REG_P0),
+ blackfin_gen_move(REG_EMUDAT, REG_R0), TAP_DRPAUSE);
+ else
+ blackfin_emuir_set_2(jtag_info,
+ blackfin_gen_load32(REG_R0, REG_P0),
+ blackfin_gen_move(REG_EMUDAT, REG_R0), TAP_DRPAUSE);
+ }
+ else
+ {
+ if (size == 2)
+ blackfin_emuir_set(jtag_info,
+ blackfin_gen_load16z_offset(REG_R0, REG_P0, offset), TAP_IDLE);
+ else
+ blackfin_emuir_set(jtag_info,
+ blackfin_gen_load32_offset(REG_R0, REG_P0, offset), TAP_IDLE);
+ blackfin_emuir_set(jtag_info, blackfin_gen_move(REG_EMUDAT, REG_R0), TAP_DRPAUSE);
+ }
+ value = blackfin_emudat_get(jtag_info, TAP_IDLE);
+
+ return value;
+}
+
+static uint32_t mmr_read(struct blackfin_jtag *jtag_info, uint32_t addr, uint32_t size)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(jtag_info->target);
+ uint32_t p0, r0;
+ uint32_t value;
+
+ if (addr == DMEM_CONTROL)
+ {
+ if (size != 4)
+ {
+ LOG_ERROR("DMEM_CONTROL can only be accessed as 32-bit word");
+ /* Return a weird value to notice people. */
+ return 0xfffffff;
+ }
+
+ if (blackfin->dmem_control_valid_p)
+ return blackfin->dmem_control;
+ }
+ else if (addr == IMEM_CONTROL)
+ {
+ if (size != 4)
+ {
+ LOG_ERROR("IMEM_CONTROL can only be accessed as 32-bit word");
+ /* Return a weird value to notice people. */
+ return 0xfffffff;
+ }
+
+ if (blackfin->imem_control_valid_p)
+ return blackfin->imem_control;
+ }
+
+
+ p0 = blackfin_get_p0(jtag_info);
+ r0 = blackfin_get_r0(jtag_info);
+
+ blackfin_set_p0(jtag_info, addr);
+ value = mmr_read_clobber_r0(jtag_info, 0, size);
+
+ blackfin_set_p0(jtag_info, p0);
+ blackfin_set_r0(jtag_info, r0);
+
+ if (addr == DMEM_CONTROL)
+ {
+ blackfin->dmem_control = value;
+ blackfin->dmem_control_valid_p = 1;
+ }
+ else if (addr == IMEM_CONTROL)
+ {
+ blackfin->imem_control = value;
+ blackfin->imem_control_valid_p = 1;
+ }
+
+ return value;
+}
+
+static void mmr_write_clobber_r0(struct blackfin_jtag *jtag_info, int32_t offset, uint32_t data, uint32_t size)
+{
+ assert (size == 2 || size == 4);
+
+ blackfin_emudat_set(jtag_info, data, TAP_DRPAUSE);
+
+ if (offset == 0)
+ {
+ if (size == 2)
+ blackfin_emuir_set_2(jtag_info,
+ blackfin_gen_move(REG_R0, REG_EMUDAT),
+ blackfin_gen_store16(REG_P0, REG_R0), TAP_IDLE);
+ else
+ blackfin_emuir_set_2(jtag_info,
+ blackfin_gen_move(REG_R0, REG_EMUDAT),
+ blackfin_gen_store32(REG_P0, REG_R0), TAP_IDLE);
+ }
+ else
+ {
+ blackfin_emuir_set(jtag_info, blackfin_gen_move(REG_R0, REG_EMUDAT), TAP_IDLE);
+ if (size == 2)
+ blackfin_emuir_set(jtag_info, blackfin_gen_store16_offset(REG_P0, offset, REG_R0), TAP_IDLE);
+ else
+ blackfin_emuir_set(jtag_info, blackfin_gen_store32_offset(REG_P0, offset, REG_R0), TAP_IDLE);
+ }
+}
+
+static void mmr_write(struct blackfin_jtag *jtag_info, uint32_t addr, uint32_t data, int size)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(jtag_info->target);
+ uint32_t p0, r0;
+
+ if (addr == DMEM_CONTROL)
+ {
+ if (size != 4)
+ {
+ LOG_ERROR("DMEM_CONTROL can only be accessed as 32-bit word");
+ return;
+ }
+
+ if (blackfin->dmem_control_valid_p
+ && blackfin->dmem_control == data)
+ return;
+ else
+ {
+ blackfin->dmem_control = data;
+ blackfin->dmem_control_valid_p = 1;
+ }
+ }
+ else if (addr == IMEM_CONTROL)
+ {
+ if (size != 4)
+ {
+ LOG_ERROR("IMEM_CONTROL can only be accessed as 32-bit word");
+ return;
+ }
+
+ if (blackfin->imem_control_valid_p
+ && blackfin->imem_control == data)
+ return;
+ else
+ {
+ blackfin->imem_control = data;
+ blackfin->imem_control_valid_p = 1;
+ }
+ }
+
+ p0 = blackfin_get_p0(jtag_info);
+ r0 = blackfin_get_r0(jtag_info);
+
+ blackfin_set_p0(jtag_info, addr);
+ mmr_write_clobber_r0(jtag_info, 0, data, size);
+
+ blackfin_set_p0(jtag_info, p0);
+ blackfin_set_r0(jtag_info, r0);
+}
+
+static void cache_status_get(struct blackfin_jtag *jtag_info)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(jtag_info->target);
+ uint32_t p0, r0;
+
+ /* Instead of calling mmr_read twice, we save one of context save
+ and restore. */
+ if (!blackfin->dmem_control_valid_p
+ && !blackfin->imem_control_valid_p)
+ {
+ p0 = blackfin_get_p0(jtag_info);
+ r0 = blackfin_get_r0(jtag_info);
+
+ blackfin_set_p0(jtag_info, DMEM_CONTROL);
+
+ blackfin->dmem_control = mmr_read_clobber_r0(jtag_info, 0, 4);
+ blackfin->dmem_control_valid_p = 1;
+ blackfin->imem_control = mmr_read_clobber_r0(jtag_info, IMEM_CONTROL - DMEM_CONTROL, 4);
+ blackfin->imem_control_valid_p = 1;
+
+ blackfin_set_p0(jtag_info, p0);
+ blackfin_set_r0(jtag_info, r0);
+ }
+ else if (!blackfin->dmem_control_valid_p)
+ /* No need to set dmem_control and dmem_control_valid_p here.
+ mmr_read will handle them. */
+ mmr_read(jtag_info, DMEM_CONTROL, 4);
+ else if (!blackfin->imem_control_valid_p)
+ /* No need to set imem_control and imem_control_valid_p here.
+ mmr_read will handle them. */
+ mmr_read(jtag_info, IMEM_CONTROL, 4);
+
+ if (blackfin->imem_control & IMC)
+ blackfin->l1_code_cache_enabled = 1;
+ else
+ blackfin->l1_code_cache_enabled = 0;
+
+ if ((blackfin->dmem_control & DMC) == ACACHE_BCACHE)
+ {
+ blackfin->l1_data_a_cache_enabled = 1;
+ blackfin->l1_data_b_cache_enabled = 1;
+ }
+ else if ((blackfin->dmem_control & DMC) == ACACHE_BSRAM)
+ {
+ blackfin->l1_data_a_cache_enabled = 1;
+ blackfin->l1_data_b_cache_enabled = 0;
+ }
+ else
+ {
+ blackfin->l1_data_a_cache_enabled = 0;
+ blackfin->l1_data_b_cache_enabled = 0;
+ }
+}
+
+int blackfin_sdram_init(struct blackfin_jtag *jtag_info)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(jtag_info->target);
+ uint32_t p0, r0, value;
+
+ p0 = blackfin_get_p0(jtag_info);
+ r0 = blackfin_get_r0(jtag_info);
+
+ blackfin_set_p0(jtag_info, EBIU_SDGCTL);
+
+ /* Check if SDRAM has been enabled already.
+ If so, don't enable it again. */
+ value = mmr_read_clobber_r0(jtag_info, EBIU_SDSTAT - EBIU_SDGCTL, 2);
+ if ((value & 0x8) == 0)
+ {
+ LOG_DEBUG("%s: SDRAM has already been enabled", target_name(jtag_info->target));
+ return ERROR_OK;
+ }
+
+ mmr_write_clobber_r0(jtag_info, EBIU_SDRRC - EBIU_SDGCTL,
+ blackfin->sdram_config->sdrrc, 2);
+ mmr_write_clobber_r0(jtag_info, EBIU_SDBCTL - EBIU_SDGCTL,
+ blackfin->sdram_config->sdbctl, 2);
+ mmr_write_clobber_r0(jtag_info, 0, blackfin->sdram_config->sdgctl, 4);
+ blackfin_emuir_set(jtag_info, BLACKFIN_INSN_SSYNC, TAP_IDLE);
+
+ blackfin_set_p0(jtag_info, p0);
+ blackfin_set_r0(jtag_info, r0);
+
+ return ERROR_OK;
+}
+
+int blackfin_ddr_init(struct blackfin_jtag *jtag_info)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(jtag_info->target);
+ uint32_t p0, r0, value;
+
+ p0 = blackfin_get_p0(jtag_info);
+ r0 = blackfin_get_r0(jtag_info);
+
+ blackfin_set_p0(jtag_info, EBIU_DDRCTL0);
+
+ value = mmr_read_clobber_r0(jtag_info, EBIU_RSTCTL - EBIU_DDRCTL0, 2);
+ mmr_write_clobber_r0(jtag_info, EBIU_RSTCTL - EBIU_DDRCTL0, value | 0x1, 2);
+ blackfin_emuir_set(jtag_info, BLACKFIN_INSN_SSYNC, TAP_IDLE);
+
+ mmr_write_clobber_r0(jtag_info, 0, blackfin->ddr_config->ddrctl0, 4);
+ mmr_write_clobber_r0(jtag_info, EBIU_DDRCTL1 - EBIU_DDRCTL0,
+ blackfin->ddr_config->ddrctl1, 4);
+ mmr_write_clobber_r0(jtag_info, EBIU_DDRCTL2 - EBIU_DDRCTL0,
+ blackfin->ddr_config->ddrctl2, 4);
+ blackfin_emuir_set(jtag_info, BLACKFIN_INSN_SSYNC, TAP_IDLE);
+
+ blackfin_set_p0(jtag_info, p0);
+ blackfin_set_r0(jtag_info, r0);
+
+ return ERROR_OK;
+}
+
+static void dcplb_enable_clobber_p0r0(struct blackfin_jtag *jtag_info)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(jtag_info->target);
+
+ blackfin_set_p0(jtag_info, DMEM_CONTROL);
+
+ if (!blackfin->dmem_control_valid_p)
+ {
+ blackfin_emuir_set(jtag_info, BLACKFIN_INSN_CSYNC, TAP_IDLE);
+ blackfin->dmem_control = mmr_read_clobber_r0(jtag_info, 0, 4);
+ blackfin->dmem_control_valid_p = 1;
+ }
+
+ if (blackfin->dmem_control & ENDCPLB)
+ return;
+
+ blackfin->dmem_control |= ENDCPLB;
+ mmr_write_clobber_r0(jtag_info, 0, blackfin->dmem_control, 4);
+ blackfin_emuir_set(jtag_info, BLACKFIN_INSN_SSYNC, TAP_IDLE);
+}
+
+static int dcplb_disable_clobber_p0r0(struct blackfin_jtag *jtag_info)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(jtag_info->target);
+ int orig;
+
+ blackfin_set_p0(jtag_info, DMEM_CONTROL);
+
+ if (!blackfin->dmem_control_valid_p)
+ {
+ blackfin_emuir_set(jtag_info, BLACKFIN_INSN_CSYNC, TAP_IDLE);
+ blackfin->dmem_control = mmr_read_clobber_r0(jtag_info, 0, 4);
+ blackfin->dmem_control_valid_p = 1;
+ }
+
+ orig = blackfin->dmem_control & ENDCPLB;
+
+ if (orig)
+ {
+ blackfin->dmem_control &= ~ENDCPLB;
+ mmr_write_clobber_r0(jtag_info, 0, blackfin->dmem_control, 4);
+ blackfin_emuir_set(jtag_info, BLACKFIN_INSN_SSYNC, TAP_IDLE);
+ }
+
+ return orig;
+}
+
+static void dma_context_save_clobber_p0r0(struct blackfin_jtag *jtag_info, uint32_t base, struct blackfin_dma *dma)
+{
+ blackfin_set_p0(jtag_info, base);
+
+ dma->start_addr = mmr_read_clobber_r0(jtag_info, 0x04, 4);
+ dma->config = mmr_read_clobber_r0(jtag_info, 0x08, 2);
+ dma->x_count = mmr_read_clobber_r0(jtag_info, 0x10, 2);
+ dma->x_modify = mmr_read_clobber_r0(jtag_info, 0x14, 2);
+ dma->irq_status = mmr_read_clobber_r0(jtag_info, 0x28, 2);
+}
+
+static void dma_context_restore_clobber_p0r0(struct blackfin_jtag *jtag_info, uint32_t base, struct blackfin_dma *dma)
+{
+ blackfin_set_p0(jtag_info, base);
+
+ mmr_write_clobber_r0(jtag_info, 0x04, dma->start_addr, 4);
+ mmr_write_clobber_r0(jtag_info, 0x10, dma->x_count, 2);
+ mmr_write_clobber_r0(jtag_info, 0x14, dma->x_modify, 2);
+ mmr_write_clobber_r0(jtag_info, 0x08, dma->config, 2);
+}
+
+static void log_dma(uint32_t base, struct blackfin_dma *dma)
+{
+ LOG_DEBUG("DMA base [0x%08X]", base);
+ LOG_DEBUG("START_ADDR [0x%08X]", dma->start_addr);
+ LOG_DEBUG("CONFIG [0x%04X]", dma->config);
+ LOG_DEBUG("X_COUNT [0x%04X]", dma->x_count);
+ LOG_DEBUG("X_MODIFY [0x%04X]", dma->x_modify);
+ LOG_DEBUG("IRQ_STATUS [0x%04X]", dma->irq_status);
+}
+
+static int dma_copy(struct blackfin_jtag *jtag_info, uint32_t dest, uint32_t src, uint32_t size)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(jtag_info->target);
+ struct blackfin_dma mdma_s0_save, mdma_d0_save;
+ struct blackfin_dma mdma_s0, mdma_d0;
+ uint32_t p0, r0;
+ uint16_t s0_irq_status, d0_irq_status;
+ int retval;
+ const struct timespec dma_wait = {0, 50000000};
+
+ blackfin_emupc_reset(jtag_info);
+
+ p0 = blackfin_get_p0(jtag_info);
+ r0 = blackfin_get_r0(jtag_info);
+
+ dma_context_save_clobber_p0r0(jtag_info, blackfin->mdma_s0, &mdma_s0_save);
+ dma_context_save_clobber_p0r0(jtag_info, blackfin->mdma_d0, &mdma_d0_save);
+
+ log_dma(blackfin->mdma_s0, &mdma_s0_save);
+ log_dma(blackfin->mdma_d0, &mdma_d0_save);
+
+ s0_irq_status = mdma_s0_save.irq_status;
+ d0_irq_status = mdma_d0_save.irq_status;
+
+ while ((s0_irq_status & DMA_IRQ_STATUS_DMA_RUN) ||
+ (d0_irq_status & DMA_IRQ_STATUS_DMA_RUN))
+ {
+ if ((s0_irq_status & DMA_IRQ_STATUS_DMA_ERR) ||
+ (d0_irq_status & DMA_IRQ_STATUS_DMA_ERR))
+ break;
+
+ LOG_DEBUG("wait DMA done: S0:0x%08X [0x%04X] D0:0x%08X [0x%04X]",
+ src, s0_irq_status, dest, d0_irq_status);
+
+ nanosleep(&dma_wait, NULL);
+
+ blackfin_set_p0(jtag_info, blackfin->mdma_s0);
+ s0_irq_status = mmr_read_clobber_r0(jtag_info, 0x28, 2);
+ blackfin_set_p0(jtag_info, blackfin->mdma_d0);
+ d0_irq_status = mmr_read_clobber_r0(jtag_info, 0x28, 2);
+ }
+
+ if (s0_irq_status & DMA_IRQ_STATUS_DMA_ERR)
+ LOG_DEBUG("clear MDMA0_S0 DMA ERR: IRQ_STATUS [0x%04X]",
+ s0_irq_status);
+ if (s0_irq_status & DMA_IRQ_STATUS_DMA_DONE)
+ LOG_DEBUG("clear MDMA_S0 DMA DONE: IRQ_STATUS [0x%04X]",
+ s0_irq_status);
+ if (d0_irq_status & DMA_IRQ_STATUS_DMA_ERR)
+ LOG_DEBUG("clear MDMA0_D0 DMA ERR: IRQ_STATUS [0x%04X]",
+ d0_irq_status);
+ if (d0_irq_status & DMA_IRQ_STATUS_DMA_DONE)
+ LOG_DEBUG("clear MDMA_D0 DMA DONE: IRQ_STATUS [0x%04X]",
+ d0_irq_status);
+
+ if (s0_irq_status & (DMA_IRQ_STATUS_DMA_ERR | DMA_IRQ_STATUS_DMA_DONE))
+ {
+ blackfin_set_p0(jtag_info, blackfin->mdma_s0);
+ mmr_write_clobber_r0(jtag_info,
+ 0x28, DMA_IRQ_STATUS_DMA_ERR | DMA_IRQ_STATUS_DMA_DONE, 2);
+ }
+
+ if (d0_irq_status & (DMA_IRQ_STATUS_DMA_ERR | DMA_IRQ_STATUS_DMA_DONE))
+ {
+ blackfin_set_p0(jtag_info, blackfin->mdma_d0);
+ mmr_write_clobber_r0(jtag_info,
+ 0x28, DMA_IRQ_STATUS_DMA_ERR | DMA_IRQ_STATUS_DMA_DONE, 2);
+ }
+
+ blackfin_set_p0(jtag_info, blackfin->mdma_s0);
+ s0_irq_status = mmr_read_clobber_r0(jtag_info, 0x28, 2);
+ blackfin_set_p0(jtag_info, blackfin->mdma_d0);
+ d0_irq_status = mmr_read_clobber_r0(jtag_info, 0x28, 2);
+
+ LOG_DEBUG("before dma copy MDMA0_S0 IRQ_STATUS [0x%04X]", s0_irq_status);
+ LOG_DEBUG("before dma copy MDMA0_D0 IRQ_STATUS [0x%04X]", d0_irq_status);
+
+ mdma_s0.start_addr = src;
+ mdma_s0.x_count = size;
+ mdma_s0.x_modify = 1;
+ mdma_s0.config = DMA_CONFIG_FLOW_STOP | DMA_CONFIG_NDSIZE_0;
+ mdma_s0.config |= DMA_CONFIG_WDSIZE_8 | DMA_CONFIG_DMAEN | DMA_CONFIG_DI_EN;
+
+ mdma_d0.start_addr = dest;
+ mdma_d0.x_count = size;
+ mdma_d0.x_modify = 1;
+ mdma_d0.config =
+ DMA_CONFIG_FLOW_STOP | DMA_CONFIG_NDSIZE_0 | DMA_CONFIG_WNR;
+ mdma_d0.config |= DMA_CONFIG_WDSIZE_8 | DMA_CONFIG_DMAEN | DMA_CONFIG_DI_EN;
+
+ dma_context_restore_clobber_p0r0(jtag_info, blackfin->mdma_s0, &mdma_s0);
+ dma_context_restore_clobber_p0r0(jtag_info, blackfin->mdma_d0, &mdma_d0);
+
+ wait_dma:
+
+ blackfin_set_p0(jtag_info, blackfin->mdma_s0);
+ s0_irq_status = mmr_read_clobber_r0(jtag_info, 0x28, 2);
+ blackfin_set_p0(jtag_info, blackfin->mdma_d0);
+ d0_irq_status = mmr_read_clobber_r0(jtag_info, 0x28, 2);
+
+ if (s0_irq_status & DMA_IRQ_STATUS_DMA_ERR)
+ {
+ LOG_ERROR("MDMA0_S0 DMA error: 0x%08X: IRQ_STATUS [0x%04X]",
+ src, s0_irq_status);
+ retval = ERROR_FAIL;
+ goto finish_dma_copy;
+ }
+ if (d0_irq_status & DMA_IRQ_STATUS_DMA_ERR)
+ {
+ LOG_ERROR("MDMA0_D0 DMA error: 0x%08X: IRQ_STATUS [0x%04X]",
+ dest, d0_irq_status);
+ retval = ERROR_FAIL;
+ goto finish_dma_copy;
+ }
+ else if (!(s0_irq_status & DMA_IRQ_STATUS_DMA_DONE))
+ {
+ LOG_INFO("MDMA_S0 wait for done: IRQ_STATUS [0x%04X]", s0_irq_status);
+ nanosleep (&dma_wait, NULL);
+ goto wait_dma;
+ }
+ else if (!(d0_irq_status & DMA_IRQ_STATUS_DMA_DONE))
+ {
+ LOG_INFO("MDMA_D0 wait for done: IRQ_STATUS [0x%04X]", d0_irq_status);
+ nanosleep (&dma_wait, NULL);
+ goto wait_dma;
+ }
+ else
+ retval = ERROR_OK;
+
+ LOG_DEBUG("done dma copy MDMA_S0: 0x%08X: IRQ_STATUS [0x%04X]",
+ src, s0_irq_status);
+
+ LOG_DEBUG("done dma copy MDMA_D0: 0x%08X: IRQ_STATUS [0x%04X]",
+ dest, d0_irq_status);
+
+ if ((s0_irq_status & DMA_IRQ_STATUS_DMA_ERR)
+ || (s0_irq_status & DMA_IRQ_STATUS_DMA_DONE))
+ {
+ blackfin_set_p0(jtag_info, blackfin->mdma_s0);
+ mmr_write_clobber_r0(jtag_info,
+ 0x28, DMA_IRQ_STATUS_DMA_ERR | DMA_IRQ_STATUS_DMA_DONE, 2);
+ }
+
+ if ((d0_irq_status & DMA_IRQ_STATUS_DMA_ERR)
+ || (d0_irq_status & DMA_IRQ_STATUS_DMA_DONE))
+ {
+ blackfin_set_p0(jtag_info, blackfin->mdma_d0);
+ mmr_write_clobber_r0(jtag_info,
+ 0x28, DMA_IRQ_STATUS_DMA_ERR | DMA_IRQ_STATUS_DMA_DONE, 2);
+ }
+
+
+ dma_context_restore_clobber_p0r0(jtag_info, blackfin->mdma_s0, &mdma_s0_save);
+ dma_context_restore_clobber_p0r0(jtag_info, blackfin->mdma_d0, &mdma_d0_save);
+
+ finish_dma_copy:
+
+ blackfin_set_p0(jtag_info, p0);
+ blackfin_set_r0(jtag_info, r0);
+
+ return retval;
+}
+
+/* TODO optimize it by using blackfin_emudat_defer_get and blackfin_emudat_get_done. */
+
+static int memory_read_1(struct blackfin_jtag *jtag_info, uint32_t addr, uint8_t *buf, int size)
+{
+ uint32_t p0, r0;
+ bool dcplb_enabled;
+
+ assert (size > 0);
+
+ p0 = blackfin_get_p0(jtag_info);
+ r0 = blackfin_get_r0(jtag_info);
+
+ dcplb_enabled = dcplb_disable_clobber_p0r0(jtag_info);
+
+ blackfin_set_p0(jtag_info, addr);
+
+ if ((addr & 0x3) != 0)
+ blackfin_emuir_set_2(jtag_info,
+ blackfin_gen_load8zpi(REG_R0, REG_P0),
+ blackfin_gen_move(REG_EMUDAT, REG_R0), TAP_DRPAUSE);
+
+ while ((addr & 0x3) != 0 && size != 0)
+ {
+ *buf++ = blackfin_emudat_get(jtag_info, TAP_IDLE);
+ addr++;
+ size--;
+ }
+ if (size == 0)
+ goto finish_read;
+
+ if (size >= 4)
+ blackfin_emuir_set_2(jtag_info,
+ blackfin_gen_load32pi(REG_R0, REG_P0),
+ blackfin_gen_move(REG_EMUDAT, REG_R0), TAP_DRPAUSE);
+
+ for (; size >= 4; size -= 4)
+ {
+ uint32_t data;
+
+ data = blackfin_emudat_get(jtag_info, TAP_IDLE);
+ *buf++ = data & 0xff;
+ *buf++ = (data >> 8) & 0xff;
+ *buf++ = (data >> 16) & 0xff;
+ *buf++ = (data >> 24) & 0xff;
+ }
+
+ if (size == 0)
+ goto finish_read;
+
+ blackfin_emuir_set_2 (jtag_info,
+ blackfin_gen_load8zpi(REG_R0, REG_P0),
+ blackfin_gen_move(REG_EMUDAT, REG_R0), TAP_DRPAUSE);
+
+ for (; size > 0; size--)
+ *buf++ = blackfin_emudat_get(jtag_info, TAP_IDLE);
+
+ finish_read:
+
+ if (dcplb_enabled)
+ dcplb_enable_clobber_p0r0(jtag_info);
+
+ blackfin_set_p0(jtag_info, p0);
+ blackfin_set_r0(jtag_info, r0);
+
+ return 0;
+}
+
+static int memory_read(struct blackfin_jtag *jtag_info, uint32_t addr, uint32_t size, uint8_t *buf)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(jtag_info->target);
+ uint32_t s;
+
+ if ((addr & 0x3) != 0)
+ {
+ s = 4 - (addr & 0x3);
+ s = size < s ? size : s;
+ memory_read_1(jtag_info, addr, buf, s);
+ size -= s;
+ addr += s;
+ buf += s;
+ }
+
+ while (size > 0)
+ {
+ blackfin_emupc_reset(jtag_info);
+
+ /* The overhead should be no larger than 0x20. */
+ s = (RTI_LIMIT(blackfin) - 0x20) * 4;
+ s = size < s ? size : s;
+ memory_read_1(jtag_info, addr, buf, s);
+ size -= s;
+ addr += s;
+ buf += s;
+ }
+
+ return ERROR_OK;
+}
+
+static int memory_write_1 (struct blackfin_jtag *jtag_info, uint32_t addr, uint8_t *buf, int size)
+{
+ uint32_t p0, r0;
+ bool dcplb_enabled;
+
+ assert (size > 0);
+
+ p0 = blackfin_get_p0(jtag_info);
+ r0 = blackfin_get_r0(jtag_info);
+
+ dcplb_enabled = dcplb_disable_clobber_p0r0(jtag_info);
+
+ blackfin_set_p0(jtag_info, addr);
+
+ if ((addr & 0x3) != 0)
+ blackfin_emuir_set_2(jtag_info,
+ blackfin_gen_move(REG_R0, REG_EMUDAT),
+ blackfin_gen_store8pi(REG_P0, REG_R0), TAP_DRPAUSE);
+
+ while ((addr & 0x3) != 0 && size != 0)
+ {
+ blackfin_emudat_set(jtag_info, *buf++, TAP_IDLE);
+ addr++;
+ size--;
+ }
+ if (size == 0)
+ goto finish_write;
+
+ if (size >= 4)
+ blackfin_emuir_set_2(jtag_info,
+ blackfin_gen_move(REG_R0, REG_EMUDAT),
+ blackfin_gen_store32pi(REG_P0, REG_R0), TAP_DRPAUSE);
+
+ for (; size >= 4; size -= 4)
+ {
+ uint32_t data;
+
+ data = *buf++;
+ data |= (*buf++) << 8;
+ data |= (*buf++) << 16;
+ data |= (*buf++) << 24;
+ blackfin_emudat_set(jtag_info, data, TAP_IDLE);
+ }
+
+ if (size == 0)
+ goto finish_write;
+
+ blackfin_emuir_set_2(jtag_info,
+ blackfin_gen_move(REG_R0, REG_EMUDAT),
+ blackfin_gen_store8pi(REG_P0, REG_R0), TAP_DRPAUSE);
+
+ for (; size > 0; size--)
+ blackfin_emudat_set(jtag_info, *buf++, TAP_IDLE);
+
+ finish_write:
+
+ if (dcplb_enabled)
+ dcplb_enable_clobber_p0r0(jtag_info);
+
+ blackfin_set_p0(jtag_info, p0);
+ blackfin_set_r0(jtag_info, r0);
+
+ return 0;
+}
+
+static int memory_write(struct blackfin_jtag *jtag_info, uint32_t addr, uint32_t size, uint8_t *buf)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(jtag_info->target);
+ uint32_t s;
+
+ if ((addr & 0x3) != 0)
+ {
+ s = 4 - (addr & 0x3);
+ s = size < s ? size : s;
+ memory_write_1(jtag_info, addr, buf, s);
+ size -= s;
+ addr += s;
+ buf += s;
+ }
+
+ while (size > 0)
+ {
+ blackfin_emupc_reset(jtag_info);
+
+ /* The overhead should be no larger than 0x20. */
+ s = (RTI_LIMIT(blackfin) - 0x20) * 4;
+ s = size < s ? size : s;
+ memory_write_1(jtag_info, addr, buf, s);
+ size -= s;
+ addr += s;
+ buf += s;
+ }
+
+ return ERROR_OK;
+}
+
+static int dma_sram_read(struct blackfin_jtag *jtag_info, uint32_t address,
+ uint32_t size, uint8_t *buffer)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(jtag_info->target);
+ uint32_t l1_addr;
+ uint8_t *tmp;
+ int retval;
+
+ l1_addr = blackfin->l1_map->l1_data_a;
+
+ assert(size < 0x4000);
+
+ tmp = (uint8_t *) malloc(size);
+ if (tmp == NULL)
+ abort();
+
+ memory_read(jtag_info, l1_addr, size, tmp);
+
+ retval = dma_copy(jtag_info, l1_addr, address, size);
+
+ memory_read(jtag_info, l1_addr, size, buffer);
+
+ memory_write(jtag_info, l1_addr, size, buffer);
+
+ free(tmp);
+
+ return retval;
+}
+
+static int dma_sram_write(struct blackfin_jtag *jtag_info, uint32_t address,
+ uint32_t size, uint8_t *buffer)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(jtag_info->target);
+ uint32_t l1_addr;
+ uint8_t *tmp;
+ int retval;
+
+ l1_addr = blackfin->l1_map->l1_data_a;
+
+ assert(l1_addr);
+ assert(size <= MAP_LEN(blackfin->l1_map->l1_data_a));
+
+ tmp = (uint8_t *) malloc(size);
+ if (tmp == NULL)
+ abort();
+
+ memory_read(jtag_info, l1_addr, size, tmp);
+
+ memory_write(jtag_info, l1_addr, size, buffer);
+
+ retval = dma_copy(jtag_info, address, l1_addr, size);
+
+ memory_write(jtag_info, l1_addr, size, tmp);
+
+ free(tmp);
+
+ return retval;
+}
+
+/* Read Instruction SRAM using Instruction Test Registers. */
+
+static void test_command (struct blackfin_jtag *jtag_info, uint32_t addr, bool write_p,
+ uint32_t command_addr, uint32_t *command_value)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(jtag_info->target);
+
+ /* The shifting here is a bit funky, but should be straight forward and
+ easier to maintain than hand coded masks. So, start with the break
+ down of the [DI]TEST_COMMAND MMR in the HRM and follow along:
+
+ We need to put bit 11 of the address into bit 26 of the MMR. So first
+ we mask off ADDR[11] with:
+ (addr & (1 << 11))
+
+ Then we shift it from its current position (11) to its new one (26):
+ ((...) << (26 - 11))
+ */
+
+ /* Start with the bits ITEST/DTEST share. */
+ *command_value =
+ ((addr & (0x03 << 12)) << (16 - 12)) | /* ADDR[13:12] -> MMR[17:16] */
+ ((addr & (0x01 << 14)) << (14 - 14)) | /* ADDR[14] -> MMR[14] */
+ ((addr & (0xff << 3)) << ( 3 - 3)) | /* ADDR[10:3] -> MMR[10:3] */
+ (1 << 2) | /* 1 (data) -> MMR[2] */
+ (write_p << 1); /* read/write -> MMR[1] */
+
+ /* Now for the bits that aren't the same. */
+ if (command_addr == ITEST_COMMAND)
+ *command_value |=
+ ((addr & (0x03 << 10)) << (26 - 10)); /* ADDR[11:10] -> MMR[27:26] */
+ else
+ *command_value |=
+ ((addr & (0x01 << 11)) << (26 - 11)) | /* ADDR[11] -> MMR[26] */
+ ((addr & (0x01 << 21)) << (24 - 21)); /* ADDR[21] -> MMR[24] */
+
+ /* Now, just for fun, some parts are slightly different. */
+ if (command_addr == DTEST_COMMAND)
+ {
+ /* BF50x has no additional needs. */
+ if (!strcasecmp (blackfin->part, "BF518"))
+ {
+ /* MMR[23]:
+ 0 - Data Bank A (0xff800000) / Inst Bank A (0xffa00000)
+ 1 - Data Bank B (0xff900000) / Inst Bank B (0xffa04000)
+ */
+ if ((addr & 0xfff04000) == 0xffa04000 ||
+ (addr & 0xfff00000) == 0xff900000)
+ *command_value |= (1 << 23);
+ }
+ else if (!strcasecmp (blackfin->part, "BF526") ||
+ !strcasecmp (blackfin->part, "BF527") ||
+ !strcasecmp (blackfin->part, "BF533") ||
+ !strcasecmp (blackfin->part, "BF534") ||
+ !strcasecmp (blackfin->part, "BF537") ||
+ !strcasecmp (blackfin->part, "BF538") ||
+ !strcasecmp (blackfin->part, "BF548") ||
+ !strcasecmp (blackfin->part, "BF548M"))
+ {
+ /* MMR[23]:
+ 0 - Data Bank A (0xff800000) / Inst Bank A (0xffa00000)
+ 1 - Data Bank B (0xff900000) / Inst Bank B (0xffa08000)
+ */
+ if ((addr & 0xfff08000) == 0xffa08000 ||
+ (addr & 0xfff00000) == 0xff900000)
+ *command_value |= (1 << 23);
+ }
+ else if (!strcasecmp (blackfin->part, "BF561"))
+ {
+ /* MMR[23]:
+ 0 - Data Bank A (Core A: 0xff800000 Core B: 0xff400000)
+ Inst Bank A (Core A: 0xffa00000 Core B: 0xff600000)
+ 1 - Data Bank B (Core A: 0xff900000 Core B: 0xff500000)
+ N/A for Inst (no Bank B)
+ */
+ uint32_t hi = (addr >> 20);
+ if (hi == 0xff9 || hi == 0xff5)
+ *command_value |= (1 << 23);
+ }
+ else if (!strcasecmp (blackfin->part, "BF592"))
+ {
+ /* ADDR[15] -> MMR[15]
+ MMR[22]:
+ 0 - L1 Inst (0xffa00000)
+ 1 - L1 ROM (0xffa10000)
+ */
+ *command_value |= (addr & (1 << 15));
+ if ((addr >> 16) == 0xffa1)
+ *command_value |= (1 << 22);
+ }
+ }
+}
+
+/* Do one ITEST read. ADDR should be aligned to 8 bytes. BUF should
+ be enough large to hold 64 bits. */
+static void itest_read_clobber_r0 (struct blackfin_jtag *jtag_info,
+ struct blackfin_test_data *test_data, uint32_t addr, uint8_t *buf)
+{
+ uint32_t command, data1, data0;
+
+ assert ((addr & 0x7) == 0);
+
+ test_command (jtag_info, addr, false, test_data->command_addr, &command);
+
+ mmr_write_clobber_r0 (jtag_info, 0, command, 4);
+ blackfin_emuir_set (jtag_info, BLACKFIN_INSN_CSYNC, TAP_IDLE);
+ data1 = mmr_read_clobber_r0 (jtag_info, test_data->data1_off, 4);
+ data0 = mmr_read_clobber_r0 (jtag_info, test_data->data0_off, 4);
+
+ *buf++ = data0 & 0xff;
+ *buf++ = (data0 >> 8) & 0xff;
+ *buf++ = (data0 >> 16) & 0xff;
+ *buf++ = (data0 >> 24) & 0xff;
+ *buf++ = data1 & 0xff;
+ *buf++ = (data1 >> 8) & 0xff;
+ *buf++ = (data1 >> 16) & 0xff;
+ *buf++ = (data1 >> 24) & 0xff;
+}
+
+/* Do one ITEST write. ADDR should be aligned to 8 bytes. BUF should
+ be enough large to hold 64 bits. */
+static void itest_write_clobber_r0 (struct blackfin_jtag *jtag_info,
+ struct blackfin_test_data *test_data, uint32_t addr, uint8_t *buf)
+{
+ uint32_t command, data1, data0;
+
+ assert ((addr & 0x7) == 0);
+
+ test_command(jtag_info, addr, true, test_data->command_addr, &command);
+
+ data0 = *buf++;
+ data0 |= (*buf++) << 8;
+ data0 |= (*buf++) << 16;
+ data0 |= (*buf++) << 24;
+ data1 = *buf++;
+ data1 |= (*buf++) << 8;
+ data1 |= (*buf++) << 16;
+ data1 |= (*buf++) << 24;
+
+ mmr_write_clobber_r0(jtag_info, test_data->data1_off, data1, 4);
+ mmr_write_clobber_r0(jtag_info, test_data->data0_off, data0, 4);
+ mmr_write_clobber_r0(jtag_info, 0, command, 4);
+ blackfin_emuir_set(jtag_info, BLACKFIN_INSN_CSYNC, TAP_IDLE);
+}
+
+static void test_context_save_clobber_r0(struct blackfin_jtag *jtag_info, struct blackfin_test_data *test_data)
+{
+ test_data->data1 = mmr_read_clobber_r0(jtag_info, test_data->data1_off, 4);
+ test_data->data0 = mmr_read_clobber_r0(jtag_info, test_data->data0_off, 4);
+}
+
+static void test_context_restore_clobber_r0(struct blackfin_jtag *jtag_info, struct blackfin_test_data *test_data)
+{
+ mmr_write_clobber_r0 (jtag_info, test_data->data1_off, test_data->data1, 4);
+ mmr_write_clobber_r0 (jtag_info, test_data->data0_off, test_data->data0, 4);
+ /* Yeah, TEST_COMMAND is reset to 0, i.e. clobbered! But it should
+ not do any harm to any reasonable user programs. Codes trying to
+ peek TEST_COMMAND might be affected. But why do such codes
+ exist? */
+ mmr_write_clobber_r0 (jtag_info, 0, 0, 4);
+ blackfin_emuir_set (jtag_info, BLACKFIN_INSN_CSYNC, TAP_IDLE);
+}
+
+static void test_command_mmrs(struct blackfin_jtag *jtag_info, uint32_t addr, int icache, uint32_t *command_addr, uint32_t *data0_addr, uint32_t *data1_addr)
+{
+ if (icache) {
+ *command_addr = ITEST_COMMAND;
+ *data0_addr = ITEST_DATA0;
+ *data1_addr = ITEST_DATA1;
+ } else {
+ *command_addr = DTEST_COMMAND;
+ *data0_addr = DTEST_DATA0;
+ *data1_addr = DTEST_DATA1;
+ }
+}
+
+static int itest_sram_1(struct blackfin_jtag *jtag_info, uint32_t addr, uint8_t *buf, uint32_t size, int write_p)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(jtag_info->target);
+ struct blackfin_test_data test_data;
+ uint32_t p0, r0;
+ uint8_t data[8];
+
+ p0 = blackfin_get_p0(jtag_info);
+ r0 = blackfin_get_r0(jtag_info);
+
+ test_command_mmrs(jtag_info, addr,
+ IN_MAP(addr, blackfin->l1_map->l1_code_cache),
+ &test_data.command_addr,
+ &test_data.data0_addr,
+ &test_data.data1_addr);
+ test_data.data0_off = test_data.data0_addr - test_data.command_addr;
+ test_data.data1_off = test_data.data1_addr - test_data.command_addr;
+ blackfin_register_set(jtag_info, REG_P0, test_data.command_addr);
+
+ test_context_save_clobber_r0(jtag_info, &test_data);
+
+ if ((addr & 0x7) != 0)
+ {
+ uint32_t aligned_addr = addr & 0xfffffff8;
+
+ itest_read_clobber_r0(jtag_info, &test_data, aligned_addr, data);
+
+ if (write_p)
+ {
+ while ((addr & 0x7) != 0 && size != 0)
+ {
+ data[addr & 0x7] = *buf++;
+ addr++;
+ size--;
+ }
+
+ itest_write_clobber_r0(jtag_info, &test_data, aligned_addr, data);
+ }
+ else
+ {
+ while ((addr & 0x7) != 0 && size != 0)
+ {
+ *buf++ = data[addr & 0x7];
+ addr++;
+ size--;
+ }
+ }
+ }
+
+ for (; size >= 8; size -= 8)
+ {
+ if (write_p)
+ itest_write_clobber_r0(jtag_info, &test_data, addr, buf);
+ else
+ itest_read_clobber_r0(jtag_info, &test_data, addr, buf);
+ addr += 8;
+ buf += 8;
+ }
+
+ if (size != 0)
+ {
+ itest_read_clobber_r0(jtag_info, &test_data, addr, data);
+
+ if (write_p)
+ {
+ memcpy(data, buf, size);
+ itest_write_clobber_r0(jtag_info, &test_data, addr, data);
+ }
+ else
+ {
+ memcpy(buf, data, size);
+ }
+ }
+
+ test_context_restore_clobber_r0(jtag_info, &test_data);
+
+ blackfin_set_p0(jtag_info, p0);
+ blackfin_set_r0(jtag_info, r0);
+
+ return 0;
+}
+
+static int itest_sram(struct blackfin_jtag *jtag_info, uint32_t addr,
+ uint32_t size, uint8_t *buf, bool write_p)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(jtag_info->target);
+ uint32_t s;
+
+ if ((addr & 0x7) != 0)
+ {
+ s = 8 - (addr & 0x7);
+ s = size < s ? size : s;
+ itest_sram_1(jtag_info, addr, buf, s, write_p);
+ size -= s;
+ addr += s;
+ buf += s;
+ }
+
+ while (size > 0)
+ {
+ blackfin_emupc_reset(jtag_info);
+
+ /* The overhead should be no larger than 0x20. */
+ s = (RTI_LIMIT(blackfin) - 0x20) / 25 * 32;
+ s = size < s ? size : s;
+ /* We also need to keep transfers from spanning SRAM banks.
+ The core itest logic looks up appropriate MMRs once per
+ call, and different SRAM banks might require a different
+ set of MMRs. */
+ if ((addr / 0x4000) != ((addr + s) / 0x4000))
+ s -= ((addr + s) % 0x4000);
+ itest_sram_1(jtag_info, addr, buf, s, write_p);
+ size -= s;
+ addr += s;
+ buf += s;
+ }
+
+ return ERROR_OK;
+}
+
+static int sram_read_write(struct blackfin_jtag *jtag_info, uint32_t addr,
+ uint32_t size, uint8_t *buf, bool dma_p, bool write_p)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(jtag_info->target);
+
+ assert(!dma_p || blackfin->mdma_d0 != 0);
+
+ /* FIXME Add an option to control using dma or itest. BF592 can only use itest for its L1 ROM. */
+ if (dma_p)
+ {
+ if (write_p)
+ return dma_sram_write(jtag_info, addr, size, buf);
+ else
+ return dma_sram_read(jtag_info, addr, size, buf);
+ }
+ else
+ return itest_sram(jtag_info, addr, size, buf, write_p);
+}
+
+static int sram_read(struct blackfin_jtag *jtag_info, uint32_t addr,
+ uint32_t size, uint8_t *buf, bool dma_p)
+{
+ return sram_read_write(jtag_info, addr, size, buf, dma_p, false);
+}
+
+static int sram_write(struct blackfin_jtag *jtag_info, uint32_t addr,
+ uint32_t size, uint8_t *buf, bool dma_p)
+{
+ return sram_read_write(jtag_info, addr, size, buf, dma_p, true);
+}
+
+int blackfin_read_mem(struct blackfin_jtag *jtag_info, uint32_t addr,
+ uint32_t size, uint8_t *buf)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(jtag_info->target);
+ int retval;
+ uint32_t value;
+ uint32_t end;
+
+ LOG_DEBUG("bfin_read_mem(0x%08X, %d)", addr, size);
+
+ blackfin_emupc_reset(jtag_info);
+
+ if (!IN_MAP(addr, blackfin->mem_map->l1))
+ goto skip_l1;
+
+ if (IN_MAP(addr, blackfin->l1_map->l1))
+ cache_status_get(jtag_info);
+
+ if (IN_MAP(addr, blackfin->l1_map->l1_code))
+ {
+ if (!blackfin->l1_code_cache_enabled &&
+ (blackfin->l1_map->l1_code_end == blackfin->l1_map->l1_code_cache))
+ end = blackfin->l1_map->l1_code_cache_end;
+ else
+ end = blackfin->l1_map->l1_code_end;
+
+ if (addr + size > end)
+ size = end - addr;
+
+ retval = sram_read(jtag_info, addr, size, buf, false);
+ goto done;
+ }
+ else if (!blackfin->l1_code_cache_enabled &&
+ IN_MAP(addr, blackfin->l1_map->l1_code_cache))
+ {
+ if (addr + size > blackfin->l1_map->l1_code_cache_end)
+ size = blackfin->l1_map->l1_code_cache_end - addr;
+
+ retval = sram_read(jtag_info, addr, size, buf, false);
+ goto done;
+ }
+ else if (IN_MAP(addr, blackfin->l1_map->l1_code_rom))
+ {
+ if (addr + size > blackfin->l1_map->l1_code_rom_end)
+ size = blackfin->l1_map->l1_code_rom_end - addr;
+
+ retval = sram_read(jtag_info, addr, size, buf, false);
+ goto done;
+ }
+ else if (IN_MAP(addr, blackfin->l1_map->l1_data_a))
+ {
+ if (!blackfin->l1_data_a_cache_enabled &&
+ (blackfin->l1_map->l1_data_a_end == blackfin->l1_map->l1_data_a_cache))
+ end = blackfin->l1_map->l1_data_a_cache_end;
+ else
+ end = blackfin->l1_map->l1_data_a_end;
+
+ if (addr + size > end)
+ size = end - addr;
+
+ retval = memory_read(jtag_info, addr, size, buf);
+ goto done;
+ }
+ else if (!blackfin->l1_data_a_cache_enabled &&
+ IN_MAP (addr, blackfin->l1_map->l1_data_a_cache))
+ {
+ if (addr + size > blackfin->l1_map->l1_data_a_cache_end)
+ size = blackfin->l1_map->l1_data_a_cache_end - addr;
+
+ retval = memory_read(jtag_info, addr, size, buf);
+ goto done;
+ }
+ else if (IN_MAP (addr, blackfin->l1_map->l1_data_b))
+ {
+ if (!blackfin->l1_data_b_cache_enabled
+ && (blackfin->l1_map->l1_data_b_end
+ == blackfin->l1_map->l1_data_b_cache))
+ end = blackfin->l1_map->l1_data_b_cache_end;
+ else
+ end = blackfin->l1_map->l1_data_b_end;
+
+ if (addr + size > end)
+ size = end - addr;
+
+ retval = memory_read(jtag_info, addr, size, buf);
+ goto done;
+ }
+ else if (!blackfin->l1_data_b_cache_enabled &&
+ IN_MAP (addr, blackfin->l1_map->l1_data_b_cache))
+ {
+ if (addr + size > blackfin->l1_map->l1_data_b_cache_end)
+ size = blackfin->l1_map->l1_data_b_cache_end - addr;
+
+ retval = memory_read(jtag_info, addr, size, buf);
+ goto done;
+ }
+ else if (IN_MAP (addr, blackfin->l1_map->l1_scratch))
+ {
+ if (addr + size > blackfin->l1_map->l1_scratch_end)
+ size = blackfin->l1_map->l1_scratch_end - addr;
+
+ retval = memory_read(jtag_info, addr, size, buf);
+ goto done;
+ }
+ else if (IN_MAP (addr, blackfin->l1_map->l1))
+ {
+ LOG_ERROR("invalid L1 memory address [0x%08X]", addr);
+ retval = ERROR_FAIL;
+ goto done;
+ }
+
+ skip_l1:
+
+ /* TODO Accurately check MMR validity. */
+
+ if ((IN_RANGE (addr, blackfin->mem_map->sysmmr, blackfin->mem_map->coremmr)
+ && addr + size > blackfin->mem_map->coremmr)
+ || (addr >= blackfin->mem_map->coremmr && addr + size < addr))
+ {
+ LOG_ERROR("bad MMR addr or size [0x%08X] size %d", addr, size);
+ return ERROR_FAIL;
+ }
+
+ if (addr >= blackfin->mem_map->sysmmr)
+ {
+ if (size != 2 && size != 4)
+ {
+ LOG_ERROR("bad MMR size [0x%08X] size %d", addr, size);
+ return ERROR_FAIL;
+ }
+
+ if ((addr & 0x1) == 1)
+ {
+ LOG_ERROR("odd MMR addr [0x%08X]", addr);
+ return ERROR_FAIL;
+ }
+
+ value = mmr_read(jtag_info, addr, size);
+ *buf++ = value & 0xff;
+ *buf++ = (value >> 8) & 0xff;
+ if (size == 4)
+ {
+ *buf++ = (value >> 16) & 0xff;
+ *buf++ = (value >> 24) & 0xff;
+ }
+ retval = ERROR_OK;
+ goto done;
+ }
+
+ if (IN_MAP (addr, blackfin->mem_map->sdram))
+ {
+ if (addr + size > blackfin->mem_map->sdram_end)
+ size = blackfin->mem_map->sdram_end - addr;
+
+ retval = memory_read(jtag_info, addr, size, buf);
+ }
+ else if (IN_MAP (addr, blackfin->mem_map->async_mem))
+ {
+ if (addr + size > blackfin->mem_map->async_mem_end)
+ size = blackfin->mem_map->async_mem_end - addr;
+
+ retval = memory_read(jtag_info, addr, size, buf);
+ }
+ /* TODO Allow access to devices mapped to async mem. */
+ else if (IN_MAP (addr, blackfin->mem_map->boot_rom))
+ {
+ if (addr + size > blackfin->mem_map->boot_rom_end)
+ size = blackfin->mem_map->boot_rom_end - addr;
+ retval = memory_read(jtag_info, addr, size, buf);
+ }
+ else if (IN_MAP (addr, blackfin->mem_map->l2_sram))
+ {
+ if (addr + size > blackfin->mem_map->l2_sram_end)
+ size = blackfin->mem_map->l2_sram_end - addr;
+
+ retval = memory_read(jtag_info, addr, size, buf);
+ }
+ else
+ {
+ LOG_ERROR("invalid L1 memory address [0x%08X]", addr);
+ retval = ERROR_FAIL;
+ }
+
+ done:
+
+ return retval;
+}
+
+static void icache_flush(struct blackfin_jtag *jtag_info, uint32_t addr, int size)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(jtag_info->target);
+ uint32_t p0, r0;
+ int i;
+
+ assert (size > 0);
+
+ p0 = blackfin_get_p0(jtag_info);
+
+ if (!blackfin->imem_control_valid_p)
+ {
+ r0 = blackfin_get_r0(jtag_info);
+ blackfin_set_p0(jtag_info, IMEM_CONTROL);
+ blackfin_emuir_set(jtag_info, BLACKFIN_INSN_CSYNC, TAP_IDLE);
+ blackfin->imem_control = mmr_read_clobber_r0(jtag_info, 0, 4);
+ blackfin->imem_control_valid_p = 1;
+ blackfin_set_r0(jtag_info, r0);
+ }
+
+ if (blackfin->imem_control & IMC)
+ {
+ blackfin_set_p0(jtag_info, addr);
+ for (i = (size + addr % CACHE_LINE_BYTES - 1) / CACHE_LINE_BYTES + 1;
+ i > 0; i--)
+ blackfin_emuir_set(jtag_info, blackfin_gen_iflush_pm(REG_P0), TAP_IDLE);
+ }
+
+ blackfin_set_p0(jtag_info, p0);
+}
+
+int blackfin_write_mem(struct blackfin_jtag *jtag_info, uint32_t addr,
+ uint32_t size, const uint8_t *buffer)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(jtag_info->target);
+ int retval;
+ uint32_t value;
+ uint32_t end;
+ uint8_t *buf = (uint8_t *) buffer; /* TODO remove this cast. */
+
+ LOG_DEBUG("bfin_write_mem(0x%08X, %d)", addr, size);
+
+ blackfin_emupc_reset(jtag_info);
+
+ if (!IN_MAP (addr, blackfin->mem_map->l1))
+ goto skip_l1;
+
+ if (IN_MAP (addr, blackfin->l1_map->l1))
+ cache_status_get(jtag_info);
+
+ if (IN_MAP(addr, blackfin->l1_map->l1_code) &&
+ ((!blackfin->l1_code_cache_enabled &&
+ (blackfin->l1_map->l1_code_end == blackfin->l1_map->l1_code_cache)
+ && (end = blackfin->l1_map->l1_code_cache_end))
+ || (end = blackfin->l1_map->l1_code_end))
+ && addr + size <= end)
+ {
+ retval = sram_write(jtag_info, addr, size, buf, false);
+ icache_flush(jtag_info, addr, size);
+ goto done;
+ }
+ else if (IN_MAP (addr, blackfin->l1_map->l1_code_cache) &&
+ addr + size <= blackfin->l1_map->l1_code_cache_end)
+ {
+ if (blackfin->l1_code_cache_enabled)
+ {
+ LOG_ERROR("cannot write L1 icache when enabled [0x%08X] size %d", addr, size);
+ return ERROR_FAIL;
+ }
+
+ retval = sram_write(jtag_info, addr, size, buf, false);
+ goto done;
+ }
+ else if (IN_MAP (addr, blackfin->l1_map->l1_data_a) &&
+ ((!blackfin->l1_data_a_cache_enabled &&
+ (blackfin->l1_map->l1_data_a_end == blackfin->l1_map->l1_data_a_cache)
+ && (end = blackfin->l1_map->l1_data_a_cache_end))
+ || (end = blackfin->l1_map->l1_data_a_end))
+ && addr + size <= end)
+ {
+ retval = memory_write(jtag_info, addr, size, buf);
+ goto done;
+ }
+ else if (IN_MAP (addr, blackfin->l1_map->l1_data_a_cache) &&
+ addr + size <= blackfin->l1_map->l1_data_a_cache_end)
+ {
+ if (blackfin->l1_data_a_cache_enabled)
+ {
+ LOG_ERROR("cannot write L1 dcache when enabled [0x%08X] size %d", addr, size);
+ return ERROR_FAIL;
+ }
+
+ retval = memory_write(jtag_info, addr, size, buf);
+ goto done;
+ }
+ else if (IN_MAP(addr, blackfin->l1_map->l1_data_b) &&
+ ((!blackfin->l1_data_b_cache_enabled &&
+ (blackfin->l1_map->l1_data_b_end == blackfin->l1_map->l1_data_b_cache)
+ && (end = blackfin->l1_map->l1_data_b_cache_end))
+ || (end = blackfin->l1_map->l1_data_b_end))
+ && addr + size <= end)
+ {
+ retval = memory_write(jtag_info, addr, size, buf);
+ goto done;
+ }
+ else if (IN_MAP(addr, blackfin->l1_map->l1_data_b_cache) &&
+ addr + size <= blackfin->l1_map->l1_data_b_cache_end)
+ {
+ if (blackfin->l1_data_b_cache_enabled)
+ {
+ LOG_ERROR("cannot write L1 dcache when enabled [0x%08X] size %d", addr, size);
+ return ERROR_FAIL;
+ }
+
+ retval = memory_write(jtag_info, addr, size, buf);
+ goto done;
+ }
+ else if (IN_MAP(addr, blackfin->l1_map->l1_scratch) &&
+ addr + size <= blackfin->l1_map->l1_scratch_end)
+ {
+ retval = memory_write(jtag_info, addr, size, buf);
+ goto done;
+ }
+ else if (IN_MAP(addr, blackfin->l1_map->l1))
+ {
+ LOG_ERROR("cannot write reserved L1 [0x%08X] size %d", addr, size);
+ return ERROR_FAIL;
+ }
+
+ skip_l1:
+
+ /* TODO Accurately check MMR validity. */
+
+ if ((IN_RANGE (addr, blackfin->mem_map->sysmmr, blackfin->mem_map->coremmr) &&
+ addr + size > blackfin->mem_map->coremmr)
+ || (addr >= blackfin->mem_map->coremmr && addr + size < addr))
+ {
+ LOG_ERROR("bad MMR addr or size [0x%08X] size %d", addr, size);
+ return ERROR_FAIL;
+ }
+
+ if (addr >= blackfin->mem_map->sysmmr)
+ {
+ if (size != 2 && size != 4)
+ {
+ LOG_ERROR("bad MMR size [0x%08X] size %d", addr, size);
+ return ERROR_FAIL;
+ }
+
+ if ((addr & 0x1) == 1)
+ {
+ LOG_ERROR("odd MMR addr [0x%08X]", addr);
+ return ERROR_FAIL;
+ }
+
+ value = *buf++;
+ value |= (*buf++) << 8;
+ if (size == 4)
+ {
+ value |= (*buf++) << 16;
+ value |= (*buf++) << 24;
+ }
+ mmr_write(jtag_info, addr, value, size);
+ retval = ERROR_OK;
+ goto done;
+ }
+
+ if ((IN_MAP (addr, blackfin->mem_map->sdram) &&
+ addr + size <= blackfin->mem_map->sdram_end)
+ || (IN_MAP (addr, blackfin->mem_map->async_mem) &&
+ addr + size <= blackfin->mem_map->async_mem_end)
+ || (IN_MAP (addr, blackfin->mem_map->l2_sram) &&
+ addr + size <= blackfin->mem_map->l2_sram_end))
+ {
+ retval = memory_write(jtag_info, addr, size, buf);
+ icache_flush(jtag_info, addr, size);
+ }
+ else
+ {
+ LOG_ERROR("cannot write memory [0x%08X]", addr);
+ return ERROR_FAIL;
+ }
+
+ done:
+
+ return retval;
+}
diff --git a/src/target/blackfin_mem.h b/src/target/blackfin_mem.h
new file mode 100644
index 0000000..aa6f0fb
--- /dev/null
+++ b/src/target/blackfin_mem.h
@@ -0,0 +1,86 @@
+/***************************************************************************
+ * Copyright (C) 2011 by Analog Devices, Inc. *
+ * Written by Jie Zhang <***@analog.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 BLACKFIN_MEM_H
+#define BLACKFIN_MEM_H
+
+struct blackfin_mem_map
+{
+ uint32_t sdram;
+ uint32_t sdram_end;
+ uint32_t async_mem;
+ uint32_t flash;
+ uint32_t flash_end;
+ uint32_t async_mem_end;
+ uint32_t boot_rom;
+ uint32_t boot_rom_end;
+ uint32_t l2_sram;
+ uint32_t l2_sram_end;
+ uint32_t l1;
+ uint32_t l1_end;
+ uint32_t sysmmr;
+ uint32_t coremmr;
+};
+
+struct blackfin_l1_map
+{
+ uint32_t l1;
+ uint32_t l1_data_a;
+ uint32_t l1_data_a_end;
+ uint32_t l1_data_a_cache;
+ uint32_t l1_data_a_cache_end;
+ uint32_t l1_data_b;
+ uint32_t l1_data_b_end;
+ uint32_t l1_data_b_cache;
+ uint32_t l1_data_b_cache_end;
+ uint32_t l1_code;
+ uint32_t l1_code_end;
+ uint32_t l1_code_cache;
+ uint32_t l1_code_cache_end;
+ uint32_t l1_code_rom;
+ uint32_t l1_code_rom_end;
+ uint32_t l1_scratch;
+ uint32_t l1_scratch_end;
+ uint32_t l1_end;
+};
+
+struct blackfin_sdram_config
+{
+ uint16_t sdrrc;
+ uint16_t sdbctl;
+ uint32_t sdgctl;
+};
+
+struct blackfin_ddr_config
+{
+ uint32_t ddrctl0;
+ uint32_t ddrctl1;
+ uint32_t ddrctl2;
+};
+
+extern int blackfin_read_mem(struct blackfin_jtag *jtag_info, uint32_t addr,
+ uint32_t size, uint8_t *buf);
+extern int blackfin_write_mem(struct blackfin_jtag *jtag_info, uint32_t addr,
+ uint32_t size, const uint8_t *buf);
+extern int blackfin_sdram_init(struct blackfin_jtag *jtag_info);
+extern int blackfin_ddr_init(struct blackfin_jtag *jtag_info);
+
+#endif /* BLACKFIN_MEM_H */
diff --git a/src/target/blackfin_memory_map.c b/src/target/blackfin_memory_map.c
new file mode 100644
index 0000000..f1f3701
--- /dev/null
+++ b/src/target/blackfin_memory_map.c
@@ -0,0 +1,267 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "helper/log.h"
+
+#include "target.h"
+#include "blackfin.h"
+#include "blackfin_memory_map.h"
+
+
+#if !defined(HAVE_LIBEXPAT)
+
+int parse_memory_map(struct target *target, const char *memory_map)
+{
+ LOG_WARNING("%s: cannot parse XML memory map; XML support was disabled at compile time", target_name(target));
+ return ERROR_FAIL;
+}
+
+#else /* HAVE_LIBEXPAT */
+
+#include "xml_support.h"
+
+struct memory_map_parsing_data
+{
+ const char *name;
+ struct blackfin_mem_map *mem_map;
+ struct blackfin_l1_map *l1_map;
+ char *processor;
+ char *core;
+ bool skip;
+};
+
+
+/* Callback called by Expat on start of element.
+ This function handles the following elements:
+ * processor: unused now
+ * core: contains the memory map for the core
+ * memory: a memory region
+ * property: unused now
+ The target name is in format PROCESSOR or PROCESSOR.CORE */
+static void memory_map_start_element(void *data_, const XML_Char *name,
+ const XML_Char **attrs)
+{
+ struct memory_map_parsing_data *data = data_;
+
+ if (strcmp(name, "processor") == 0)
+ {
+ const char *attr = xml_find_attribute(attrs, "name");
+ if (!attr)
+ attr = "";
+ data->processor = strdup(attr);
+ if (!data->processor)
+ LOG_ERROR("%s: strdup(%s) failed", data->name, attr);
+ }
+ else if (strcmp(name, "core") == 0)
+ {
+ char buf[40];
+ const char *attr = xml_find_attribute(attrs, "name");
+
+ if (!attr)
+ {
+ attr = "";
+ sprintf(buf, "%s", data->processor);
+ }
+ else
+ sprintf(buf, "%s.%s", data->processor, attr);
+
+ data->core = strdup(attr);
+ if (!data->core)
+ LOG_ERROR("%s: strdup(%s) failed", data->name, attr);
+
+ if (strcmp(buf, data->name) == 0)
+ data->skip = false;
+ else
+ data->skip = true;
+ }
+ else if (strcmp(name, "memory") == 0 && !data->skip)
+ {
+ const XML_Char *memory_name;
+ uint32_t *start = NULL, *end = NULL;
+
+ memory_name = xml_find_attribute(attrs, "name");
+ if (!data->core)
+ {
+ if (strcmp(memory_name, "sdram") == 0)
+ {
+ start = &data->mem_map->sdram;
+ end = &data->mem_map->sdram_end;
+ }
+ else if (strcmp(memory_name, "async_mem") == 0)
+ {
+ start = &data->mem_map->async_mem;
+ end = &data->mem_map->async_mem_end;
+ }
+ else if (strcmp(memory_name, "flash") == 0)
+ {
+ start = &data->mem_map->flash;
+ end = &data->mem_map->flash_end;
+ }
+ else if (strcmp(memory_name, "boot_rom") == 0)
+ {
+ start = &data->mem_map->boot_rom;
+ end = &data->mem_map->boot_rom_end;
+ }
+ else if (strcmp(memory_name, "l2_sram") == 0)
+ {
+ start = &data->mem_map->l2_sram;
+ end = &data->mem_map->l2_sram_end;
+ }
+ else if (strcmp(memory_name, "sysmmr") == 0)
+ {
+ start = &data->mem_map->sysmmr;
+ end = NULL;
+ }
+ else if (strcmp(memory_name, "coremmr") == 0)
+ {
+ start = &data->mem_map->coremmr;
+ end = NULL;
+ }
+ else if (strcmp(memory_name, "l1") == 0)
+ {
+ start = &data->mem_map->l1;
+ end = &data->mem_map->l1_end;
+ }
+ }
+ else
+ {
+ if (strcmp(memory_name, "l1") == 0)
+ {
+ start = &data->l1_map->l1;
+ end = &data->l1_map->l1_end;
+ }
+ else if (strcmp(memory_name, "l1_data_a") == 0)
+ {
+ start = &data->l1_map->l1_data_a;
+ end = &data->l1_map->l1_data_a_end;
+ }
+ else if (strcmp(memory_name, "l1_data_a_cache") == 0)
+ {
+ start = &data->l1_map->l1_data_a_cache;
+ end = &data->l1_map->l1_data_a_cache_end;
+ }
+ else if (strcmp(memory_name, "l1_data_b") == 0)
+ {
+ start = &data->l1_map->l1_data_b;
+ end = &data->l1_map->l1_data_b_end;
+ }
+ else if (strcmp(memory_name, "l1_data_b_cache") == 0)
+ {
+ start = &data->l1_map->l1_data_b_cache;
+ end = &data->l1_map->l1_data_b_cache_end;
+ }
+ else if (strcmp(memory_name, "l1_code") == 0)
+ {
+ start = &data->l1_map->l1_code;
+ end = &data->l1_map->l1_code_end;
+ }
+ else if (strcmp(memory_name, "l1_code_cache") == 0)
+ {
+ start = &data->l1_map->l1_code_cache;
+ end = &data->l1_map->l1_code_cache_end;
+ }
+ else if (strcmp(memory_name, "l1_code_rom") == 0)
+ {
+ start = &data->l1_map->l1_code_rom;
+ end = &data->l1_map->l1_code_rom_end;
+ }
+ else if (strcmp(memory_name, "l1_scratch") == 0)
+ {
+ start = &data->l1_map->l1_scratch;
+ end = &data->l1_map->l1_scratch_end;
+ }
+ }
+
+ if (xml_parse_uint32(xml_find_attribute(attrs, "start"), start) < 0)
+ return;
+
+ if (end)
+ {
+ if (xml_parse_uint32(xml_find_attribute(attrs, "length"), end) < 0)
+ return;
+ *end += *start;
+ }
+ }
+ else if (strcmp(name, "property") == 0)
+ {
+ /* Ignore for now */
+ }
+}
+
+static void memory_map_end_element(void *data_, const XML_Char *name)
+{
+ struct memory_map_parsing_data *data = data_;
+
+ if (strcmp(name, "processor") == 0)
+ {
+ free(data->processor);
+ data->processor = NULL;
+ }
+ else if (strcmp(name, "core") == 0)
+ {
+ free(data->core);
+ data->core = NULL;
+ data->skip = false;
+ }
+}
+
+static void memory_map_character_data(void *data_, const XML_Char *s, int len)
+{
+ return;
+}
+
+int parse_memory_map(struct target *target, const char *memory_map)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(target);
+ int retval;
+
+ struct memory_map_parsing_data data;
+
+ data.name = blackfin->part;
+ data.mem_map = calloc(1, sizeof (struct blackfin_mem_map));
+ if (!data.mem_map)
+ {
+ LOG_ERROR("%s: malloc(%"PRIzu") failed",
+ target_name(target), sizeof (struct blackfin_mem_map));
+ return ERROR_FAIL;
+ }
+ data.l1_map = calloc(1, sizeof (struct blackfin_l1_map));
+ if (!data.l1_map)
+ {
+ LOG_ERROR("%s: malloc(%"PRIzu") failed",
+ target_name(target), sizeof (struct blackfin_l1_map));
+ free(data.mem_map);
+ return ERROR_FAIL;
+ }
+ data.processor = NULL;
+ data.core = NULL;
+ data.skip = false;
+
+ XML_Parser parser = XML_ParserCreateNS(NULL, '!');
+ if (parser == NULL)
+ return ERROR_FAIL;
+
+ XML_SetElementHandler(parser, memory_map_start_element, memory_map_end_element);
+ XML_SetCharacterDataHandler(parser, memory_map_character_data);
+ XML_SetUserData(parser, &data);
+
+ retval = XML_Parse(parser, memory_map, strlen(memory_map), 1);
+ if (retval != XML_STATUS_OK)
+ {
+ enum XML_Error err = XML_GetErrorCode(parser);
+ LOG_ERROR("%s: cannot parse XML memory map [%s]",
+ target_name(target), XML_ErrorString(err));
+ free(data.mem_map);
+ free(data.l1_map);
+ return ERROR_FAIL;
+ }
+
+ blackfin->mem_map = data.mem_map;
+ blackfin->l1_map = data.l1_map;
+
+ return ERROR_OK;
+}
+
+#endif
+
diff --git a/src/target/blackfin_memory_map.h b/src/target/blackfin_memory_map.h
new file mode 100644
index 0000000..4455182
--- /dev/null
+++ b/src/target/blackfin_memory_map.h
@@ -0,0 +1,6 @@
+#ifndef BLACKFIN_MEMORY_MAP_H
+#define BLACKFIN_MEMORY_MAP_H
+
+extern int parse_memory_map(struct target *target, const char *memory_map);
+
+#endif
diff --git a/src/target/cortex_a.c b/src/target/cortex_a.c
index 207fb81..e087923 100644
--- a/src/target/cortex_a.c
+++ b/src/target/cortex_a.c
@@ -55,6 +55,8 @@
#include "target_request.h"
#include "target_type.h"
#include "arm_opcodes.h"
+#include "arm_semihosting.h"
+#include "cortex_a_memory_map.h"
#include <helper/time_support.h>
static int cortex_a_poll(struct target *target);
@@ -75,9 +77,11 @@ static int cortex_a_dap_write_coreregister_u32(struct target *target,
static int cortex_a_mmu(struct target *target, int *enabled);
static int cortex_a_virt2phys(struct target *target,
uint32_t virt, uint32_t *phys);
+static int cortex_a_write_phys_memory(struct target *target,
+ uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer);
static int cortex_a_read_apb_ab_memory(struct target *target,
uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer);
-
+static int cortex_a_setup_semihosting(struct target *target, int enable);
/* restore cp15_control_reg at resume */
static int cortex_a_restore_cp15_control_reg(struct target *target)
@@ -96,7 +100,7 @@ static int cortex_a_restore_cp15_control_reg(struct target *target)
}
return retval;
}
-
+#if 0
/* check address before cortex_a_apb read write access with mmu on
* remove apb predictible data abort */
static int cortex_a_check_address(struct target *target, uint32_t address)
@@ -124,6 +128,7 @@ static int cortex_a_check_address(struct target *target, uint32_t address)
}
return ERROR_OK;
}
+#endif
/* modify cp15_control_reg in order to enable or disable mmu for :
* - virt2phys address conversion
* - read or write memory in phys or virt address */
@@ -879,6 +884,10 @@ static int cortex_a_poll(struct target *target)
retval = cortex_a_debug_entry(target);
if (retval != ERROR_OK)
return retval;
+ /* cortex_a_debug_entry could resume target to ignore
+ a halting event */
+ if (target->state == TARGET_RUNNING)
+ return ERROR_OK;
if (target->smp) {
retval = update_halt_gdb(target);
if (retval != ERROR_OK)
@@ -972,6 +981,11 @@ static int cortex_a_internal_restore(struct target *target, int current,
if (!debug_execution)
target_free_all_working_areas(target);
+ if (arm->hit_syscall) {
+ arm_semihosting_step_over_svc(target);
+ arm->hit_syscall = false;
+ }
+
#if 0
if (debug_execution) {
/* Disable interrupts */
@@ -1083,9 +1097,16 @@ static int cortex_a_internal_restart(struct target *target)
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 (target->restart_use_cti) {
+ // Send DBGRESTART signal
+ uint8_t value[4] = {0, 0, 0, 0};
+ value[0] = 1 << target->restart_cti_channel;
+ retval = cortex_a_write_phys_memory(target, target->restart_cti_reg_addr, 1, 4, value);
+ } else {
+ 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;
@@ -1168,6 +1189,78 @@ static int cortex_a_resume(struct target *target, int current,
return ERROR_OK;
}
+static int cortex_a_step_quiet(struct target *target)
+{
+ struct armv7a_common *armv7a = target_to_armv7a(target);
+ struct arm *arm = &armv7a->arm;
+ struct adiv5_dap *swjdp = armv7a->arm.dap;
+ struct breakpoint stepbreakpoint;
+ struct reg *r = arm->pc;
+ uint32_t address = buf_get_u32(r->value, 0, 32);
+ int retval;
+ uint32_t dscr;
+ int semihosting_disabled = 0;
+
+ if (arm->is_semihosting) {
+ uint32_t vector_base;
+
+ /* MRC p15,0,<Rt>,c12,c0,0 ; Read Vector Base Register */
+ retval = arm->mrc(target, 15,
+ 0, 0, /* op1, op2 */
+ 12, 0, /* CRn, CRm */
+ &vector_base);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* TODO We should check DBGVCR.V */
+ if (address == vector_base + 0x8 || address == 0xffff0008) {
+ cortex_a_setup_semihosting(target, 0);
+ semihosting_disabled = 1;
+ }
+ }
+
+ /* 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_a_set_breakpoint(target, &stepbreakpoint, 0x04);
+
+ retval = cortex_a_resume(target, 1, address, 0, 0);
+ if (retval != ERROR_OK)
+ return retval;
+
+ while (target->state != TARGET_HALTED) {
+ 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_RUN_MODE(dscr) == (DSCR_CORE_HALTED | DSCR_CORE_RESTARTED))
+ target->state = TARGET_HALTED;
+ }
+
+ /* 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;
+
+ retval = arm_dpm_read_current_registers(&armv7a->dpm);
+ if (retval != ERROR_OK)
+ return retval;
+
+ cortex_a_unset_breakpoint(target, &stepbreakpoint);
+
+ if (semihosting_disabled)
+ cortex_a_setup_semihosting(target, 1);
+
+ return ERROR_OK;
+}
+
static int cortex_a_debug_entry(struct target *target)
{
int i;
@@ -1286,6 +1379,15 @@ static int cortex_a_debug_entry(struct target *target)
return retval;
}
+ if (DSCR_ENTRY(dscr) == DSCR_ENTRY_VECT_CATCH) {
+ if (arm_semihosting(target))
+ arm->hit_syscall = true;
+ else if (!cortex_a->is_stepping) {
+ cortex_a_step_quiet(target);
+ cortex_a_resume(target, 1, 0, 0, 0);
+ }
+ }
+
return retval;
}
@@ -1326,18 +1428,25 @@ static int cortex_a_post_debug_entry(struct target *target)
static int cortex_a_step(struct target *target, int current, uint32_t address,
int handle_breakpoints)
{
+ struct cortex_a_common *cortex_a = target_to_cortex_a(target);
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;
+ int semihosting_disabled = 0;
if (target->state != TARGET_HALTED) {
LOG_WARNING("target not halted");
return ERROR_TARGET_NOT_HALTED;
}
+ if (arm->hit_syscall) {
+ retval = cortex_a_internal_restore(target, current, &address, handle_breakpoints, 0);
+ return retval;
+ }
+
/* current = 1: continue on current pc, otherwise continue at <address> */
r = arm->pc;
if (!current)
@@ -1345,6 +1454,24 @@ static int cortex_a_step(struct target *target, int current, uint32_t address,
else
address = buf_get_u32(r->value, 0, 32);
+ if (arm->is_semihosting) {
+ uint32_t vector_base;
+
+ /* MRC p15,0,<Rt>,c12,c0,0 ; Read Vector Base Register */
+ retval = arm->mrc(target, 15,
+ 0, 0, /* op1, op2 */
+ 12, 0, /* CRn, CRm */
+ &vector_base);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* TODO We should check DBGVCR.V */
+ if (address == vector_base + 0x8 || address == 0xffff0008) {
+ cortex_a_setup_semihosting(target, 0);
+ semihosting_disabled = 1;
+ }
+ }
+
/* The front-end may request us not to handle breakpoints.
* But since Cortex-A uses breakpoint for single step,
* we MUST handle breakpoints.
@@ -1366,6 +1493,8 @@ static int cortex_a_step(struct target *target, int current, uint32_t address,
/* Break on IVA mismatch */
cortex_a_set_breakpoint(target, &stepbreakpoint, 0x04);
+ cortex_a->is_stepping = 1;
+
target->debug_reason = DBG_REASON_SINGLESTEP;
retval = cortex_a_resume(target, 1, address, 0, 0);
@@ -1383,6 +1512,8 @@ static int cortex_a_step(struct target *target, int current, uint32_t address,
}
}
+ cortex_a->is_stepping = 0;
+
cortex_a_unset_breakpoint(target, &stepbreakpoint);
target->debug_reason = DBG_REASON_BREAKPOINT;
@@ -1393,6 +1524,9 @@ static int cortex_a_step(struct target *target, int current, uint32_t address,
if (target->state != TARGET_HALTED)
LOG_DEBUG("target stepped");
+ if (semihosting_disabled)
+ cortex_a_setup_semihosting(target, 1);
+
return ERROR_OK;
}
@@ -2571,31 +2705,53 @@ static int cortex_a_read_phys_memory(struct target *target,
uint32_t address, uint32_t size,
uint32_t count, uint8_t *buffer)
{
+ int mmu_enabled = 0;
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%" PRIx32 "; size %" PRId32 "; count %" PRId32,
address, size, count);
if (count && buffer) {
- if (armv7a->memory_ap_available && (apsel == armv7a->memory_ap)) {
+ if (armv7a->memory_ap_available
+ && address >= swjdp->ahb_mem_start_address
+ && address + size * count <= swjdp->ahb_mem_end_address) {
/* read memory through AHB-AP */
retval = mem_ap_sel_read_buf(swjdp, armv7a->memory_ap, buffer, size, count, address);
- } else {
+ } else if (target->state == TARGET_HALTED) {
- /* read memory through APB-AP */
+ /* determine if MMU was enabled on target stop */
if (!armv7a->is_armv7r) {
+ retval = cortex_a_mmu(target, &mmu_enabled);
+ if (retval != ERROR_OK)
+ return retval;
+ }
+
+ /* read memory through APB-AP */
+ if (mmu_enabled) {
/* disable mmu */
retval = cortex_a_mmu_modify(target, 0);
if (retval != ERROR_OK)
return retval;
}
+
retval = cortex_a_read_apb_ab_memory(target, address, size, count, buffer);
+ if (retval != ERROR_OK)
+ return retval;
+
+ if (mmu_enabled) {
+ /* enable mmu */
+ retval = cortex_a_mmu_modify(target, 1);
+ if (retval != ERROR_OK)
+ return retval;
+ }
+ } else {
+ retval = ERROR_TARGET_NOT_HALTED;
}
}
+
return retval;
}
@@ -2603,11 +2759,8 @@ static int cortex_a_read_memory(struct target *target, uint32_t address,
uint32_t size, uint32_t count, uint8_t *buffer)
{
int mmu_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_a handles unaligned memory access */
LOG_DEBUG("Reading memory at address 0x%" PRIx32 "; size %" PRId32 "; count %" PRId32, address,
@@ -2619,32 +2772,22 @@ static int cortex_a_read_memory(struct target *target, uint32_t address,
if (retval != ERROR_OK)
return retval;
}
+ /*
+ if (mmu_enabled) {
+ retval = cortex_a_check_address(target, address);
+ if (retval != ERROR_OK)
+ return retval;
+ }
+ */
+ if (target->state != TARGET_HALTED) {
- if (armv7a->memory_ap_available && (apsel == armv7a->memory_ap)) {
- if (mmu_enabled) {
- virt = address;
- retval = cortex_a_virt2phys(target, virt, &phys);
- if (retval != ERROR_OK)
- return retval;
-
- LOG_DEBUG("Reading at virtual address. Translating v:0x%" PRIx32 " to r:0x%" PRIx32,
- virt, phys);
- address = phys;
- }
- retval = cortex_a_read_phys_memory(target, address, size,
- count, buffer);
- } else {
- if (mmu_enabled) {
- retval = cortex_a_check_address(target, address);
- if (retval != ERROR_OK)
- return retval;
- /* enable MMU as we could have disabled it for phys access */
- retval = cortex_a_mmu_modify(target, 1);
- if (retval != ERROR_OK)
- return retval;
- }
+ if (mmu_enabled)
+ retval = ERROR_TARGET_NOT_HALTED;
+ else
+ retval = cortex_a_read_phys_memory(target, address, size, count, buffer);
+ } else
retval = cortex_a_read_apb_ab_memory(target, address, size, count, buffer);
- }
+
return retval;
}
@@ -2652,85 +2795,50 @@ static int cortex_a_write_phys_memory(struct target *target,
uint32_t address, uint32_t size,
uint32_t count, const uint8_t *buffer)
{
+ int mmu_enabled = 0;
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%" PRIx32 "; size %" PRId32 "; count %" PRId32, address,
size, count);
if (count && buffer) {
- if (armv7a->memory_ap_available && (apsel == armv7a->memory_ap)) {
+ if (armv7a->memory_ap_available
+ && address >= swjdp->ahb_mem_start_address
+ && address + size * count <= swjdp->ahb_mem_end_address) {
/* write memory through AHB-AP */
retval = mem_ap_sel_write_buf(swjdp, armv7a->memory_ap, buffer, size, count, address);
- } else {
+ } else if (target->state == TARGET_HALTED) {
- /* write memory through APB-AP */
+ /* determine if MMU was enabled on target stop */
if (!armv7a->is_armv7r) {
- retval = cortex_a_mmu_modify(target, 0);
+ retval = cortex_a_mmu(target, &mmu_enabled);
if (retval != ERROR_OK)
return retval;
}
- return cortex_a_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-A 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 = 0;
- cacheline < size * count;
- cacheline += 64) {
- retval = dpm->instr_write_data_r0(dpm,
- ARMV4_5_MCR(15, 0, 0, 7, 5, 1),
- address + cacheline);
+ /* write memory through APB-AP */
+ if (mmu_enabled) {
+ retval = cortex_a_mmu_modify(target, 0);
if (retval != ERROR_OK)
return retval;
}
- }
+ retval = cortex_a_write_apb_ab_memory(target, address, size, count, buffer);
+ 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 = 0;
- cacheline < size * count;
- cacheline += 64) {
- retval = dpm->instr_write_data_r0(dpm,
- ARMV4_5_MCR(15, 0, 0, 7, 6, 1),
- address + cacheline);
+ if (mmu_enabled) {
+ /* enable mmu */
+ retval = cortex_a_mmu_modify(target, 1);
if (retval != ERROR_OK)
return retval;
}
+ } else {
+ retval = ERROR_TARGET_NOT_HALTED;
}
-
- /* (void) */ dpm->finish(dpm);
}
return retval;
@@ -2740,11 +2848,8 @@ static int cortex_a_write_memory(struct target *target, uint32_t address,
uint32_t size, uint32_t count, const uint8_t *buffer)
{
int mmu_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_a handles unaligned memory access */
LOG_DEBUG("Writing memory at address 0x%" PRIx32 "; size %" PRId32 "; count %" PRId32, address,
@@ -2756,35 +2861,48 @@ static int cortex_a_write_memory(struct target *target, uint32_t address,
if (retval != ERROR_OK)
return retval;
}
+ /*
+ if (mmu_enabled) {
+ retval = cortex_a_check_address(target, address);
+ if (retval != ERROR_OK)
+ return retval;
+ }
+ */
+ if (target->state != TARGET_HALTED) {
- if (armv7a->memory_ap_available && (apsel == armv7a->memory_ap)) {
- LOG_DEBUG("Writing memory to address 0x%" PRIx32 "; size %" PRId32 "; count %" PRId32, address, size,
- count);
- if (mmu_enabled) {
- virt = address;
- retval = cortex_a_virt2phys(target, virt, &phys);
- if (retval != ERROR_OK)
- return retval;
-
- LOG_DEBUG("Writing to virtual address. Translating v:0x%" PRIx32 " to r:0x%" PRIx32,
- virt,
- phys);
- address = phys;
- }
- retval = cortex_a_write_phys_memory(target, address, size,
- count, buffer);
+ if (mmu_enabled)
+ retval = ERROR_TARGET_NOT_HALTED;
+ else
+ retval = cortex_a_write_phys_memory(target, address, size, count, buffer);
} else {
- if (mmu_enabled) {
- retval = cortex_a_check_address(target, address);
- if (retval != ERROR_OK)
- return retval;
- /* enable MMU as we could have disabled it for phys access */
- retval = cortex_a_mmu_modify(target, 1);
+ retval = cortex_a_write_apb_ab_memory(target, address, size, count, buffer);
+#if 0
+ {
+ uint8_t *new_buf = malloc (size * count);
+ int i;
+ //retval = mem_ap_sel_read_buf(swjdp, armv7a->memory_ap, new_buf, size, count, address);
+ retval = cortex_a_read_apb_ab_memory(target, address, size, count, new_buf);
if (retval != ERROR_OK)
return retval;
+ for (i = 0; i < size * count; i++)
+ if (buffer[i] != new_buf[i]) {
+ uint32_t r0;
+ cortex_a_dap_read_coreregister_u32(target, &r0, 0);
+ return ERROR_FAIL;
+ }
}
- retval = cortex_a_write_apb_ab_memory(target, address, size, count, buffer);
+#endif
}
+ if (retval == ERROR_OK && mmu_enabled)
+ retval = armv7a_clean_data_cache(target, address, size, count);
+
+ if (retval == ERROR_OK)
+ retval = armv7a_invalidate_instruction_cache(target, address, size, count);
+
+ if (retval == ERROR_OK && !mmu_enabled
+ && armv7a->armv7a_mmu.armv7a_cache.l2_cache)
+ retval = armv7a_l2x_invalidate_all_data(target);
+
return retval;
}
@@ -2999,6 +3117,21 @@ static int cortex_a_examine(struct target *target)
return retval;
}
+static int cortex_a_setup_semihosting(struct target *target, int enable)
+{
+ struct armv7a_common *armv7a = target_to_armv7a(target);
+ struct adiv5_dap *swjdp = armv7a->arm.dap;
+ uint32_t vcr;
+
+ mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap, armv7a->debug_base + CPUDBG_VCR, &vcr);
+ if (enable)
+ mem_ap_sel_write_atomic_u32(swjdp, armv7a->debug_ap, armv7a->debug_base + CPUDBG_VCR, vcr | VCR_SVC);
+ else
+ mem_ap_sel_write_atomic_u32(swjdp, armv7a->debug_ap, armv7a->debug_base + CPUDBG_VCR, vcr & ~VCR_SVC);
+
+ return ERROR_OK;
+}
+
/*
* Cortex-A target creation and initialization
*/
@@ -3006,15 +3139,27 @@ static int cortex_a_examine(struct target *target)
static int cortex_a_init_target(struct command_context *cmd_ctx,
struct target *target)
{
- /* examine_first() does a bunch of this */
+ target->fileio_info = malloc(sizeof(struct gdb_fileio_info));
+ target->fileio_info->identifier = NULL;
+
return ERROR_OK;
}
static int cortex_a_init_arch_info(struct target *target,
- struct cortex_a_common *cortex_a, struct jtag_tap *tap)
+ struct cortex_a_common *cortex_a, struct jtag_tap *tap,
+ Jim_Interp *interp)
{
struct armv7a_common *armv7a = &cortex_a->armv7a_common;
struct adiv5_dap *dap = &armv7a->dap;
+ struct Jim_Obj *objPtr;
+ const char *map;
+
+ armv7a->arm.setup_semihosting = cortex_a_setup_semihosting;
+ armv7a->arm.is_semihosting = false;
+ armv7a->arm.hit_syscall = false;
+ armv7a->arm.active_syscall_id = 0;
+ armv7a->arm.semihosting_errno = 0;
+ armv7a->arm.semihosting_ctrl_c = false;
armv7a->arm.dap = dap;
@@ -3041,6 +3186,8 @@ static int cortex_a_init_arch_info(struct target *target,
cortex_a->fast_reg_read = 0;
+ cortex_a->is_stepping = 0;
+
/* register arch-specific functions */
armv7a->examine_debug_reason = NULL;
@@ -3055,6 +3202,16 @@ static int cortex_a_init_arch_info(struct target *target,
/* REVISIT v7a setup should be in a v7a-specific routine */
armv7a_init_arch_info(target, armv7a);
+
+ objPtr = Jim_GetGlobalVariableStr(interp, "MEMORY_MAP", JIM_NONE);
+ if (objPtr) {
+ map = Jim_GetString(objPtr, NULL);
+ cortex_a_parse_memory_map(target, map);
+ } else {
+ dap->ahb_mem_start_address = 0;
+ dap->ahb_mem_end_address = 0xffffffff;
+ }
+
target_register_timer_callback(cortex_a_handle_target_request, 1, 1, target);
return ERROR_OK;
@@ -3066,7 +3223,7 @@ static int cortex_a_target_create(struct target *target, Jim_Interp *interp)
cortex_a->armv7a_common.is_armv7r = false;
- return cortex_a_init_arch_info(target, cortex_a, target->tap);
+ return cortex_a_init_arch_info(target, cortex_a, target->tap, interp);
}
static int cortex_r4_target_create(struct target *target, Jim_Interp *interp)
@@ -3075,7 +3232,7 @@ static int cortex_r4_target_create(struct target *target, Jim_Interp *interp)
cortex_a->armv7a_common.is_armv7r = true;
- return cortex_a_init_arch_info(target, cortex_a, target->tap);
+ return cortex_a_init_arch_info(target, cortex_a, target->tap, interp);
}
@@ -3193,6 +3350,53 @@ COMMAND_HANDLER(cortex_a_handle_smp_gdb_command)
return ERROR_OK;
}
+COMMAND_HANDLER(cortex_a_handle_mmu_command)
+{
+ struct target *target = get_current_target(CMD_CTX);
+ struct armv7a_common *armv7a = target_to_armv7a(target);
+ struct arm *arm = &armv7a->arm;
+ int 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;
+ uint32_t sctlr;
+
+ COMMAND_PARSE_ENABLE(CMD_ARGV[0], enable);
+
+ /* MRC p15, 0, <Rt>, c1, c0, 0 ; Read SCTLR */
+ retval = arm->mrc(target, 15,
+ 0, 0, /* op1, op2 */
+ 1, 0, /* CRn, CRm */
+ &sctlr);
+ if (retval != ERROR_OK)
+ return retval;
+
+ if (enable)
+ sctlr |= 0x1;
+ else
+ sctlr &= ~0x1;
+
+ /* MCR p15, 0, <Rt>, c1, c0, 0 ; Write SCTLR */
+ retval = arm->mcr(target, 15,
+ 0, 0, /* op1, op2 */
+ 1, 0, /* CRn, CRm */
+ sctlr);
+ if (retval != ERROR_OK)
+ return retval;
+
+ armv7a->armv7a_mmu.mmu_enabled = enable;
+ }
+
+ command_print(CMD_CTX, "mmu %s",
+ (armv7a->armv7a_mmu.mmu_enabled) ? "enabled" : "disabled");
+
+ return ERROR_OK;
+}
static const struct command_registration cortex_a_exec_command_handlers[] = {
{
.name = "cache_info",
@@ -3227,6 +3431,13 @@ static const struct command_registration cortex_a_exec_command_handlers[] = {
.help = "display/fix current core played to gdb",
.usage = "",
},
+ {
+ .name = "mmu",
+ .handler = cortex_a_handle_mmu_command,
+ .mode = COMMAND_EXEC,
+ .help = "enable or disable the MMU",
+ .usage = "['enable'|'disable']",
+ },
COMMAND_REGISTRATION_DONE
@@ -3279,6 +3490,7 @@ struct target_type cortexa_target = {
.remove_breakpoint = cortex_a_remove_breakpoint,
.add_watchpoint = NULL,
.remove_watchpoint = NULL,
+ .hit_watchpoint = NULL,
.commands = cortex_a_command_handlers,
.target_create = cortex_a_target_create,
@@ -3289,6 +3501,10 @@ struct target_type cortexa_target = {
.write_phys_memory = cortex_a_write_phys_memory,
.mmu = cortex_a_mmu,
.virt2phys = cortex_a_virt2phys,
+
+ .get_gdb_fileio_info = arm_get_gdb_fileio_info,
+ .gdb_fileio_end = arm_gdb_fileio_end,
+ .pre_write_buffer = arm_gdb_fileio_pre_write_buffer,
};
static const struct command_registration cortex_r4_exec_command_handlers[] = {
diff --git a/src/target/cortex_a.h b/src/target/cortex_a.h
index ebf79b8..0a86eac 100644
--- a/src/target/cortex_a.h
+++ b/src/target/cortex_a.h
@@ -91,8 +91,9 @@ struct cortex_a_common {
uint32_t ttypr;
uint32_t didr;
- struct armv7a_common armv7a_common;
+ int is_stepping;
+ struct armv7a_common armv7a_common;
};
static inline struct cortex_a_common *
diff --git a/src/target/cortex_a_memory_map.c b/src/target/cortex_a_memory_map.c
new file mode 100644
index 0000000..7c4205c
--- /dev/null
+++ b/src/target/cortex_a_memory_map.c
@@ -0,0 +1,130 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "helper/log.h"
+
+#include "target.h"
+#include "armv7a.h"
+#include "cortex_a_memory_map.h"
+
+
+#if !defined(HAVE_LIBEXPAT)
+
+int cortex_a_parse_memory_map(struct target *target, const char *memory_map)
+{
+ LOG_WARNING("%s: cannot parse XML memory map; XML support was disabled at compile time", target_name(target));
+ return ERROR_FAIL;
+}
+
+#else /* HAVE_LIBEXPAT */
+
+#include "xml_support.h"
+
+struct cortex_a_memory_map_parsing_data
+{
+ char *processor;
+ uint32_t ahb_mem;
+ uint32_t ahb_mem_end;
+};
+
+
+/* Callback called by Expat on start of element.
+ This function handles the following elements:
+ * processor: unused now
+ * memory: a memory region
+ * property: unused now
+ The target name is in format PROCESSOR */
+static void memory_map_start_element(void *data_, const XML_Char *name,
+ const XML_Char **attrs)
+{
+ struct cortex_a_memory_map_parsing_data *data = data_;
+
+ if (strcmp(name, "processor") == 0)
+ {
+ const char *attr = xml_find_attribute(attrs, "name");
+ if (!attr)
+ attr = "";
+ data->processor = strdup(attr);
+ if (!data->processor)
+ LOG_ERROR("cortex_a: strdup(%s) failed", attr);
+ }
+ else if (strcmp(name, "memory") == 0)
+ {
+ const XML_Char *memory_name;
+ uint32_t *start = NULL, *end = NULL;
+
+ memory_name = xml_find_attribute(attrs, "name");
+ if (strcmp(memory_name, "ahb_mem") == 0)
+ {
+ start = &data->ahb_mem;
+ end = &data->ahb_mem_end;
+ }
+
+ if (xml_parse_uint32(xml_find_attribute(attrs, "start"), start) < 0)
+ return;
+
+ if (end)
+ {
+ if (xml_parse_uint32(xml_find_attribute(attrs, "length"), end) < 0)
+ return;
+ *end += *start - 1;
+ }
+ }
+ else if (strcmp(name, "property") == 0)
+ {
+ /* Ignore for now */
+ }
+}
+
+static void memory_map_end_element(void *data_, const XML_Char *name)
+{
+ struct cortex_a_memory_map_parsing_data *data = data_;
+
+ if (strcmp(name, "processor") == 0)
+ {
+ free(data->processor);
+ data->processor = NULL;
+ }
+}
+
+static void memory_map_character_data(void *data_, const XML_Char *s, int len)
+{
+ return;
+}
+
+int cortex_a_parse_memory_map(struct target *target, const char *memory_map)
+{
+ struct armv7a_common *armv7a = target_to_armv7a(target);
+ struct adiv5_dap *dap = armv7a->arm.dap;
+ int retval;
+
+ struct cortex_a_memory_map_parsing_data data;
+
+ data.processor = NULL;
+
+ XML_Parser parser = XML_ParserCreateNS(NULL, '!');
+ if (parser == NULL)
+ return ERROR_FAIL;
+
+ XML_SetElementHandler(parser, memory_map_start_element, memory_map_end_element);
+ XML_SetCharacterDataHandler(parser, memory_map_character_data);
+ XML_SetUserData(parser, &data);
+
+ retval = XML_Parse(parser, memory_map, strlen(memory_map), 1);
+ if (retval != XML_STATUS_OK)
+ {
+ enum XML_Error err = XML_GetErrorCode(parser);
+ LOG_ERROR("%s: cannot parse XML memory map [%s]",
+ target_name(target), XML_ErrorString(err));
+ return ERROR_FAIL;
+ }
+
+ dap->ahb_mem_start_address = data.ahb_mem;
+ dap->ahb_mem_end_address = data.ahb_mem_end;
+
+ return ERROR_OK;
+}
+
+#endif
+
diff --git a/src/target/cortex_a_memory_map.h b/src/target/cortex_a_memory_map.h
new file mode 100644
index 0000000..8f4aa25
--- /dev/null
+++ b/src/target/cortex_a_memory_map.h
@@ -0,0 +1,6 @@
+#ifndef CORTEX_A_MEMORY_MAP_H
+#define CORTEX_A_MEMORY_MAP_H
+
+extern int cortex_a_parse_memory_map(struct target *target, const char *memory_map);
+
+#endif
diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c
index 2cb83a4..06a67e3 100644
--- a/src/target/cortex_m.c
+++ b/src/target/cortex_m.c
@@ -56,7 +56,9 @@
/**
* Returns the type of a break point required by address location
*/
-#define BKPT_TYPE_BY_ADDR(addr) ((addr) < 0x20000000 ? BKPT_HARD : BKPT_SOFT)
+/* #define BKPT_TYPE_BY_ADDR(addr) ((addr) < 0x20000000 ? BKPT_HARD : BKPT_SOFT) */
+/* This is only for ADuCM302x */
+#define BKPT_TYPE_BY_ADDR(addr) ((addr) < 0x40800 ? BKPT_HARD : BKPT_SOFT)
/* forward declarations */
static int cortex_m_store_core_reg_u32(struct target *target,
@@ -168,39 +170,6 @@ static int cortex_m_clear_halt(struct target *target)
return ERROR_OK;
}
-static int cortex_m_single_step_core(struct target *target)
-{
- struct cortex_m_common *cortex_m = target_to_cm(target);
- struct adiv5_dap *swjdp = cortex_m->armv7m.arm.dap;
- uint32_t dhcsr_save;
- int retval;
-
- /* backup dhcsr reg */
- dhcsr_save = cortex_m->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_m->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_m->dcb_dhcsr = dhcsr_save;
- cortex_m_clear_halt(target);
-
- return ERROR_OK;
-}
-
static int cortex_m_enable_fpb(struct target *target)
{
int retval = target_write_u32(target, FP_CTRL, 3);
@@ -549,8 +518,8 @@ static int cortex_m_poll(struct target *target)
if (retval != ERROR_OK)
return retval;
- if (arm_semihosting(target, &retval) != 0)
- return retval;
+ if (arm_semihosting(target))
+ cortex_m->armv7m.arm.hit_syscall = true;
target_call_event_callbacks(target, TARGET_EVENT_HALTED);
}
@@ -690,7 +659,6 @@ static int cortex_m_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;
@@ -699,6 +667,11 @@ static int cortex_m_resume(struct target *target, int current,
return ERROR_TARGET_NOT_HALTED;
}
+ if (armv7m->arm.hit_syscall) {
+ arm_semihosting_step_over_bkpt(target);
+ armv7m->arm.hit_syscall = false;
+ }
+
if (!debug_execution) {
target_free_all_working_areas(target);
cortex_m_enable_breakpoints(target);
@@ -738,32 +711,10 @@ static int cortex_m_resume(struct target *target, int current,
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: %" PRIu32 ")",
- breakpoint->address,
- breakpoint->unique_id);
- cortex_m_unset_breakpoint(target, breakpoint);
- cortex_m_single_step_core(target);
- cortex_m_set_breakpoint(target, breakpoint);
- }
- }
-
/* Restart core */
cortex_m_write_debug_halt_mask(target, 0, C_HALT);
@@ -794,7 +745,6 @@ static int cortex_m_step(struct target *target, int current,
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;
@@ -803,6 +753,13 @@ static int cortex_m_step(struct target *target, int current,
return ERROR_TARGET_NOT_HALTED;
}
+ if (armv7m->arm.hit_syscall) {
+ arm_semihosting_step_over_bkpt(target);
+ armv7m->arm.hit_syscall = false;
+ target_call_event_callbacks(target, TARGET_EVENT_HALTED);
+ return ERROR_OK;
+ }
+
/* current = 1: continue on current pc, otherwise continue at <address> */
if (!current)
buf_set_u32(pc->value, 0, 32, address);
@@ -816,10 +773,6 @@ static int cortex_m_step(struct target *target, int current,
cortex_m_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);
@@ -827,7 +780,18 @@ static int cortex_m_step(struct target *target, int current,
/* 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) {
+
+ /* pretend that we hit a breakpoint and check if the instruction is a
+ semihosting call */
+ target->debug_reason = DBG_REASON_BREAKPOINT;
+ if (arm_semihosting(target)) {
+ armv7m->arm.hit_syscall = true;
+ target_call_event_callbacks(target, TARGET_EVENT_HALTED);
+ return ERROR_OK;
+ }
+
+ target->debug_reason = DBG_REASON_SINGLESTEP;
+
/* Automatic ISR masking mode off: Just step over the next instruction */
if ((cortex_m->isrmasking_mode != CORTEX_M_ISRMASK_AUTO))
cortex_m_write_debug_halt_mask(target, C_STEP, C_HALT);
@@ -926,7 +890,6 @@ static int cortex_m_step(struct target *target, int current,
}
}
}
- }
retval = mem_ap_read_atomic_u32(swjdp, DCB_DHCSR, &cortex_m->dcb_dhcsr);
if (retval != ERROR_OK)
@@ -1470,6 +1433,19 @@ int cortex_m_remove_watchpoint(struct target *target, struct watchpoint *watchpo
return ERROR_OK;
}
+static int cortex_m_hit_watchpoint(struct target *target, struct watchpoint **hit_watchpoint)
+{
+ struct watchpoint *watchpoint = target->watchpoints;
+
+ /* we only support only 1 watchpoint */
+ if (watchpoint) {
+ *hit_watchpoint = watchpoint;
+ return ERROR_OK;
+ }
+
+ return ERROR_FAIL;
+}
+
void cortex_m_enable_watchpoints(struct target *target)
{
struct watchpoint *watchpoint = target->watchpoints;
@@ -1685,6 +1661,9 @@ static int cortex_m_write_memory(struct target *target, uint32_t address,
static int cortex_m_init_target(struct command_context *cmd_ctx,
struct target *target)
{
+ target->fileio_info = malloc(sizeof(struct gdb_fileio_info));
+ target->fileio_info->identifier = NULL;
+
armv7m_build_reg_cache(target);
return ERROR_OK;
}
@@ -1982,6 +1961,11 @@ int cortex_m_examine(struct target *target)
target_name(target),
cortex_m->fp_num_code,
cortex_m->dwt_num_comp);
+
+ if (cortex_m->dwt_num_comp > 1) {
+ cortex_m->dwt_num_comp = 1;
+ LOG_INFO("%s: but you can only set 1 watchpoint", target_name(target));
+ }
}
return ERROR_OK;
@@ -2087,6 +2071,8 @@ static int cortex_m_init_arch_info(struct target *target,
* if not it will use CORTEX_M3_RESET_VECTRESET */
cortex_m->soft_reset_config = CORTEX_M_RESET_VECTRESET;
+ armv7m->arm.hit_syscall = false;
+
armv7m->arm.dap = &armv7m->dap;
/* Leave (only) generic DAP stuff for debugport_init(); */
@@ -2383,10 +2369,15 @@ struct target_type cortexm_target = {
.remove_breakpoint = cortex_m_remove_breakpoint,
.add_watchpoint = cortex_m_add_watchpoint,
.remove_watchpoint = cortex_m_remove_watchpoint,
+ .hit_watchpoint = cortex_m_hit_watchpoint,
.commands = cortex_m_command_handlers,
.target_create = cortex_m_target_create,
.init_target = cortex_m_init_target,
.examine = cortex_m_examine,
.deinit_target = cortex_m_deinit_target,
+
+ .get_gdb_fileio_info = arm_get_gdb_fileio_info,
+ .gdb_fileio_end = arm_gdb_fileio_end,
+ .pre_write_buffer = arm_gdb_fileio_pre_write_buffer,
};
diff --git a/src/target/hla_target.c b/src/target/hla_target.c
index d0be966..5859d26 100644
--- a/src/target/hla_target.c
+++ b/src/target/hla_target.c
@@ -463,9 +463,6 @@ static int adapter_poll(struct target *target)
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);
}
diff --git a/src/target/image.c b/src/target/image.c
index b1b7e3a..6bd4618 100644
--- a/src/target/image.c
+++ b/src/target/image.c
@@ -483,7 +483,7 @@ static int image_elf_read_section(struct image *image,
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,
+ LOG_DEBUG("read elf: size = 0x%"PRIzu" 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);
diff --git a/src/target/target.c b/src/target/target.c
index 4ea445f..5e24f7c 100644
--- a/src/target/target.c
+++ b/src/target/target.c
@@ -65,9 +65,9 @@ static int target_read_buffer_default(struct target *target, uint32_t address,
static int target_write_buffer_default(struct target *target, uint32_t address,
uint32_t count, const uint8_t *buffer);
static int target_array2mem(Jim_Interp *interp, struct target *target,
- int argc, Jim_Obj * const *argv);
+ int argc, Jim_Obj * const *argv, bool physical);
static int target_mem2array(Jim_Interp *interp, struct target *target,
- int argc, Jim_Obj * const *argv);
+ int argc, Jim_Obj * const *argv, bool physical);
static int target_register_user_commands(struct command_context *cmd_ctx);
static int target_get_gdb_fileio_info_default(struct target *target,
struct gdb_fileio_info *fileio_info);
@@ -104,6 +104,7 @@ extern struct target_type nds32_v3_target;
extern struct target_type nds32_v3m_target;
extern struct target_type or1k_target;
extern struct target_type quark_x10xx_target;
+extern struct target_type blackfin_target;
static struct target_type *target_types[] = {
&arm7tdmi_target,
@@ -133,6 +134,7 @@ static struct target_type *target_types[] = {
&nds32_v3m_target,
&or1k_target,
&quark_x10xx_target,
+ &blackfin_target,
NULL,
};
@@ -896,12 +898,15 @@ int target_run_flash_async_algorithm(struct target *target,
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;
+ /* make sure the size of FIFO is multiple of block_size */
+ assert((fifo_end_addr - fifo_start_addr) % block_size == 0);
/* validate block_size is 2^n */
assert(!block_size || !(block_size & (block_size - 1)));
+ uint32_t wp = fifo_start_addr;
+ uint32_t rp = fifo_start_addr;
+
retval = target_write_u32(target, wp_addr, wp);
if (retval != ERROR_OK)
return retval;
@@ -929,8 +934,8 @@ int target_run_flash_async_algorithm(struct target *target,
break;
}
- LOG_DEBUG("offs 0x%zx count 0x%" PRIx32 " wp 0x%" PRIx32 " rp 0x%" PRIx32,
- (size_t) (buffer - buffer_orig), count, wp, rp);
+ LOG_DEBUG("offs 0x%"PRIz"x count 0x%" PRIx32 " wp 0x%" PRIx32 " rp 0x%" PRIx32,
+ (buffer - buffer_orig), count, wp, rp);
if (rp == 0) {
LOG_ERROR("flash write algorithm aborted by target");
@@ -1208,6 +1213,8 @@ static int target_init_one(struct command_context *cmd_ctx,
return retval;
}
+ target->no_callbacks = false;
+
/* Sanity-check MMU support ... stub in what we must, to help
* implement it in stages, but warn if we need to do so.
*/
@@ -1985,6 +1992,12 @@ int target_write_buffer(struct target *target, uint32_t address, uint32_t size,
return ERROR_FAIL;
}
+ if (target->type->pre_write_buffer) {
+ int ret = target->type->pre_write_buffer(target, address, size, buffer);
+ if (ret == ERROR_OK)
+ return ret;
+ }
+
return target->type->write_buffer(target, address, size, buffer);
}
@@ -3346,7 +3359,7 @@ static COMMAND_HELPER(handle_verify_image_command_internal, int verify)
free(data);
}
} else {
- command_print(CMD_CTX, "address 0x%08" PRIx32 " length 0x%08zx",
+ command_print(CMD_CTX, "address 0x%08" PRIx32 " length 0x%08"PRIzx,
image.sections[i].base_address,
buf_cnt);
}
@@ -3626,7 +3639,7 @@ 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));
+ LOG_ERROR("failed to write %"PRIzu" bytes: %s", len, strerror(errno));
}
static void writeLong(FILE *f, int l, struct target *target)
@@ -3854,10 +3867,28 @@ static int jim_mem2array(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
return JIM_ERR;
}
- return target_mem2array(interp, target, argc - 1, argv + 1);
+ return target_mem2array(interp, target, argc - 1, argv + 1, false /* physical */);
}
-static int target_mem2array(Jim_Interp *interp, struct target *target, int argc, Jim_Obj *const *argv)
+static int jim_pmem2array(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, true /* physical */);
+}
+
+
+static int target_mem2array(Jim_Interp *interp, struct target *target, int argc, Jim_Obj *const *argv, bool physical)
{
long l;
uint32_t width;
@@ -3959,7 +3990,11 @@ static int target_mem2array(Jim_Interp *interp, struct target *target, int argc,
if (count > (buffersize / width))
count = (buffersize / width);
- retval = target_read_memory(target, addr, width, count, buffer);
+ if (physical)
+ retval = target_read_phys_memory(target, addr, width, count, buffer);
+ else
+ 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",
@@ -4042,11 +4077,28 @@ static int jim_array2mem(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
return JIM_ERR;
}
- return target_array2mem(interp, target, argc-1, argv + 1);
+ return target_array2mem(interp, target, argc-1, argv + 1, false /* physical */);
+}
+
+static int jim_array2pmem(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, true /* physical */);
}
static int target_array2mem(Jim_Interp *interp, struct target *target,
- int argc, Jim_Obj *const *argv)
+ int argc, Jim_Obj *const *argv, bool physical)
{
long l;
uint32_t width;
@@ -4169,7 +4221,11 @@ static int target_array2mem(Jim_Interp *interp, struct target *target,
}
len -= count;
- retval = target_write_memory(target, addr, width, count, buffer);
+ if (physical)
+ retval = target_write_phys_memory(target, addr, width, count, buffer);
+ else
+ 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",
@@ -4241,6 +4297,8 @@ enum target_cfg_param {
TCFG_CHAIN_POSITION,
TCFG_DBGBASE,
TCFG_RTOS,
+ TCFG_RESTART_CTI_REG_ADDR,
+ TCFG_RESTART_CTI_CHANNEL,
};
static Jim_Nvp nvp_config_opts[] = {
@@ -4255,6 +4313,8 @@ static Jim_Nvp nvp_config_opts[] = {
{ .name = "-chain-position", .value = TCFG_CHAIN_POSITION },
{ .name = "-dbgbase", .value = TCFG_DBGBASE },
{ .name = "-rtos", .value = TCFG_RTOS },
+ { .name = "-restart-cti-reg-addr", .value = TCFG_RESTART_CTI_REG_ADDR },
+ { .name = "-restart-cti-channel", .value = TCFG_RESTART_CTI_CHANNEL },
{ .name = NULL, .value = -1 }
};
@@ -4529,6 +4589,35 @@ no_params:
}
/* loop for more */
break;
+
+ case TCFG_RESTART_CTI_REG_ADDR:
+ if (goi->isconfigure) {
+ e = Jim_GetOpt_Wide(goi, &w);
+ if (e != JIM_OK)
+ return e;
+ target->restart_cti_reg_addr = (uint32_t)w;
+ target->restart_use_cti = true;
+ } else {
+ if (goi->argc != 0)
+ goto no_params;
+ }
+ Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, target->restart_cti_reg_addr));
+ /* loop for more */
+ break;
+
+ case TCFG_RESTART_CTI_CHANNEL:
+ if (goi->isconfigure) {
+ e = Jim_GetOpt_Wide(goi, &w);
+ if (e != JIM_OK)
+ return e;
+ target->restart_cti_channel = (int32_t)w;
+ } else {
+ if (goi->argc != 0)
+ goto no_params;
+ }
+ Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, target->restart_cti_channel));
+ /* loop for more */
+ break;
}
} /* while (goi->argc) */
@@ -4781,14 +4870,28 @@ 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);
+ return target_mem2array(interp, target, argc - 1, argv + 1, false /* physical */);
}
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);
+ return target_array2mem(interp, target, argc - 1, argv + 1, false /* physical */);
+}
+
+static int jim_target_pmem2array(Jim_Interp *interp,
+ int argc, Jim_Obj *const *argv)
+{
+ struct target *target = Jim_CmdPrivData(interp);
+ return target_mem2array(interp, target, argc - 1, argv + 1, true /* physical */);
+}
+
+static int jim_target_array2pmem(Jim_Interp *interp,
+ int argc, Jim_Obj *const *argv)
+{
+ struct target *target = Jim_CmdPrivData(interp);
+ return target_array2mem(interp, target, argc - 1, argv + 1, true /* physical */);
}
static int jim_target_tap_disabled(Jim_Interp *interp)
@@ -5077,6 +5180,22 @@ static const struct command_registration target_instance_command_handlers[] = {
.usage = "arrayname bitwidth address count",
},
{
+ .name = "array2pmem",
+ .mode = COMMAND_EXEC,
+ .jim_handler = jim_target_array2pmem,
+ .help = "Writes Tcl array of 8/16/32 bit numbers "
+ "to target physical memory",
+ .usage = "arrayname bitwidth address count",
+ },
+ {
+ .name = "pmem2array",
+ .mode = COMMAND_EXEC,
+ .jim_handler = jim_target_pmem2array,
+ .help = "Loads Tcl array of 8/16/32 bit numbers "
+ "from target physical memory",
+ .usage = "arrayname bitwidth address count",
+ },
+ {
.name = "eventlist",
.mode = COMMAND_EXEC,
.jim_handler = jim_target_event_list,
@@ -5263,6 +5382,10 @@ static int target_create(Jim_GetOptInfo *goi)
target->rtos = NULL;
target->rtos_auto_detect = false;
+ target->restart_use_cti = false;
+ target->restart_cti_reg_addr = 0;
+ target->restart_cti_channel = 0;
+
/* Do the rest as "configure" options */
goi->isconfigure = 1;
e = target_configure(goi, target);
@@ -6098,6 +6221,22 @@ static const struct command_registration target_exec_command_handlers[] = {
.usage = "arrayname bitwidth address count",
},
{
+ .name = "pmem2array",
+ .mode = COMMAND_EXEC,
+ .jim_handler = jim_pmem2array,
+ .help = "read 8/16/32 bit physical memory and return as a TCL array "
+ "for script processing",
+ .usage = "arrayname bitwidth address count",
+ },
+ {
+ .name = "array2pmem",
+ .mode = COMMAND_EXEC,
+ .jim_handler = jim_array2pmem,
+ .help = "convert a TCL array to physical 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,
diff --git a/src/target/target.h b/src/target/target.h
index 7471c1b..b01cfb2 100644
--- a/src/target/target.h
+++ b/src/target/target.h
@@ -197,6 +197,14 @@ struct target {
/* file-I/O information for host to do syscall */
struct gdb_fileio_info *fileio_info;
+
+ /** Shut off callbacks */
+ bool no_callbacks;
+
+ /* Some targets use CoreSight CTI to do restart */
+ bool restart_use_cti;
+ uint32_t restart_cti_reg_addr;
+ int restart_cti_channel;
};
struct target_list {
diff --git a/src/target/target_type.h b/src/target/target_type.h
index 234cdfb..5da48cc 100644
--- a/src/target/target_type.h
+++ b/src/target/target_type.h
@@ -126,6 +126,11 @@ struct target_type {
int (*read_buffer)(struct target *target, uint32_t address,
uint32_t size, uint8_t *buffer);
+ /* Allow target to do some pre-processing before write_buffer.
+ Don't call write_buffer if this function returns ERROR_OK. */
+ int (*pre_write_buffer)(struct target *target, uint32_t address,
+ uint32_t size, const 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);
diff --git a/src/target/trace.c b/src/target/trace.c
index 9c2d369..f2425dc 100644
--- a/src/target/trace.c
+++ b/src/target/trace.c
@@ -55,7 +55,7 @@ COMMAND_HANDLER(handle_trace_point_command)
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)",
+ command_print(CMD_CTX, "trace point 0x%8.8" PRIx32 " (%"PRIlld" times hit)",
trace->trace_points[i].address,
(long long)trace->trace_points[i].hit_counter);
}
diff --git a/src/target/xml_support.c b/src/target/xml_support.c
new file mode 100644
index 0000000..5f267b8
--- /dev/null
+++ b/src/target/xml_support.c
@@ -0,0 +1,39 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+
+#if defined(HAVE_LIBEXPAT)
+
+#include <expat.h>
+
+const XML_Char *xml_find_attribute(const XML_Char **attrs, const XML_Char *attr)
+{
+ const XML_Char **p;
+ for (p = attrs; *p; p += 2)
+ {
+ const char *name = p[0];
+ const char *val = p[1];
+ if (strcmp(name, attr) == 0)
+ return val;
+ }
+ return NULL;
+}
+
+int xml_parse_uint32(const char *str, uint32_t *p)
+{
+ char *endptr;
+ unsigned long result;
+
+ if (*str == '\0')
+ return -1;
+
+ result = strtol(str, &endptr, 0);
+ if (*endptr != '\0')
+ return -1;
+
+ *p = result;
+ return 0;
+}
+
+#endif /* HAVE_LIBEXPAT */
diff --git a/src/target/xml_support.h b/src/target/xml_support.h
new file mode 100644
index 0000000..b9cbd3e
--- /dev/null
+++ b/src/target/xml_support.h
@@ -0,0 +1,9 @@
+#ifndef XML_SUPPORT_H
+#define XML_SUPPORT_H
+
+#include <expat.h>
+
+extern const XML_Char *xml_find_attribute(const XML_Char **attrs, const XML_Char *attr);
+extern int xml_parse_uint32(const char *str, uint32_t *p);
+
+#endif /* XML_SUPPORT_H */
diff --git a/src/xsvf/xsvf.c b/src/xsvf/xsvf.c
index 6f8db8c..e5521bc 100644
--- a/src/xsvf/xsvf.c
+++ b/src/xsvf/xsvf.c
@@ -1016,7 +1016,7 @@ COMMAND_HANDLER(handle_xsvf_command)
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",
+ "unsupported xsvf command (0x%02X) at offset %"PRIjd", aborting",
uc, (intmax_t)offset);
return ERROR_FAIL;
}
diff --git a/tcl/board/adspsc573_ezkit.cfg b/tcl/board/adspsc573_ezkit.cfg
new file mode 100644
index 0000000..3795c3a
--- /dev/null
+++ b/tcl/board/adspsc573_ezkit.cfg
@@ -0,0 +1,11 @@
+# Analog Devices ADSP-SC573 EZ-KIT with SDRAM initialization
+
+set CHIPNAME adspsc573
+
+source [find target/adspsc57x.cfg]
+source [find board/adspsc5xx_ezbrd.tcl]
+
+proc adspsc57x_init {} {
+ cortex_a mmu disable
+ adspsc5xx_init_ddr3 0
+}
diff --git a/tcl/board/adspsc584_ezbrd.cfg b/tcl/board/adspsc584_ezbrd.cfg
new file mode 100644
index 0000000..0ffbb19
--- /dev/null
+++ b/tcl/board/adspsc584_ezbrd.cfg
@@ -0,0 +1,11 @@
+# Analog Devices ADSP-SC584 EZ-BRD with SDRAM initialization
+
+set CHIPNAME adspsc584
+
+source [find target/adspsc58x.cfg]
+source [find board/adspsc5xx_ezbrd.tcl]
+
+proc adspsc58x_init {} {
+ cortex_a mmu disable
+ adspsc5xx_init_ddr2
+}
diff --git a/tcl/board/adspsc589_ezbrd.cfg b/tcl/board/adspsc589_ezbrd.cfg
new file mode 100644
index 0000000..3c2fa4b
--- /dev/null
+++ b/tcl/board/adspsc589_ezbrd.cfg
@@ -0,0 +1,12 @@
+# Analog Devices ADSP-SC589 EZ-BRD with SDRAM initialization
+
+set CHIPNAME adspsc589
+
+source [find target/adspsc58x.cfg]
+source [find board/adspsc5xx_ezbrd.tcl]
+
+proc adspsc58x_init {} {
+ cortex_a mmu disable
+ adspsc5xx_init_ddr3 0
+ adspsc5xx_init_ddr3 1
+}
diff --git a/tcl/board/adspsc5xx_ezbrd.tcl b/tcl/board/adspsc5xx_ezbrd.tcl
new file mode 100644
index 0000000..6188734
--- /dev/null
+++ b/tcl/board/adspsc5xx_ezbrd.tcl
@@ -0,0 +1,274 @@
+# Common routines used by ADI ADSP-SC58x and ADSP-SC57x boards
+
+proc smpu_config { smpu } {
+ # Use SMPU instances to disable accesses to system memory that may not be
+ # populated or needs to be initialized before being accessed. This will
+ # avoid the possibility of an infinite stall in the system due to a
+ # speculative access to a disabled or uninitialized memory. This is also
+ # part of the workaround for silicon anomaly 20000018.
+
+ if { $smpu == 0 } {
+ set smpu_baseaddr 0x31007000
+ } elseif { $smpu == 8 } {
+ set smpu_baseaddr 0x31099000
+ } elseif { $smpu == 9 } {
+ set smpu_baseaddr 0x310a0000
+ } elseif { $smpu == 10 } {
+ set smpu_baseaddr 0x310a1000
+ } else {
+ puts stderr "Error: unknown SMPU number"
+ shutdown error
+ }
+
+ set smpu_ctl [expr {$smpu_baseaddr + 0x0}]
+ set smpu_securectl [expr {$smpu_baseaddr + 0x800}]
+
+ # SMC - SMPU instance 0
+ # *pREG_SMPU0_CTL |= ENUM_SMPU_CTL_RSDIS;
+ pmmw $smpu_ctl 0x1 0
+
+ # *pREG_SMPU0_SECURECTL = 0xf01;
+ mww phys $smpu_securectl 0xf01
+}
+
+proc adspsc5xx_init_ddr3 { dmc } {
+ global CHIPNAME
+
+ if { $dmc == 0 } {
+ set dmc_baseaddr 0x31070000
+ set dummy_addr 0x80000000
+ } else {
+ set dmc_baseaddr 0x31073000
+ set dummy_addr 0xc0000000
+ }
+
+ set dmc_ctl [expr {$dmc_baseaddr + 0x4}]
+ set dmc_stat [expr {$dmc_baseaddr + 0x8}]
+ set dmc_cfg [expr {$dmc_baseaddr + 0x40}]
+ set dmc_tr0 [expr {$dmc_baseaddr + 0x44}]
+ set dmc_tr1 [expr {$dmc_baseaddr + 0x48}]
+ set dmc_tr2 [expr {$dmc_baseaddr + 0x4c}]
+ set dmc_mr [expr {$dmc_baseaddr + 0x60}]
+ set dmc_emr1 [expr {$dmc_baseaddr + 0x64}]
+ set dmc_emr2 [expr {$dmc_baseaddr + 0x68}]
+ set dmc_dllctl [expr {$dmc_baseaddr + 0x80}]
+ set dmc_phy_ctl0 [expr {$dmc_baseaddr + 0x1000}]
+ set dmc_phy_ctl1 [expr {$dmc_baseaddr + 0x1004}]
+ set dmc_phy_ctl2 [expr {$dmc_baseaddr + 0x1008}]
+ set dmc_phy_ctl3 [expr {$dmc_baseaddr + 0x100c}]
+ set dmc_phy_ctl4 [expr {$dmc_baseaddr + 0x1010}]
+ set dmc_cal_padctl0 [expr {$dmc_baseaddr + 0x1034}]
+ set dmc_cal_padctl2 [expr {$dmc_baseaddr + 0x103c}]
+
+ # Configure SMPU (silicon anomaly 20000018)
+ if { $CHIPNAME == "adspsc589" } {
+ smpu_config 0
+ smpu_config 8
+ } elseif { $CHIPNAME == "adspsc573" } {
+ smpu_config 0
+ }
+
+ # Set the RESETDLL bit (bit 11 of the DMC_PHY_CTL0 register) before CGU Initialization.
+ # *pREG_DMC0_PHY_CTL0 |= BITM_DMC_PHY_CTL0_RESETDLL;
+ pmmw $dmc_phy_ctl0 0x800 0
+
+ # Set CGU clock select register to CLKO2/4 (ARM core)
+ mww phys 0x3108d010 4
+
+ # Reset processor to default power settings
+ # Clear DISABLE and set EXIT_ACTIVE in CGU0_PLLCTL
+ mww phys 0x3108d004 0x2
+ # Set DF = 0 MSEL = 0x12 in CGU0_CTL
+ mww phys 0x3108d000 0x1200
+ # Set SYSSEL = 2 S0SEL = 2 S1SEL = 2 CSEL = 1 DSEL = 1 in CGU0_DIV
+ mww phys 0x3108d00c 0x44014241
+
+ # Read CGU0_STAT to make sure it's in FULL ON mode
+ #mdw phys 0x3108d008
+
+ # Clear the PHY_CTL0 after CGU Initialization
+ mww phys $dmc_phy_ctl0 0
+
+ # Wait for DLL lock - 9000 DCLK cycles
+ # 1ms should be enough
+ after 1
+
+ # *pREG_DMC0_PHY_CTL0 |= 0x0000000F;
+ pmmw $dmc_phy_ctl0 0xf 0
+ # *pREG_DMC0_PHY_CTL2 |= 0xFC000000;
+ pmmw $dmc_phy_ctl2 0xfc000000 0
+ # *pREG_DMC0_PHY_CTL3 |= 0x0A0000C0;
+ pmmw $dmc_phy_ctl3 0xa0000c0 0
+
+ # *pREG_DMC0_PHY_CTL1 = 0x00000000;
+ mww phys $dmc_phy_ctl1 0
+
+ # *pREG_DMC0_PHY_CTL4 = 0x00000000;
+ mww phys $dmc_phy_ctl4 0
+
+ # Program the PAD RTT and driver impedance values required here
+ # *pREG_DMC0_CAL_PADCTL0 = 0xE0000000;
+ mww phys $dmc_cal_padctl0 0xe0000000
+ # *pREG_DMC0_CAL_PADCTL2 = 0x0078283C;
+ mww phys $dmc_cal_padctl2 0x0078283c
+
+ # Start calibration
+ # *pREG_DMC0_CAL_PADCTL0 |= 0x10000000;
+ pmmw $dmc_cal_padctl0 0x10000000 0
+
+ # Wait for PAD calibration to complete - 300 DCLK cycle.
+ # 1ms should be enough
+ after 1
+
+ # *pREG_DMC0_CFG = 0x00000522;
+ mww phys $dmc_cfg 0x00000522
+ # *pREG_DMC0_TR0 = 0x41711646;
+ mww phys $dmc_tr0 0x41711646
+ # *pREG_DMC0_TR1 = 0x40480db6;
+ mww phys $dmc_tr1 0x40480db6
+ # *pREG_DMC0_TR2 = 0x00347417;
+ mww phys $dmc_tr2 0x00347417
+ # *pREG_DMC0_MR = 0x00000D30;
+ mww phys $dmc_mr 0x00000D30
+ # *pREG_DMC0_EMR1 = 0x00000006;
+ mww phys $dmc_emr1 0x00000006
+ # *pREG_DMC0_EMR2 = 0x00000008;
+ mww phys $dmc_emr2 0x00000008
+ # *pREG_DMC0_CTL = 0x00000405;
+ mww phys $dmc_ctl 0x00000405
+
+ # Wait till INIDONE is set
+ # while((*pREG_DMC0_STAT&BITM_DMC_STAT_INITDONE)==0);
+ set data 0
+ while { [expr {$data & 4}] == 0 } {
+ set data [pmemread32 $dmc_stat]
+ }
+
+ # *pREG_DMC0_DLLCTL = 0x00000948;
+ mww phys $dmc_dllctl 0x00000948
+
+ # Workaround for silicon anomaly 20000037
+ # Dummy read
+ set data [memread32 $dummy_addr]
+ # *pREG_DMC0_PHY_CTL0|=0x1000;
+ # *pREG_DMC0_PHY_CTL0&=~0x1000;
+ set data [pmemread32 $dmc_phy_ctl0]
+ mww phys $dmc_phy_ctl0 [expr {$data | 0x1000}]
+ mww phys $dmc_phy_ctl0 [expr {$data & ~0x1000}]
+}
+
+proc adspsc5xx_init_ddr2 { } {
+ set dmc_baseaddr 0x31070000
+ set dummy_addr 0x80000000
+
+ set dmc_ctl [expr {$dmc_baseaddr + 0x4}]
+ set dmc_stat [expr {$dmc_baseaddr + 0x8}]
+ set dmc_cfg [expr {$dmc_baseaddr + 0x40}]
+ set dmc_tr0 [expr {$dmc_baseaddr + 0x44}]
+ set dmc_tr1 [expr {$dmc_baseaddr + 0x48}]
+ set dmc_tr2 [expr {$dmc_baseaddr + 0x4c}]
+ set dmc_mr [expr {$dmc_baseaddr + 0x60}]
+ set dmc_emr1 [expr {$dmc_baseaddr + 0x64}]
+ set dmc_emr2 [expr {$dmc_baseaddr + 0x68}]
+ set dmc_dllctl [expr {$dmc_baseaddr + 0x80}]
+ set dmc_phy_ctl0 [expr {$dmc_baseaddr + 0x1000}]
+ set dmc_phy_ctl1 [expr {$dmc_baseaddr + 0x1004}]
+ set dmc_phy_ctl2 [expr {$dmc_baseaddr + 0x1008}]
+ set dmc_phy_ctl3 [expr {$dmc_baseaddr + 0x100c}]
+ set dmc_phy_ctl4 [expr {$dmc_baseaddr + 0x1010}]
+ set dmc_cal_padctl0 [expr {$dmc_baseaddr + 0x1034}]
+ set dmc_cal_padctl2 [expr {$dmc_baseaddr + 0x103c}]
+
+ # Configure SMPU (silicon anomaly 20000018)
+ smpu_config 0
+ smpu_config 8
+ smpu_config 10
+
+ # Set the RESETDLL bit (bit 11 of the DMC_PHY_CTL0 register) before CGU Initialization.
+ # *pREG_DMC0_PHY_CTL0 |= BITM_DMC_PHY_CTL0_RESETDLL;
+ pmmw $dmc_phy_ctl0 0x800 0
+
+ # Set CGU clock select register to CLKO2/4 (ARM core)
+ mww phys 0x3108d010 4
+
+ # Reset processor to default power settings
+ # Clear DISABLE and set EXIT_ACTIVE in CGU0_PLLCTL
+ mww phys 0x3108d004 0x2
+ # Set DF = 0 MSEL = 0x10 in CGU0_CTL
+ mww phys 0x3108d000 0x1000
+ # Set SYSSEL = 2 S0SEL = 2 S1SEL = 2 CSEL = 1 DSEL = 1 in CGU0_DIV
+ mww phys 0x3108d00c 0x44014241
+
+ # Read CGU0_STAT to make sure it's in FULL ON mode
+ #mdw phys 0x3108d008
+
+ # Clear the PHY_CTL0 after CGU Initialization
+ mww phys $dmc_phy_ctl0 0
+
+ # Wait for DLL lock - 9000 DCLK cycles
+ # 1ms should be enough
+ after 1
+
+ # *pREG_DMC0_PHY_CTL0 |= 0x0000000F;
+ pmmw $dmc_phy_ctl0 0xf 0
+ # *pREG_DMC0_PHY_CTL2 |= 0xFC000000;
+ pmmw $dmc_phy_ctl2 0xfc000000 0
+ # *pREG_DMC0_PHY_CTL3 |= 0x0A0000C0;
+ pmmw $dmc_phy_ctl3 0xa0000c0 0
+
+ # *pREG_DMC0_PHY_CTL1 = 0x00000000;
+ mww phys $dmc_phy_ctl1 0
+
+ # *pREG_DMC0_PHY_CTL4 = 0x00000001;
+ mww phys $dmc_phy_ctl4 1
+
+ # Program the PAD RTT and driver impedance values required here
+ # *pREG_DMC0_CAL_PADCTL0 = 0xE0000000;
+ mww phys $dmc_cal_padctl0 0xe0000000
+ # *pREG_DMC0_CAL_PADCTL2 = 0x0078283C;
+ mww phys $dmc_cal_padctl2 0x0078283c
+
+ # Start calibration
+ # *pREG_DMC0_CAL_PADCTL0 |= 0x10000000;
+ pmmw $dmc_cal_padctl0 0x10000000 0
+
+ # Wait for PAD calibration to complete - 300 DCLK cycle.
+ # 1ms should be enough
+ after 1
+
+ # *pREG_DMC0_CFG = 0x00000522;
+ mww phys $dmc_cfg 0x00000522
+ # *pREG_DMC0_TR0 = 0x21610535;
+ mww phys $dmc_tr0 0x21610535
+ # *pREG_DMC0_TR1 = 0x404e0c30;
+ mww phys $dmc_tr1 0x404e0c30
+ # *pREG_DMC0_TR2 = 0x00326312;
+ mww phys $dmc_tr2 0x00326312
+ # *pREG_DMC0_MR = 0x00000a52;
+ mww phys $dmc_mr 0x00000a52
+ # *pREG_DMC0_EMR1 = 0x00000004;
+ mww phys $dmc_emr1 0x00000004
+ # *pREG_DMC0_EMR2 = 0x00000000;
+ mww phys $dmc_emr2 0x00000000
+ # *pREG_DMC0_CTL = 0x00000404;
+ mww phys $dmc_ctl 0x00000404
+
+ # Wait till INIDONE is set
+ # while((*pREG_DMC0_STAT&BITM_DMC_STAT_INITDONE)==0);
+ set data 0
+ while { [expr {$data & 4}] == 0 } {
+ set data [pmemread32 $dmc_stat]
+ }
+
+ # *pREG_DMC0_DLLCTL = 0x00000948;
+ mww phys $dmc_dllctl 0x00000948
+
+ # Workaround for silicon anomaly 20000037
+ # Dummy read
+ set data [memread32 $dummy_addr]
+ # *pREG_DMC0_PHY_CTL0|=0x1000;
+ # *pREG_DMC0_PHY_CTL0&=~0x1000;
+ set data [pmemread32 $dmc_phy_ctl0]
+ mww phys $dmc_phy_ctl0 [expr {$data | 0x1000}]
+ mww phys $dmc_phy_ctl0 [expr {$data & ~0x1000}]
+}
diff --git a/tcl/board/bf537_ezkit.cfg b/tcl/board/bf537_ezkit.cfg
new file mode 100644
index 0000000..86bd898
--- /dev/null
+++ b/tcl/board/bf537_ezkit.cfg
@@ -0,0 +1,21 @@
+# Analog Devices ADSP-BF537 EZ-KIT LITE board
+
+set SDRAM_SIZE 0x4000000
+set FLASH_SIZE 0x400000
+
+# Config parameters for SDRAM on the board
+
+global SDRRC
+global SDBCTL
+global SDGCTL
+set SDRRC 0x03a0
+set SDBCTL 0x0025
+set SDGCTL 0x0091998d
+
+source [find target/bf537.cfg]
+
+$_TARGETNAME configure -event reset-init {
+ blackfin wpu_init
+ blackfin sdram_init
+}
+$_TARGETNAME configure -event gdb-attach { reset init }
diff --git a/tcl/board/bf561_ezkit.cfg b/tcl/board/bf561_ezkit.cfg
new file mode 100644
index 0000000..8f349f1
--- /dev/null
+++ b/tcl/board/bf561_ezkit.cfg
@@ -0,0 +1,21 @@
+# Analog Devices ADSP-BF537 EZ-KIT LITE board
+
+set SDRAM_SIZE 0x4000000
+set FLASH_SIZE 0x800000
+
+# Config parameters for SDRAM on the board
+
+global SDRRC
+global SDBCTL
+global SDGCTL
+set SDRRC 0x01cf
+set SDBCTL 0x0013
+set SDGCTL 0x0091998d
+
+source [find target/bf561.cfg]
+
+$_TARGETNAME_A configure -event reset-init {
+ blackfin wpu_init
+ blackfin sdram_init
+}
+$_TARGETNAME_A configure -event gdb-attach { reset init }
diff --git a/tcl/cpu/blackfin/blackfin.cfg b/tcl/cpu/blackfin/blackfin.cfg
new file mode 100644
index 0000000..e2921c1
--- /dev/null
+++ b/tcl/cpu/blackfin/blackfin.cfg
@@ -0,0 +1,18 @@
+# common script for Blackfin
+
+set _CHIPNAME $CHIPNAME
+set _CPUTAPID $CPUTAPID
+
+jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id $_CPUTAPID -ignore-version
+
+set _TARGETNAME $_CHIPNAME.cpu
+target create $_TARGETNAME blackfin -chain-position $_TARGETNAME
+
+adapter_nsrst_delay 100
+jtag_ntrst_delay 100
+
+reset_config trst_only
+
+# FIXME
+gdb_memory_map disable
+
diff --git a/tcl/interface/ftdi/gnice+.cfg b/tcl/interface/ftdi/gnice+.cfg
new file mode 100644
index 0000000..16d0f3f
--- /dev/null
+++ b/tcl/interface/ftdi/gnice+.cfg
@@ -0,0 +1,13 @@
+#
+# Blackfin gnICE+
+#
+
+interface ftdi
+ftdi_device_desc "Blackfin gnICE+"
+ftdi_vid_pid 0x0456 0xf001
+
+ftdi_layout_init 0x0208 0x0a0b
+ftdi_layout_signal LED -ndata 0x0800
+ftdi_layout_signal nTRST -data 0x0020
+
+adapter_khz 30000
diff --git a/tcl/interface/ftdi/gnice.cfg b/tcl/interface/ftdi/gnice.cfg
new file mode 100644
index 0000000..a93e60f
--- /dev/null
+++ b/tcl/interface/ftdi/gnice.cfg
@@ -0,0 +1,13 @@
+#
+# Blackfin gnICE
+#
+
+interface ftdi
+ftdi_device_desc "Blackfin gnICE"
+ftdi_vid_pid 0x0456 0xf000
+
+ftdi_layout_init 0x0208 0x0a0b
+ftdi_layout_signal LED -ndata 0x0800
+ftdi_layout_signal nTRST -data 0x0020
+
+adapter_khz 6000
diff --git a/tcl/interface/ice1000.cfg b/tcl/interface/ice1000.cfg
new file mode 100644
index 0000000..91689e4
--- /dev/null
+++ b/tcl/interface/ice1000.cfg
@@ -0,0 +1,11 @@
+# Analog Devices ICE-1000 Emulator
+#
+# http://www.analog.com/ice1000
+#
+
+interface ice1000
+
+# valid frequencies: 1000: 1 MHz
+# 2000: 2 MHz
+# 5000: 5 MHz
+adapter_khz 1000
diff --git a/tcl/interface/ice2000.cfg b/tcl/interface/ice2000.cfg
new file mode 100644
index 0000000..ff59548
--- /dev/null
+++ b/tcl/interface/ice2000.cfg
@@ -0,0 +1,25 @@
+# Analog Devices ICE-2000 Emulator
+#
+# http://www.analog.com/ice2000
+#
+
+interface ice2000
+
+# valid voltages: 1: 1.8 V
+# 2: 2.5 V
+# 3: 3.3 V
+# default 3
+#ice2000_voltage 3
+
+# valid frequencies: 1000: 1 MHz
+# 2000: 2 MHz
+# 5000: 5 MHz
+# 9000: 9 MHz
+# 15000: 15 MHz
+# 23000: 23 MHz
+adapter_khz 1000
+
+# ICE-2000 supports up to 46 MHz. But not all processors will work
+# with this emuator frequency for all transport types (JTAG and SWD).
+#
+# 46000: 46 MHz
diff --git a/tcl/mem_helper.tcl b/tcl/mem_helper.tcl
index a3d92cb..563ff95 100644
--- a/tcl/mem_helper.tcl
+++ b/tcl/mem_helper.tcl
@@ -20,3 +20,24 @@ proc mmw {reg setbits clearbits} {
add_usage_text mmw "address setbits clearbits"
add_help_text mmw "Modify word in memory. new_val = (old_val & ~clearbits) | setbits;"
+
+# pmrw: "physical memory read word", returns value of $reg
+proc pmrw {reg} {
+ set value ""
+ pmem2array value 32 $reg 1
+ return $value(0)
+}
+
+add_usage_text pmrw "address"
+add_help_text pmrw "Returns value of word in physical memory."
+
+# pmmw: "physical memory modify word", updates value of $reg
+# $reg <== ((value & ~$clearbits) | $setbits)
+proc pmmw {reg setbits clearbits} {
+ set old [pmrw $reg]
+ set new [expr ($old & ~$clearbits) | $setbits]
+ mww phys $reg $new
+}
+
+add_usage_text pmmw "address setbits clearbits"
+add_help_text pmmw "Modify word in physical memory. new_val = (old_val & ~clearbits) | setbits;"
diff --git a/tcl/memory.tcl b/tcl/memory.tcl
index 2719d3f..9677e0f 100644
--- a/tcl/memory.tcl
+++ b/tcl/memory.tcl
@@ -131,3 +131,57 @@ proc memwrite8 {ADDR DATA} {
error "memwrite8: $msg"
}
}
+
+proc pmemread32 {ADDR} {
+ set foo(0) 0
+ if ![ catch { pmem2array foo 32 $ADDR 1 } msg ] {
+ return $foo(0)
+ } else {
+ error "pmemread32: $msg"
+ }
+}
+
+proc pmemread16 {ADDR} {
+ set foo(0) 0
+ if ![ catch { pmem2array foo 16 $ADDR 1 } msg ] {
+ return $foo(0)
+ } else {
+ error "pmemread16: $msg"
+ }
+}
+
+proc pmemread8 {ADDR} {
+ set foo(0) 0
+ if ![ catch { pmem2array foo 8 $ADDR 1 } msg ] {
+ return $foo(0)
+ } else {
+ error "pmemread8: $msg"
+ }
+}
+
+proc pmemwrite32 {ADDR DATA} {
+ set foo(0) $DATA
+ if ![ catch { array2pmem foo 32 $ADDR 1 } msg ] {
+ return $foo(0)
+ } else {
+ error "pmemwrite32: $msg"
+ }
+}
+
+proc pmemwrite16 {ADDR DATA} {
+ set foo(0) $DATA
+ if ![ catch { array2pmem foo 16 $ADDR 1 } msg ] {
+ return $foo(0)
+ } else {
+ error "pmemwrite16: $msg"
+ }
+}
+
+proc pmemwrite8 {ADDR DATA} {
+ set foo(0) $DATA
+ if ![ catch { array2pmem foo 8 $ADDR 1 } msg ] {
+ return $foo(0)
+ } else {
+ error "pmemwrite8: $msg"
+ }
+}
diff --git a/tcl/mmr_helpers.tcl b/tcl/mmr_helpers.tcl
index ce116e4..d76ee5d 100644
--- a/tcl/mmr_helpers.tcl
+++ b/tcl/mmr_helpers.tcl
@@ -12,7 +12,7 @@ proc show_mmr32_reg { NAME } {
# we want $($NAME)
set a [set [set NAME]]
- if ![catch { set v [memread32 $a] } msg ] {
+ if ![catch { set v [pmemread32 $a] } msg ] {
echo [format "%15s: (0x%08x): 0x%08x" $NAME $a $v]
# Was a helper defined?
@@ -61,7 +61,7 @@ proc show_mmr32_bits { NAMES VAL } {
proc show_mmr_bitfield { MSB LSB VAL FIELDNAME FIELDVALUES } {
set width [expr (($MSB - $LSB + 1) + 7) / 4]
- set nval [show_normalize_bitfield $VAL $MSB $LSB ]
+ set nval [normalize_bitfield $VAL $MSB $LSB ]
set name0 [lindex $FIELDVALUES 0 ]
if [ string compare $name0 _NUMBER_ ] {
set sval [lindex $FIELDVALUES $nval]
diff --git a/tcl/target/adspsc57x.cfg b/tcl/target/adspsc57x.cfg
new file mode 100644
index 0000000..571ed6e
--- /dev/null
+++ b/tcl/target/adspsc57x.cfg
@@ -0,0 +1,256 @@
+# Analog Devices ADSP-SC57x
+
+#
+# ADSP-SC57x devices support JTAG and SWD transports.
+#
+transport select jtag
+#transport select swd
+
+source [find target/swj-dp.tcl]
+
+set CPU_MAX_ADDRESS 0xFFFFFFFF
+source [find bitsbytes.tcl]
+source [find memory.tcl]
+source [find mem_helper.tcl]
+source [find mmr_helpers.tcl]
+source [find target/adspsc5xx.tcl]
+
+# memory map
+
+set MAP_XML [find target/adspsc57x_memory_map.xml]
+set MAP_FILE [open $MAP_XML]
+set _MEMORY_MAP [read $MAP_FILE]
+close $MAP_FILE
+
+global MEMORY_MAP
+# substitute SDRAM_SIZE and FLASH_SIZE
+set MEMORY_MAP [subst $_MEMORY_MAP]
+
+# UserKey
+
+# Uncomment the following 4 lines and change 0x00000000 to key values
+#set USERKEY0 0x00000000
+#set USERKEY1 0x00000000
+#set USERKEY2 0x00000000
+#set USERKEY3 0x00000000
+
+if { [info exists USERKEY0] } {
+ set _USERKEY0 $USERKEY0
+} else {
+ set _USERKEY0 0x00000000
+}
+
+if { [info exists USERKEY1] } {
+ set _USERKEY1 $USERKEY1
+} else {
+ set _USERKEY1 0x00000000
+}
+
+if { [info exists USERKEY2] } {
+ set _USERKEY2 $USERKEY2
+} else {
+ set _USERKEY2 0x00000000
+}
+
+if { [info exists USERKEY3] } {
+ set _USERKEY3 $USERKEY3
+} else {
+ set _USERKEY3 0x00000000
+}
+
+# target config
+
+if { [info exists CHIPNAME] } {
+ set _CHIPNAME $CHIPNAME
+} else {
+ set _CHIPNAME adspsc57x
+}
+
+# CoreSight Debug Access Port (DAP)
+if { [info exists DAP_TAPID ] } {
+ set _DAP_TAPID $DAP_TAPID
+} else {
+ if { [using_jtag] } {
+ set _DAP_TAPID 0x4ba00477
+ } else {
+ set _DAP_TAPID 0x3ba02477
+ }
+}
+
+if { [using_swd] } {
+ swj_newdap $_CHIPNAME dap -expected-id $_DAP_TAPID
+} else {
+ jtag newtap $_CHIPNAME dap -irlen 4 -expected-id $_DAP_TAPID -disable
+ jtag configure $_CHIPNAME.dap -event tap-enable "adjc_enable_dap $_CHIPNAME.adjc"
+
+ # ADI JTAG Controller
+ if { [info exists ADJC_TAPID ] } {
+ set _ADJC_TAPID $ADJC_TAPID
+ } else {
+ set _ADJC_TAPID 0x0280f0cb
+ }
+
+ jtag newtap $_CHIPNAME adjc -irlen 5 -expected-id $_ADJC_TAPID
+
+ # Once the JRC is up, enable our TAPs
+ jtag configure $_CHIPNAME.adjc -event setup "jtag tapenable $_CHIPNAME.dap"
+}
+
+# GDB target: Cortex-A5, using DAP
+set _TARGETNAME $_CHIPNAME.dap
+target create $_TARGETNAME cortex_a -chain-position $_TARGETNAME -dbgbase 0x80020000
+
+# system reset
+proc adspsc57x_system_reset {} {
+
+ # Read BMODE from RCU0_STAT
+ set data [pmemread32 0x3108c004]
+ set bootmode [expr {($data >> 8) & 0xf}]
+ puts "Boot Mode $bootmode"
+
+ # Clear SHARC-XI debug registers for both SHARC-XI cores
+ # If EMUCTL.EMUENA bit is set, the SHARC-XI core cannot be reset
+ reset_sharcxi_debug_regs 0x80001000
+ reset_sharcxi_debug_regs 0x80005000
+
+ puts "start system reset ..."
+
+ # Clear REG_RCU0_MSG
+ # *pREG_RCU0_MSG = 0x0
+ mww phys 0x3108c06c 0
+
+ # Deassert RSTOUT in REG_RCU0_STAT
+ # *pREG_RCU0_CTL |= 0x4
+ pmmw 0x3108c000 0x4 0
+
+ # Clear REG_RCU0_STAT
+ # *pREG_RCU0_STAT = 0x7000d
+ mww phys 0x3108c004 0x7000d
+
+ # Set HALT (bit 2)
+ # *pREG_RCU0_BCODE = 0x4
+ mww phys 0x3108c028 0x4
+
+ # There are two methods to do system reset
+
+ # Use RCU_CTL to do system reset
+ # *pREG_RCU0_CTL |= 0x00000001;
+ #pmmw 0x3108c000 0x1 0
+
+ # Use CTI to do system reset
+ # Unlock CTI3 (System CTI)
+ # *pREG_CTI3_LAR = 0xC5ACCE55
+ mww phys 0x3110dfb0 0xC5ACCE55
+
+ # Enable CTI3 (System CTI)
+ # *pREG_CTI3_CTICONTROL = 1
+ mww phys 0x3110d000 0x1
+
+ # Connect CTITRIGOUT[2] of CTI3 to channel 2
+ # *pREG_CTI3_CTIOUTEN2 = 4
+ mww phys 0x3110d0a8 0x4
+
+ # Send a signal to channel 2
+ # *pREG_CTI3_CTIAPPPULSE = 4
+ mww phys 0x3110d01c 0x4
+
+ puts "system reset asserted"
+
+ # Wait till Core 0 is idle
+ # while((*pREG_RCU0_MSG & BITM_RCU_MSG_C0IDLE) == 0);
+ set data 0
+ set retry 0
+ while { [expr {$data & 0x100}] == 0 } {
+ set data [pmemread32 0x3108c06c]
+ set retry [expr {$retry + 1}]
+ if { $retry > 10 } break;
+ }
+ if { $retry > 10 } {
+ set msg [format 0x%08x $data]
+ puts stderr "Error: BCODE.HALT failed (REG_RCU0_MSG $msg)"
+ }
+
+ # update target state
+ poll
+
+ # Halt the core
+ halt
+
+ # Clear C0IDLE from REG_RCU0_MSG
+ # *pREG_RCU0_MSG_CLR = 0x100
+ mww phys 0x3108c074 0x100
+
+ # Now BOOT is done
+ puts "system reset done"
+
+ set data [pmemread32 0x3108c004]
+ show_rcu_stat "REG_RCU0_STAT" $data
+
+ # Show REG_RCU0_MSG
+ set data [pmemread32 0x3108c06c]
+ show_rcu_msg "REG_RCU0_MSG" $data
+
+ # clear REG_RCU0_MSG
+ mww phys 0x3108c06c 0
+ # clear REG_RCU0_BCODE
+ mww phys 0x3108c028 0
+ # Disable CTI3 (System CTI)
+ mww phys 0x3110d000 0
+}
+
+$_TARGETNAME configure -event reset-assert {
+ adspsc57x_system_reset
+}
+
+$_TARGETNAME configure -event examine-end {
+ global _CHIPNAME
+
+ # read PADS STAT register and store the value in data
+ set pads_stat 0x31004468
+ set data [pmemread32 $pads_stat]
+ if { "$_CHIPNAME" == "adspsc571" && [expr {$data & 1}] == 0 } {
+ puts stderr "Error: ADSP-SC573 found instead of ADSP-SC571"
+ shutdown error
+ } elseif { "$_CHIPNAME" == "adspsc573" && [expr {$data & 1}] == 1 } {
+ puts stderr "Error: ADSP-SC571 found instead of ADSP-SC573"
+ shutdown error
+ }
+}
+
+# default initialization
+proc adspsc57x_init {} {
+}
+
+# Unless USE_CTI is set to 0, CTI is used to restart the Cortex-A5 core
+# so system peripherals can be restarted at the same time
+
+if { [info exists USE_CTI] } {
+ set _USE_CTI $USE_CTI
+} else {
+ set _USE_CTI 1
+}
+if { $_USE_CTI != 0 } {
+ echo "halt and restart using CTI"
+ $_TARGETNAME configure -restart-cti-reg-addr 0x3110d01c -restart-cti-channel 1
+}
+
+$_TARGETNAME configure -event gdb-attach {
+ # set all bits in TAPC0_DBGCTL to enable all kinds of debug
+ mww phys 0x31131000 0xffff
+
+ reset
+
+ if { $_USE_CTI != 0 } {
+ adspsc5xx_configure_cti
+ }
+
+ adspsc57x_init
+
+ arm semihosting enable
+}
+
+reset_config trst_only
+
+$_TARGETNAME configure -event reset-assert-post "cortex_a dbginit"
+
+gdb_memory_map disable
diff --git a/tcl/target/adspsc57x_memory_map.xml b/tcl/target/adspsc57x_memory_map.xml
new file mode 100644
index 0000000..5141bf1
--- /dev/null
+++ b/tcl/target/adspsc57x_memory_map.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0"?>
+<!DOCTYPE memory-map SYSTEM "openocd_memory_map.dtd">
+<memory-map>
+ <processor name="adspsc57x">
+ <memory name="ahb_mem" start="0x20000000" length="0xe0000000" access="rw" />
+ </processor>
+</memory-map>
diff --git a/tcl/target/adspsc58x.cfg b/tcl/target/adspsc58x.cfg
new file mode 100644
index 0000000..2788748
--- /dev/null
+++ b/tcl/target/adspsc58x.cfg
@@ -0,0 +1,166 @@
+# Analog Devices ADSP-SC58x
+
+#
+# ADSP-SC58x devices support JTAG and SWD transports.
+#
+transport select jtag
+#transport select swd
+
+source [find target/swj-dp.tcl]
+
+set CPU_MAX_ADDRESS 0xFFFFFFFF
+source [find bitsbytes.tcl]
+source [find memory.tcl]
+source [find mem_helper.tcl]
+source [find target/adspsc5xx.tcl]
+
+# memory map
+
+set MAP_XML [find target/adspsc58x_memory_map.xml]
+set MAP_FILE [open $MAP_XML]
+set _MEMORY_MAP [read $MAP_FILE]
+close $MAP_FILE
+
+global MEMORY_MAP
+# substitute SDRAM_SIZE and FLASH_SIZE
+set MEMORY_MAP [subst $_MEMORY_MAP]
+
+# Uncomment the following 4 lines and change 0x00000000 to
+# userkey if the part is locked
+#set USERKEY0 0x00000000
+#set USERKEY1 0x00000000
+#set USERKEY2 0x00000000
+#set USERKEY3 0x00000000
+
+if { [info exists USERKEY0] } {
+ set _USERKEY0 $USERKEY0
+} else {
+ set _USERKEY0 0x00000000
+}
+
+if { [info exists USERKEY1] } {
+ set _USERKEY1 $USERKEY1
+} else {
+ set _USERKEY1 0x00000000
+}
+
+if { [info exists USERKEY2] } {
+ set _USERKEY2 $USERKEY2
+} else {
+ set _USERKEY2 0x00000000
+}
+
+if { [info exists USERKEY3] } {
+ set _USERKEY3 $USERKEY3
+} else {
+ set _USERKEY3 0x00000000
+}
+
+# target config
+
+if { [info exists CHIPNAME] } {
+ set _CHIPNAME $CHIPNAME
+} else {
+ set _CHIPNAME adspsc58x
+}
+
+# CoreSight Debug Access Port (DAP)
+if { [info exists DAP_TAPID ] } {
+ set _DAP_TAPID $DAP_TAPID
+} else {
+ if { [using_jtag] } {
+ set _DAP_TAPID 0x4ba00477
+ } else {
+ set _DAP_TAPID 0x3ba02477
+ }
+}
+
+if { [using_swd] } {
+ swj_newdap $_CHIPNAME dap -expected-id $_DAP_TAPID
+} else {
+ jtag newtap $_CHIPNAME dap -irlen 4 -expected-id $_DAP_TAPID -disable
+ jtag configure $_CHIPNAME.dap -event tap-enable "adjc_enable_dap $_CHIPNAME.adjc"
+
+ # ADI JTAG Controller
+ if { [info exists ADJC_TAPID ] } {
+ set _ADJC_TAPID $ADJC_TAPID
+ } else {
+ set _ADJC_TAPID 0x028080cb
+ }
+
+ if { [info exists ADJC_TAPID1 ] } {
+ set _ADJC_TAPID1 $ADJC_TAPID1
+ } else {
+ set _ADJC_TAPID1 0x128080cb
+ }
+
+ if { [info exists ADJC_TAPID2 ] } {
+ set _ADJC_TAPID2 $ADJC_TAPID2
+ } else {
+ set _ADJC_TAPID2 0x228080cb
+ }
+
+ jtag newtap $_CHIPNAME adjc -irlen 5 -expected-id $_ADJC_TAPID -expected-id $_ADJC_TAPID1 -expected-id $_ADJC_TAPID2
+
+ # Once the JRC is up, enable our TAPs
+ jtag configure $_CHIPNAME.adjc -event setup "jtag tapenable $_CHIPNAME.dap"
+}
+
+# GDB target: Cortex-A5, using DAP
+set _TARGETNAME $_CHIPNAME.dap
+target create $_TARGETNAME cortex_a -chain-position $_TARGETNAME -dbgbase 0x80020000
+
+cache_config l2x 0x10000000 8
+
+$_TARGETNAME configure -event examine-end {
+ global _CHIPNAME
+
+ # read PADS STAT register and store the value in data
+ set pads_stat 0x31004468
+ set data [pmemread32 $pads_stat]
+ if { "$_CHIPNAME" == "adspsc584" && [expr {$data & 1}] == 0 } {
+ puts stderr "Error: ADSP-SC589 found instead of ADSP-SC584"
+ shutdown error
+ } elseif { "$_CHIPNAME" == "adspsc589" && [expr {$data & 1}] == 1 } {
+ puts stderr "Error: ADSP-SC584 found instead of ADSP-SC589"
+ shutdown error
+ }
+}
+
+# default initialization
+proc adspsc58x_init {} {
+}
+
+# Unless USE_CTI is set to 0, CTI is used to restart the Cortex-A5 core
+# so system peripherals can be restarted at the same time
+
+if { [info exists USE_CTI] } {
+ set _USE_CTI $USE_CTI
+} else {
+ set _USE_CTI 1
+}
+if { $_USE_CTI != 0 } {
+ echo "halt and restart using CTI"
+ $_TARGETNAME configure -restart-cti-reg-addr 0x3110d01c -restart-cti-channel 1
+}
+
+$_TARGETNAME configure -event gdb-attach {
+ # set all bits in TAPC0_DBGCTL to enable all kinds of debug
+ mww phys 0x31131000 0xffff
+
+ if { $_USE_CTI != 0 } {
+ adspsc5xx_configure_cti
+ }
+
+ halt
+
+ adspsc58x_init
+
+ arm semihosting enable
+}
+
+reset_config trst_only
+
+$_TARGETNAME configure -event reset-assert-post "cortex_a dbginit"
+
+gdb_memory_map disable
diff --git a/tcl/target/adspsc58x_memory_map.xml b/tcl/target/adspsc58x_memory_map.xml
new file mode 100644
index 0000000..9937662
--- /dev/null
+++ b/tcl/target/adspsc58x_memory_map.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0"?>
+<!DOCTYPE memory-map SYSTEM "openocd_memory_map.dtd">
+<memory-map>
+ <processor name="adspsc58x">
+ <memory name="ahb_mem" start="0x20000000" length="0xe0000000" access="rw" />
+ </processor>
+</memory-map>
diff --git a/tcl/target/adspsc5xx.tcl b/tcl/target/adspsc5xx.tcl
new file mode 100644
index 0000000..c071755
--- /dev/null
+++ b/tcl/target/adspsc5xx.tcl
@@ -0,0 +1,127 @@
+# Common routines for Analog Devices ADSP-SC57x/SC58x
+
+# Unlock the processor
+proc adjc_unlock {adjc} {
+ global _USERKEY0
+ global _USERKEY1
+ global _USERKEY2
+ global _USERKEY3
+
+ irscan $adjc 0xa -endstate IRPAUSE
+ drscan $adjc 32 $_USERKEY0 32 $_USERKEY1 32 $_USERKEY2 32 $_USERKEY3 -endstate RUN/IDLE
+}
+
+# ADJC is the TAP name for the ADI JTAG Controller
+proc adjc_enable_dap {adjc} {
+ # Unlock the processor before enabling DAP
+ adjc_unlock $adjc
+
+ irscan $adjc 0x5 -endstate IRPAUSE
+ drscan $adjc 8 0x4 -endstate RUN/IDLE
+ runtest 2
+}
+
+# Show RCU_MSG bitfields
+proc show_rcu_msg { name val } {
+ puts "$name [format 0x%08x $val]"
+ show_mmr_bitfield 7 0 $val BOOTERROR { _NUMBER_ }
+ show_mmr_bitfield 8 8 $val C0IDLE { "" "Core 0 is IDLE" }
+ show_mmr_bitfield 9 9 $val C1IDLE { "" "Core 1 is IDLE" }
+ show_mmr_bitfield 10 10 $val C2IDLE { "" "Core 2 is IDLE" }
+ show_mmr_bitfield 12 12 $val C0TASK { "" "Core 0 has finished a task" }
+ show_mmr_bitfield 13 13 $val C1TASK { "" "Core 1 has finished a task" }
+ show_mmr_bitfield 14 14 $val C2TASK { "" "Core 2 has finished a task" }
+ show_mmr_bitfield 16 16 $val C0L1INIT { "" "Core 0 L1 initialized" }
+ show_mmr_bitfield 17 17 $val C1L1INIT { "" "Core 1 L1 initialized" }
+ show_mmr_bitfield 18 18 $val C2L1INIT { "" "Core 2 L1 initialized" }
+ show_mmr_bitfield 22 22 $val L2INIT { "" "L2 initialized" }
+ show_mmr_bitfield 24 24 $val HALTONAPP { "" "Halt on applicaton call" }
+ show_mmr_bitfield 25 25 $val HALTONINIT { "" "Halt on initcode call" }
+ show_mmr_bitfield 26 26 $val HALTONCALL { "" "Halt on callback call" }
+ show_mmr_bitfield 27 27 $val HALTONERR { "" "Halt on error call" }
+ show_mmr_bitfield 28 28 $val CALLAPP { "" "Call application flag" }
+ show_mmr_bitfield 29 29 $val CALLINIT { "" "Call initcode flag" }
+ show_mmr_bitfield 30 30 $val CALLBACK { "" "Call callback flag" }
+ show_mmr_bitfield 31 31 $val CALLERR { "" "Call error flag" }
+}
+
+# Show RCU_STAT bitfields
+proc show_rcu_stat { name val } {
+ puts "$name [format 0x%08x $val]"
+ show_mmr_bitfield 0 0 $val HWRST { "" HWRST }
+ show_mmr_bitfield 2 2 $val SSRST { "" SSRST }
+ show_mmr_bitfield 3 3 $val SWRST { "" SWRST }
+ show_mmr_bitfield 5 5 $val RSTOUT { "" RSTOUT }
+ show_mmr_bitfield 11 8 $val BMODE { _NUMBER_ }
+ show_mmr_bitfield 12 12 $val TESTMODE { "" TESTMODE }
+ show_mmr_bitfield 13 13 $val STESTMODE { "" STESTMODE }
+ show_mmr_bitfield 14 14 $val OTPLOCK { "" OTPLOCK }
+ show_mmr_bitfield 15 15 $val STESTROUTINE { "" STESTROUTINE }
+ show_mmr_bitfield 16 16 $val ADDRERR { "" ADDRERR }
+ show_mmr_bitfield 17 17 $val LWERR { "" LWERR }
+ show_mmr_bitfield 18 18 $val RSTOUTERR { "" RSTOUTERR }
+}
+
+# Show RCU_CRCTL bitfields
+proc show_rcu_crctl { name val } {
+ puts "$name [format 0x%08x $val]"
+ show_mmr_bitfield 0 0 $val CR0 { "" CR0 }
+ show_mmr_bitfield 1 1 $val CR1 { "" CR1 }
+ show_mmr_bitfield 2 2 $val CR2 { "" CR2 }
+ show_mmr_bitfield 3 3 $val CR3 { "" CR3 }
+}
+
+# Show RCU_CRSTAT bitfields
+proc show_rcu_crstat { name val } {
+ puts "$name [format 0x%08x $val]"
+ show_mmr_bitfield 0 0 $val CR0 { "" CR0 }
+ show_mmr_bitfield 1 1 $val CR1 { "" CR1 }
+ show_mmr_bitfield 2 2 $val CR2 { "" CR2 }
+ show_mmr_bitfield 3 3 $val CR3 { "" CR3 }
+}
+
+# Reset some debug registers in SHARC XI core debug component
+proc reset_sharcxi_debug_regs { base_addr } {
+ # Currently we only clear EMUCTL
+
+ set csdbg_emuctl [expr {$base_addr + 0x10}]
+ set csdbg_extdata [expr {$base_addr + 0x18}]
+
+ dap writemem 1 $csdbg_extdata 0
+ dap writemem 1 $csdbg_emuctl 0
+}
+
+# Configure CTIs so Cortex-A5 halt event will halt system peripherals, like watchdog timer
+proc adspsc5xx_configure_cti {} {
+ # Unlock CTI0 (Cortex A5 CTI)
+ # *pREG_CTI0_LAR = 0xC5ACCE55
+ mww phys 0x31128fb0 0xC5ACCE55
+
+ # Unlock CTI3 (System CTI)
+ # *pREG_CTI3_LAR = 0xC5ACCE55
+ mww phys 0x3110dfb0 0xC5ACCE55
+
+ # Enable CTI0 (Cortex A5 CTI)
+ # *pREG_CTI0_CTICONTROL = 1
+ mww phys 0x31128000 0x1
+
+ # Enable CTI3 (System CTI)
+ # *pREG_CTI3_CTICONTROL = 1
+ mww phys 0x3110d000 0x1
+
+ # Connect DBGTRIGGER of Cortex A5 to channel 0
+ # *pREG_CTI0_CTIINEN0 = 1
+ mww phys 0x31128020 0x1
+
+ # Connect peripheral halt to channel 0
+ # *pREG_CTI3_CTIOUTEN1 = 1
+ mww phys 0x3110d0a4 0x1
+
+ # Connect Cortex A5 DBGRESTART to channel 1
+ # *pREG_CTI0_CTIOUTEN7 = 2
+ mww phys 0x311280bc 0x2
+
+ # Connect peripheral DBGRESTART to channel 1
+ # *pREG_CTI3_CTIOUTEN7 = 2
+ mww phys 0x3110d0bc 0x2
+}
diff --git a/tcl/target/aducm3027.cfg b/tcl/target/aducm3027.cfg
new file mode 100644
index 0000000..a58ca3f
--- /dev/null
+++ b/tcl/target/aducm3027.cfg
@@ -0,0 +1,5 @@
+# Analog Devices ADuCM3027
+
+set CHIPNAME aducm3027
+set FLASHSIZE 0x20000
+source [find target/aducm302x.tcl]
diff --git a/tcl/target/aducm3029.cfg b/tcl/target/aducm3029.cfg
new file mode 100644
index 0000000..80252f5
--- /dev/null
+++ b/tcl/target/aducm3029.cfg
@@ -0,0 +1,5 @@
+# Analog Devices ADuCM3029
+
+set CHIPNAME aducm3029
+set FLASHSIZE 0x40000
+source [find target/aducm302x.tcl]
diff --git a/tcl/target/aducm302x.tcl b/tcl/target/aducm302x.tcl
new file mode 100644
index 0000000..b457a5a
--- /dev/null
+++ b/tcl/target/aducm302x.tcl
@@ -0,0 +1,90 @@
+# Common file for Analog Devices ADuCM302x
+
+# minimal dap memaccess values for adapter frequencies
+# 1 MHz: 6
+# 2 MHz: 8
+# 5 MHz: 18
+# 9 MHz: 27
+# 15 MHz: 43
+# 23 MHz: 74
+
+# hardware has 2 breakpoints, 1 watchpoints
+
+#
+# ADuCM302x devices support only SWD transport.
+#
+transport select swd
+
+source [find target/swj-dp.tcl]
+
+if { [info exists CHIPNAME] } {
+ set _CHIPNAME $CHIPNAME
+} else {
+ set _CHIPNAME aducm302x
+}
+
+if { [info exists ENDIAN] } {
+ set _ENDIAN $ENDIAN
+} else {
+ set _ENDIAN little
+}
+
+adapter_khz 1000
+
+if { [info exists CPUTAPID] } {
+ set _CPUTAPID $CPUTAPID
+} else {
+ set _CPUTAPID 0x2ba01477
+}
+
+swj_newdap $_CHIPNAME cpu -expected-id $_CPUTAPID
+
+set _TARGETNAME $_CHIPNAME.cpu
+target create $_TARGETNAME cortex_m -endian $_ENDIAN -chain-position $_TARGETNAME
+
+if { [info exists WORKAREASIZE] } {
+ set _WORKAREASIZE $WORKAREASIZE
+} else {
+ # default to 8K working area
+ set _WORKAREASIZE 0x2000
+}
+
+$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE
+
+$_TARGETNAME configure -event reset-init {
+ # disable watchdog, which will fire in about 32 second after reset.
+ mwh 0x40002c08 0x0
+ # After reset LR is 0xffffffff. There will be an error when GDB tries to
+ # read from that address.
+ reg lr 0
+}
+
+$_TARGETNAME configure -event gdb-attach {
+ reset init
+
+ arm semihosting enable
+}
+
+$_TARGETNAME configure -event gdb-flash-erase-start {
+ reset init
+ mww 0x40018054 0x1
+}
+
+$_TARGETNAME configure -event gdb-flash-write-end {
+ reset init
+ mww 0x40018054 0x1
+}
+
+set _FLASHNAME $_CHIPNAME.flash
+if { [info exists FLASHSIZE] } {
+ set _FLASHSIZE $FLASHSIZE
+} else {
+ set _FLASHSIZE 0x40000
+}
+flash bank $_FLASHNAME aducm302x 0 $_FLASHSIZE 0 0 $_TARGETNAME
+
+if {![using_hla]} {
+ # if srst is not fitted use SYSRESETREQ to
+ # perform a soft reset
+ cortex_m reset_config sysresetreq
+}
diff --git a/tcl/target/aducm350.cfg b/tcl/target/aducm350.cfg
new file mode 100644
index 0000000..142e7f7
--- /dev/null
+++ b/tcl/target/aducm350.cfg
@@ -0,0 +1,44 @@
+# script for ADUCM350
+
+#
+# ADUCM350 devices support both JTAG and SWD transports.
+#
+source [find target/swj-dp.tcl]
+
+# use SWD by default
+transport select swd
+
+if { [info exists CHIPNAME] } {
+ set _CHIPNAME $CHIPNAME
+} else {
+ set _CHIPNAME aducm350
+}
+
+if { [info exists ENDIAN] } {
+ set _ENDIAN $ENDIAN
+} else {
+ set _ENDIAN little
+}
+
+adapter_khz 1000
+
+if { [info exists CPUTAPID] } {
+ set _CPUTAPID $CPUTAPID
+} else {
+ if { [using_jtag] } {
+ # See STM Document RM0038
+ # Section 24.6.3
+ set _CPUTAPID 0x4ba00477
+ } {
+ set _CPUTAPID 0x2ba01477
+ }
+}
+
+swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID
+
+set _TARGETNAME $_CHIPNAME.cpu
+target create $_TARGETNAME cortex_m -endian $_ENDIAN -chain-position $_TARGETNAME
+
+$_TARGETNAME configure -event gdb-attach {
+ halt
+}
diff --git a/tcl/target/bf533.cfg b/tcl/target/bf533.cfg
new file mode 100644
index 0000000..7559e0d
--- /dev/null
+++ b/tcl/target/bf533.cfg
@@ -0,0 +1,6 @@
+set CHIPNAME bf533
+set CPUTAPID 0x027a50cb
+
+source [find cpu/blackfin/blackfin.cfg]
+
+# $_TARGETNAME configure -work-area-phys 0xffa00000 -work-area-size 0x4000 -work-area-backup 0
diff --git a/tcl/target/bf537.cfg b/tcl/target/bf537.cfg
new file mode 100644
index 0000000..57c25c5
--- /dev/null
+++ b/tcl/target/bf537.cfg
@@ -0,0 +1,34 @@
+set CHIPNAME bf537
+set CPUTAPID 0x027c80cb
+
+if {![info exists SDRAM_SIZE]} {
+ set SDRAM_SIZE 0x20000000
+}
+if {![info exists FLASH_SIZE]} {
+ set FLASH_SIZE 0x100000
+}
+
+# memory map
+
+set MAP_XML [find target/bf537_memory_map.xml]
+set MAP_FILE [open $MAP_XML]
+set _MEMORY_MAP [read $MAP_FILE]
+close $MAP_FILE
+
+global MEMORY_MAP
+# substitute SDRAM_SIZE and FLASH_SIZE
+set MEMORY_MAP [subst $_MEMORY_MAP]
+
+# target config
+
+set BLACKFIN_CONFIG_XML [find target/bf537_config.xml]
+set BLACKFIN_CONFIG_FILE [open $BLACKFIN_CONFIG_XML]
+set _BLACKFIN_CONFIG [read $BLACKFIN_CONFIG_FILE]
+close $BLACKFIN_CONFIG_FILE
+
+global BLACKFIN_CONFIG
+set BLACKFIN_CONFIG $_BLACKFIN_CONFIG
+
+source [find cpu/blackfin/blackfin.cfg]
+
+# $_TARGETNAME configure -work-area-phys 0xffa00000 -work-area-size 0x4000 -work-area-backup 0
diff --git a/tcl/target/bf537_config.xml b/tcl/target/bf537_config.xml
new file mode 100644
index 0000000..01e93a7
--- /dev/null
+++ b/tcl/target/bf537_config.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0"?>
+<!DOCTYPE blackfin-config SYSTEM "openocd_blackfin_config.dtd">
+<blackfin-config>
+ <processor name="bf537">
+ <config name="mdma_d0" value="0xffc00f00" />
+ <config name="mdma_s0" value="0xffc00f40" />
+ </processor>
+</blackfin-config>
diff --git a/tcl/target/bf537_memory_map.xml b/tcl/target/bf537_memory_map.xml
new file mode 100644
index 0000000..459c8cb
--- /dev/null
+++ b/tcl/target/bf537_memory_map.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0"?>
+<!DOCTYPE memory-map SYSTEM "openocd_memory_map.dtd">
+<memory-map>
+ <processor name="bf537">
+ <memory name="sdram" start="0x00000000" length="$SDRAM_SIZE" access="rw" />
+ <memory name="flash" start="0x20000000" length="$FLASH_SIZE" access="flash" />
+ <memory name="async_mem" start="0x20000000" length="0x400000" access="rw" />
+ <memory name="boot_rom" start="0xef000000" length="0x800" access="ro" />
+ <memory name="l1" start="0xff800000" length="0x400000" />
+ <core start="0xff800000" length="0x400000">
+ <memory name="l1" start="0xff800000" length="0x400000" />
+ <memory name="l1_data_a" start="0xff800000" length="0x4000" access="rw">
+ <property name="bank">"a"</property>
+ </memory>
+ <memory name="l1_data_a_cache" start="0xff804000" length="0x4000" access="dcache">
+ <property name="bank">"a"</property>
+ </memory>
+ <memory name="l1_data_b" start="0xff900000" length="0x4000" access="rw">
+ <property name="bank">"b"</property>
+ </memory>
+ <memory name="l1_data_b_cache" start="0xff904000" length="0x4000" access="dcache">
+ <property name="bank">"b"</property>
+ </memory>
+ <memory name="l1_code" start="0xffa00000" length="0x10000" access="itest" />
+ <memory name="l1_code_cache" start="0xffa10000" length="0x4000" access="icache" />
+ <memory name="l1_scratch" start="0xffb00000" length="0x1000" access="rw" />
+ </core>
+ <memory name="sysmmr" start="0xffc00000" length="0x200000" access="mmr" />
+ <memory name="coremmr" start="0xffe00000" length="0x200000" access="mmr" />
+ </processor>
+</memory-map>
diff --git a/tcl/target/bf561.cfg b/tcl/target/bf561.cfg
new file mode 100644
index 0000000..004998c
--- /dev/null
+++ b/tcl/target/bf561.cfg
@@ -0,0 +1,56 @@
+set CHIPNAME bf561
+set CPUTAPID 0x027bb0cb
+
+if {![info exists SDRAM_SIZE]} {
+ set SDRAM_SIZE 0x20000000
+}
+if {![info exists FLASH_SIZE]} {
+ set FLASH_SIZE 0x4000000
+}
+
+set MAP_XML [find target/bf561_memory_map.xml]
+set MAP_FILE [open $MAP_XML]
+set _MEMORY_MAP [read $MAP_FILE]
+close $MAP_FILE
+
+# Substitute SDRAM_SIZE and FLASH_SIZE
+global MEMORY_MAP
+set MEMORY_MAP [subst $_MEMORY_MAP]
+
+# target config
+
+set BLACKFIN_CONFIG_XML [find target/bf561_config.xml]
+set BLACKFIN_CONFIG_FILE [open $BLACKFIN_CONFIG_XML]
+set _BLACKFIN_CONFIG [read $BLACKFIN_CONFIG_FILE]
+close $BLACKFIN_CONFIG_FILE
+
+global BLACKFIN_CONFIG
+set BLACKFIN_CONFIG $_BLACKFIN_CONFIG
+
+# Maybe we should put the following into cpu/blackfin/bf561.cfg
+set _CHIPNAME $CHIPNAME
+set _CPUTAPID $CPUTAPID
+
+# TAP for Core B
+jtag newtap $_CHIPNAME b -irlen 5 -expected-id $_CPUTAPID -ignore-version
+
+# TAP for Core A
+jtag newtap $_CHIPNAME a -irlen 5 -expected-id $_CPUTAPID -ignore-version
+
+# Create target fore Core B
+set _TARGETNAME_B $_CHIPNAME.b
+target create $_TARGETNAME_B blackfin -chain-position $_TARGETNAME_B
+
+# Create target fore Core A
+set _TARGETNAME_A $_CHIPNAME.a
+target create $_TARGETNAME_A blackfin -chain-position $_TARGETNAME_A
+
+adapter_nsrst_delay 100
+jtag_ntrst_delay 100
+
+reset_config trst_only
+
+# FIXME
+gdb_memory_map disable
+
+# $_TARGETNAME configure -work-area-phys 0xffa00000 -work-area-size 0x4000 -work-area-backup 0
diff --git a/tcl/target/bf561_config.xml b/tcl/target/bf561_config.xml
new file mode 100644
index 0000000..29ed92b
--- /dev/null
+++ b/tcl/target/bf561_config.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0"?>
+<!DOCTYPE blackfin-config SYSTEM "openocd_blackfin_config.dtd">
+<blackfin-config>
+ <processor name="bf561">
+ <config name="mdma_d0" value="0xffc01800" />
+ <config name="mdma_s0" value="0xffc01840" />
+ </processor>
+</blackfin-config>
diff --git a/tcl/target/bf561_memory_map.xml b/tcl/target/bf561_memory_map.xml
new file mode 100644
index 0000000..f0e7060
--- /dev/null
+++ b/tcl/target/bf561_memory_map.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0"?>
+<!DOCTYPE memory-map SYSTEM "openocd_memory_map.dtd">
+<memory-map>
+ <processor name="bf561">
+ <memory name="sdram" start="0x00000000" length="0x20000000" access="rw" />
+ <memory name="flash" start="0x20000000" length="0x4000000" access="flash" />
+ <memory name="async_mem" start="0x20000000" length="0x10000000" access="rw" />
+ <memory name="boot_rom" start="0xef000000" length="0x800" access="ro" />
+ <memory name="l2_sram" start="0xfeb00000" length="0x20000" access="rw" />
+ <memory name="l1" start="0xff400000" length="0x800000" />
+ <core name="b" start="0xff400000" length="0x400000">
+ <memory name="l1" start="0xff400000" length="0x400000" />
+ <memory name="l1_data_a" start="0xff400000" length="0x4000" access="rw">
+ <property name="bank">"a"</property>
+ </memory>
+ <memory name="l1_data_a_cache" start="0xff404000" length="0x4000" access="dcache">
+ <property name="bank">"a"</property>
+ </memory>
+ <memory name="l1_data_b" start="0xff500000" length="0x4000" access="rw">
+ <property name="bank">"b"</property>
+ </memory>
+ <memory name="l1_data_b_cache" start="0xff504000" length="0x4000" access="dcache">
+ <property name="bank">"b"</property>
+ </memory>
+ <memory name="l1_code" start="0xff600000" length="0x4000" access="itest" />
+ <memory name="l1_code_cache" start="0xff610000" length="0x4000" access="icache" />
+ <memory name="l1_scratch" start="0xff700000" length="0x1000" access="rw" />
+ </core>
+ <core name="a" start="0xff800000" length="0x400000">
+ <memory name="l1" start="0xff800000" length="0x400000" />
+ <memory name="l1_data_a" start="0xff800000" length="0x4000" access="rw">
+ <property name="bank">"a"</property>
+ </memory>
+ <memory name="l1_data_a_cache" start="0xff804000" length="0x4000" access="dcache">
+ <property name="bank">"a"</property>
+ </memory>
+ <memory name="l1_data_b" start="0xff900000" length="0x4000" access="rw">
+ <property name="bank">"b"</property>
+ </memory>
+ <memory name="l1_data_b_cache" start="0xff904000" length="0x4000" access="dcache">
+ <property name="bank">"b"</property>
+ </memory>
+ <memory name="l1_code" start="0xffa00000" length="0x4000" access="itest" />
+ <memory name="l1_code_cache" start="0xffa10000" length="0x4000" access="icache" />
+ <memory name="l1_scratch" start="0xffb00000" length="0x1000" access="rw" />
+ </core>
+ <memory name="sysmmr" start="0xffc00000" length="0x200000" access="mmr" />
+ <memory name="coremmr" start="0xffe00000" length="0x200000" access="mmr" />
+ </processor>
+</memory-map>
diff --git a/tcl/target/omap3530.cfg b/tcl/target/omap3530.cfg
index f9dcf7c..9823072 100644
--- a/tcl/target/omap3530.cfg
+++ b/tcl/target/omap3530.cfg
@@ -39,7 +39,12 @@ set _TARGETNAME $_CHIPNAME.cpu
target create $_TARGETNAME cortex_a -chain-position $_CHIPNAME.dap
# SRAM: 64K at 0x4020.0000; use the first 16K
-$_TARGETNAME configure -work-area-phys 0x40200000 -work-area-size 0x4000
+# $_TARGETNAME configure -work-area-phys 0x40200000 -work-area-size 0x4000
+
+$_TARGETNAME configure -event gdb-attach {
+ reset init
+ arm semihosting enable stack_base=0x40210000
+}
###################
diff --git a/tcl/target/panther.cfg b/tcl/target/panther.cfg
new file mode 100644
index 0000000..ce99618
--- /dev/null
+++ b/tcl/target/panther.cfg
@@ -0,0 +1,51 @@
+if { [info exists CHIPNAME] } {
+ set _CHIPNAME $CHIPNAME
+} else {
+ set _CHIPNAME panther
+}
+
+source [find target/adi-jtag-controller.cfg]
+
+# CoreSight Debug Access Port (DAP)
+if { [info exists DAP_TAPID ] } {
+ set _DAP_TAPID $DAP_TAPID
+} else {
+ set _DAP_TAPID 0x4ba00477
+}
+
+jtag newtap $_CHIPNAME dap -irlen 4 -expected-id $_DAP_TAPID -disable
+jtag configure $_CHIPNAME.dap -event tap-enable "adjc_enable_dap $_CHIPNAME.adjc"
+
+# ADI JTAG Controller
+if { [info exists ADJC_TAPID ] } {
+ set _ADJC_TAPID $ADJC_TAPID
+} else {
+ set _ADJC_TAPID 0x028060cb
+}
+
+jtag newtap $_CHIPNAME adjc -irlen 5 -expected-id $_ADJC_TAPID
+
+
+# GDB target: Cortex-A5, using DAP
+set _TARGETNAME $_CHIPNAME.cpu
+# target create $_TARGETNAME cortex_a8 -chain-position $_CHIPNAME.dap -dbgbase 0x80110000
+target create $_TARGETNAME cortex_a8 -chain-position $_CHIPNAME.dap
+
+$_TARGETNAME configure -event gdb-attach {
+ reset init
+}
+
+# Once the JRC is up, enable our TAPs
+jtag configure $_CHIPNAME.adjc -event setup "
+ jtag tapenable $_CHIPNAME.dap
+"
+
+reset_config trst_only
+
+jtag_rclk 1000
+$_TARGETNAME configure -event "reset-start" { jtag_rclk 1000 }
+
+$_TARGETNAME configure -event reset-assert ""
+$_TARGETNAME configure -event reset-assert-post "cortex_a8 dbginit"
+
+gdb_memory_map disable
diff --git a/tcl/target/slater.cfg b/tcl/target/slater.cfg
new file mode 100644
index 0000000..09474f9
--- /dev/null
+++ b/tcl/target/slater.cfg
@@ -0,0 +1,46 @@
+if { [info exists CHIPNAME] } {
+ set _CHIPNAME $CHIPNAME
+} else {
+ set _CHIPNAME slater
+}
+
+source [find target/adi-jtag-controller.cfg]
+
+# CoreSight Debug Access Port (DAP)
+if { [info exists DAP_TAPID ] } {
+ set _DAP_TAPID $DAP_TAPID
+} else {
+ set _DAP_TAPID 0x4ba00477
+}
+
+jtag newtap $_CHIPNAME dap -irlen 4 -expected-id $_DAP_TAPID -disable
+jtag configure $_CHIPNAME.dap -event tap-enable "adjc_enable_dap $_CHIPNAME.adjc"
+
+# ADI JTAG Controller
+if { [info exists ADJC_TAPID ] } {
+ set _ADJC_TAPID $ADJC_TAPID
+} else {
+ set _ADJC_TAPID 0x028050cb
+}
+
+jtag newtap $_CHIPNAME adjc -irlen 5 -expected-id $_ADJC_TAPID
+
+
+set _TARGETNAME $_CHIPNAME.cpu
+target create $_TARGETNAME cortex_m3 -chain-position $_CHIPNAME.dap
+
+$_TARGETNAME configure -event gdb-attach { halt }
+
+# Once the JRC is up, enable our TAPs
+jtag configure $_CHIPNAME.adjc -event setup "
+ jtag tapenable $_CHIPNAME.dap
+"
+
+reset_config trst_only
+
+jtag_rclk 1000
+$_TARGETNAME configure -event "reset-start" { jtag_rclk 1000 }
+
+$_TARGETNAME configure -event reset-assert ""
+
+gdb_memory_map disable
--
Paul Fertser (***@gmail.com) just uploaded a new patch set to Gerrit, which you can find at http://openocd.zylin.com/4168
-- gerrit
commit 80f14312be2488e114ac5df485d1c77ff32b3fbb
Author: Paul Fertser <***@gmail.com>
Date: Thu Jun 22 19:35:17 2017 +0300
Huge code drop from AD developers
ftp://ftp.analog.com/pub/tools/patches/gnu_sources/cces/2.4.0/openocd-0.9.0-cces-2.4.0-src.tar.gz
Includes support for Blackfin target, aducm302x flash driver, ice1000
debug adapter, some Cortex-A tweaks/bugfixes, build process
modifications related to cross-compiling for windows.
Most of the code is apparently written by
Jie Zhang <***@analog.com>
Change-Id: Ia923787f20c5f4a297b59256cb644c9fd737ecda
Signed-off-by: Paul Fertser <***@gmail.com>
diff --git a/Makefile.am b/Makefile.am
index 2ddc96d..4b40041 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -67,7 +67,7 @@ $(THE_MANUAL): %.pdf: %.tex
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' | \
+TCL_FILES = find $(srcdir)/$(TCL_PATH) -name '*.cfg' -o -name '*.tcl' -o -name '*.txt' -o -name '*.xml' | \
sed -e 's,^$(srcdir)/$(TCL_PATH),,'
dist-hook:
diff --git a/acx.m4 b/acx.m4
new file mode 100644
index 0000000..9ff31eb
--- /dev/null
+++ b/acx.m4
@@ -0,0 +1,621 @@
+# Autoconf M4 include file defining utility macros for complex Canadian
+# cross builds.
+
+dnl ####
+dnl # _GCC_TOPLEV_NONCANONICAL_BUILD
+dnl # $build_alias or canonical $build if blank.
+dnl # Used when we would use $build_alias, but empty is not OK.
+AC_DEFUN([_GCC_TOPLEV_NONCANONICAL_BUILD],
+[AC_REQUIRE([AC_CANONICAL_BUILD]) []dnl
+case ${build_alias} in
+ "") build_noncanonical=${build} ;;
+ *) build_noncanonical=${build_alias} ;;
+esac
+]) []dnl # _GCC_TOPLEV_NONCANONICAL_BUILD
+
+dnl ####
+dnl # _GCC_TOPLEV_NONCANONICAL_HOST
+dnl # $host_alias, or $build_noncanonical if blank.
+dnl # Used when we would use $host_alias, but empty is not OK.
+AC_DEFUN([_GCC_TOPLEV_NONCANONICAL_HOST],
+[AC_REQUIRE([_GCC_TOPLEV_NONCANONICAL_BUILD]) []dnl
+case ${host_alias} in
+ "") host_noncanonical=${build_noncanonical} ;;
+ *) host_noncanonical=${host_alias} ;;
+esac
+]) []dnl # _GCC_TOPLEV_NONCANONICAL_HOST
+
+dnl ####
+dnl # _GCC_TOPLEV_NONCANONICAL_TARGET
+dnl # $target_alias or $host_noncanonical if blank.
+dnl # Used when we would use $target_alias, but empty is not OK.
+AC_DEFUN([_GCC_TOPLEV_NONCANONICAL_TARGET],
+[AC_REQUIRE([_GCC_TOPLEV_NONCANONICAL_HOST]) []dnl
+case ${target_alias} in
+ "") target_noncanonical=${host_noncanonical} ;;
+ *) target_noncanonical=${target_alias} ;;
+esac
+]) []dnl # _GCC_TOPLEV_NONCANONICAL_TARGET
+
+dnl ####
+dnl # ACX_NONCANONICAL_BUILD
+dnl # Like underscored version, but AC_SUBST's.
+AC_DEFUN([ACX_NONCANONICAL_BUILD],
+[AC_REQUIRE([_GCC_TOPLEV_NONCANONICAL_BUILD]) []dnl
+AC_SUBST(build_noncanonical)
+]) []dnl # ACX_NONCANONICAL_BUILD
+
+dnl ####
+dnl # ACX_NONCANONICAL_HOST
+dnl # Like underscored version, but AC_SUBST's.
+AC_DEFUN([ACX_NONCANONICAL_HOST],
+[AC_REQUIRE([_GCC_TOPLEV_NONCANONICAL_HOST]) []dnl
+AC_SUBST(host_noncanonical)
+]) []dnl # ACX_NONCANONICAL_HOST
+
+dnl ####
+dnl # ACX_NONCANONICAL_TARGET
+dnl # Like underscored version, but AC_SUBST's.
+AC_DEFUN([ACX_NONCANONICAL_TARGET],
+[AC_REQUIRE([_GCC_TOPLEV_NONCANONICAL_TARGET]) []dnl
+AC_SUBST(target_noncanonical)
+]) []dnl # ACX_NONCANONICAL_TARGET
+
+dnl ####
+dnl # GCC_TOPLEV_SUBDIRS
+dnl # GCC & friends build 'build', 'host', and 'target' tools. These must
+dnl # be separated into three well-known subdirectories of the build directory:
+dnl # build_subdir, host_subdir, and target_subdir. The values are determined
+dnl # here so that they can (theoretically) be changed in the future. They
+dnl # were previously reproduced across many different files.
+dnl #
+dnl # This logic really amounts to very little with autoconf 2.13; it will
+dnl # amount to a lot more with autoconf 2.5x.
+AC_DEFUN([GCC_TOPLEV_SUBDIRS],
+[AC_REQUIRE([_GCC_TOPLEV_NONCANONICAL_TARGET]) []dnl
+AC_REQUIRE([_GCC_TOPLEV_NONCANONICAL_BUILD]) []dnl
+
+# post-stage1 host modules use a different CC_FOR_BUILD so, in order to
+# have matching libraries, they should use host libraries: Makefile.tpl
+# arranges to pass --with-build-libsubdir=$(HOST_SUBDIR).
+# However, they still use the build modules, because the corresponding
+# host modules (e.g. bison) are only built for the host when bootstrap
+# finishes. So:
+# - build_subdir is where we find build modules, and never changes.
+# - build_libsubdir is where we find build libraries, and can be overridden.
+
+# Prefix 'build-' so this never conflicts with target_subdir.
+build_subdir="build-${build_noncanonical}"
+AC_ARG_WITH(build-libsubdir,
+[ --with-build-libsubdir=[DIR] Directory where to find libraries for build system],
+build_libsubdir="$withval",
+build_libsubdir="$build_subdir")
+# --srcdir=. covers the toplevel, while "test -d" covers the subdirectories
+if ( test $srcdir = . && test -d gcc ) \
+ || test -d $srcdir/../host-${host_noncanonical}; then
+ host_subdir="host-${host_noncanonical}"
+else
+ host_subdir=.
+fi
+# No prefix.
+target_subdir=${target_noncanonical}
+AC_SUBST([build_libsubdir]) []dnl
+AC_SUBST([build_subdir]) []dnl
+AC_SUBST([host_subdir]) []dnl
+AC_SUBST([target_subdir]) []dnl
+]) []dnl # GCC_TOPLEV_SUBDIRS
+
+
+####
+# _NCN_TOOL_PREFIXES: Some stuff that oughtta be done in AC_CANONICAL_SYSTEM
+# or AC_INIT.
+# These demand that AC_CANONICAL_SYSTEM be called beforehand.
+AC_DEFUN([_NCN_TOOL_PREFIXES],
+[ncn_tool_prefix=
+test -n "$host_alias" && ncn_tool_prefix=$host_alias-
+ncn_target_tool_prefix=
+test -n "$target_alias" && ncn_target_tool_prefix=$target_alias-
+]) []dnl # _NCN_TOOL_PREFIXES
+
+####
+# NCN_STRICT_CHECK_TOOLS(variable, progs-to-check-for,[value-if-not-found],[path])
+# Like plain AC_CHECK_TOOLS, but require prefix if build!=host.
+
+AC_DEFUN([NCN_STRICT_CHECK_TOOLS],
+[AC_REQUIRE([_NCN_TOOL_PREFIXES]) []dnl
+AC_ARG_VAR([$1], [$1 for the host])
+
+if test -n "[$]$1"; then
+ ac_cv_prog_$1=[$]$1
+elif test -n "$ac_cv_prog_$1"; then
+ $1=$ac_cv_prog_$1
+fi
+
+if test -n "$ac_cv_prog_$1"; then
+ for ncn_progname in $2; do
+ AC_CHECK_PROG([$1], [${ncn_progname}], [${ncn_progname}], , [$4])
+ done
+fi
+
+for ncn_progname in $2; do
+ if test -n "$ncn_tool_prefix"; then
+ AC_CHECK_PROG([$1], [${ncn_tool_prefix}${ncn_progname}],
+ [${ncn_tool_prefix}${ncn_progname}], , [$4])
+ fi
+ if test -z "$ac_cv_prog_$1" && test $build = $host ; then
+ AC_CHECK_PROG([$1], [${ncn_progname}], [${ncn_progname}], , [$4])
+ fi
+ test -n "$ac_cv_prog_$1" && break
+done
+
+if test -z "$ac_cv_prog_$1" ; then
+ ifelse([$3],[], [set dummy $2
+ if test $build = $host ; then
+ $1="[$]2"
+ else
+ $1="${ncn_tool_prefix}[$]2"
+ fi], [$1="$3"])
+fi
+]) []dnl # NCN_STRICT_CHECK_TOOLS
+
+####
+# NCN_STRICT_CHECK_TARGET_TOOLS(variable, progs-to-check-for,[value-if-not-found],[path])
+# Like CVS Autoconf AC_CHECK_TARGET_TOOLS, but require prefix if build!=target.
+
+AC_DEFUN([NCN_STRICT_CHECK_TARGET_TOOLS],
+[AC_REQUIRE([_NCN_TOOL_PREFIXES]) []dnl
+AC_ARG_VAR([$1], patsubst([$1], [_FOR_TARGET$], [])[ for the target])
+
+if test -n "[$]$1"; then
+ ac_cv_prog_$1=[$]$1
+elif test -n "$ac_cv_prog_$1"; then
+ $1=$ac_cv_prog_$1
+fi
+
+if test -n "$ac_cv_prog_$1"; then
+ for ncn_progname in $2; do
+ AC_CHECK_PROG([$1], [${ncn_progname}], [${ncn_progname}], , [$4])
+ done
+fi
+
+if test -z "$ac_cv_prog_$1" && test -n "$with_build_time_tools"; then
+ for ncn_progname in $2; do
+ AC_MSG_CHECKING([for ${ncn_progname} in $with_build_time_tools])
+ if test -x $with_build_time_tools/${ncn_progname}; then
+ ac_cv_prog_$1=$with_build_time_tools/${ncn_progname}
+ AC_MSG_RESULT(yes)
+ break
+ else
+ AC_MSG_RESULT(no)
+ fi
+ done
+fi
+
+if test -z "$ac_cv_prog_$1"; then
+ for ncn_progname in $2; do
+ if test -n "$ncn_target_tool_prefix"; then
+ AC_CHECK_PROG([$1], [${ncn_target_tool_prefix}${ncn_progname}],
+ [${ncn_target_tool_prefix}${ncn_progname}], , [$4])
+ fi
+ if test -z "$ac_cv_prog_$1" && test $build = $target ; then
+ AC_CHECK_PROG([$1], [${ncn_progname}], [${ncn_progname}], , [$4])
+ fi
+ test -n "$ac_cv_prog_$1" && break
+ done
+fi
+
+if test -z "$ac_cv_prog_$1" ; then
+ ifelse([$3],[], [set dummy $2
+ if test $build = $target ; then
+ $1="[$]2"
+ else
+ $1="${ncn_target_tool_prefix}[$]2"
+ fi], [$1="$3"])
+else
+ $1="$ac_cv_prog_$1"
+fi
+]) []dnl # NCN_STRICT_CHECK_TARGET_TOOLS
+
+
+# Backported from Autoconf 2.5x; can go away when and if
+# we switch. Put the OS path separator in $PATH_SEPARATOR.
+AC_DEFUN([ACX_PATH_SEP], [
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ echo "#! /bin/sh" >conf$$.sh
+ echo "exit 0" >>conf$$.sh
+ chmod +x conf$$.sh
+ if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+ PATH_SEPARATOR=';'
+ else
+ PATH_SEPARATOR=:
+ fi
+ rm -f conf$$.sh
+fi
+])
+
+
+AC_DEFUN([ACX_TOOL_DIRS], [
+AC_REQUIRE([ACX_PATH_SEP])
+if test "x$exec_prefix" = xNONE; then
+ if test "x$prefix" = xNONE; then
+ gcc_cv_tool_prefix=$ac_default_prefix
+ else
+ gcc_cv_tool_prefix=$prefix
+ fi
+else
+ gcc_cv_tool_prefix=$exec_prefix
+fi
+
+# If there is no compiler in the tree, use the PATH only. In any
+# case, if there is no compiler in the tree nobody should use
+# AS_FOR_TARGET and LD_FOR_TARGET.
+if test x$host = x$build && test -f $srcdir/gcc/BASE-VER; then
+ gcc_version=`cat $srcdir/gcc/BASE-VER`
+ gcc_cv_tool_dirs="$gcc_cv_tool_prefix/libexec/gcc/$target_noncanonical/$gcc_version$PATH_SEPARATOR"
+ gcc_cv_tool_dirs="$gcc_cv_tool_dirs$gcc_cv_tool_prefix/libexec/gcc/$target_noncanonical$PATH_SEPARATOR"
+ gcc_cv_tool_dirs="$gcc_cv_tool_dirs/usr/lib/gcc/$target_noncanonical/$gcc_version$PATH_SEPARATOR"
+ gcc_cv_tool_dirs="$gcc_cv_tool_dirs/usr/lib/gcc/$target_noncanonical$PATH_SEPARATOR"
+ gcc_cv_tool_dirs="$gcc_cv_tool_dirs$gcc_cv_tool_prefix/$target_noncanonical/bin/$target_noncanonical/$gcc_version$PATH_SEPARATOR"
+ gcc_cv_tool_dirs="$gcc_cv_tool_dirs$gcc_cv_tool_prefix/$target_noncanonical/bin$PATH_SEPARATOR"
+else
+ gcc_cv_tool_dirs=
+fi
+
+if test x$build = x$target && test -n "$md_exec_prefix"; then
+ gcc_cv_tool_dirs="$gcc_cv_tool_dirs$md_exec_prefix$PATH_SEPARATOR"
+fi
+
+]) []dnl # ACX_TOOL_DIRS
+
+# ACX_HAVE_GCC_FOR_TARGET
+# Check if the variable GCC_FOR_TARGET really points to a GCC binary.
+AC_DEFUN([ACX_HAVE_GCC_FOR_TARGET], [
+cat > conftest.c << \EOF
+#ifdef __GNUC__
+ gcc_yay;
+#endif
+EOF
+if ($GCC_FOR_TARGET -E conftest.c | grep gcc_yay) > /dev/null 2>&1; then
+ have_gcc_for_target=yes
+else
+ GCC_FOR_TARGET=${ncn_target_tool_prefix}gcc
+ have_gcc_for_target=no
+fi
+rm conftest.c
+])
+
+# ACX_CHECK_INSTALLED_TARGET_TOOL(VAR, PROG)
+# Searching for installed target binutils. We need to take extra care,
+# else we may find the wrong assembler, linker, etc., and lose.
+#
+# First try --with-build-time-tools, if specified.
+#
+# For build != host, we ask the installed GCC for the name of the tool it
+# uses, and accept it if it is an absolute path. This is because the
+# only good choice for a compiler is the same GCC version that is being
+# installed (or we couldn't make target libraries), and we assume that
+# on the host system we'll have not only the same GCC version, but also
+# the same binutils version.
+#
+# For build == host, search the same directories that the installed
+# compiler will search. We used to do this for the assembler, linker,
+# and nm only; for simplicity of configuration, however, we extend this
+# criterion to tools (such as ar and ranlib) that are never invoked by
+# the compiler, to avoid mismatches.
+#
+# Also note we have to check MD_EXEC_PREFIX before checking the user's path
+# if build == target. This makes the most sense only when bootstrapping,
+# but we also do so when build != host. In this case, we hope that the
+# build and host systems will have similar contents of MD_EXEC_PREFIX.
+#
+# If we do not find a suitable binary, then try the user's path.
+
+AC_DEFUN([ACX_CHECK_INSTALLED_TARGET_TOOL], [
+AC_REQUIRE([ACX_TOOL_DIRS])
+AC_REQUIRE([ACX_HAVE_GCC_FOR_TARGET])
+if test -z "$ac_cv_path_$1" ; then
+ if test -n "$with_build_time_tools"; then
+ AC_MSG_CHECKING([for $2 in $with_build_time_tools])
+ if test -x $with_build_time_tools/$2; then
+ $1=`cd $with_build_time_tools && pwd`/$2
+ ac_cv_path_$1=[$]$1
+ AC_MSG_RESULT([$ac_cv_path_$1])
+ else
+ AC_MSG_RESULT(no)
+ fi
+ elif test $build != $host && test $have_gcc_for_target = yes; then
+ $1=`$GCC_FOR_TARGET --print-prog-name=$2`
+ test [$]$1 = $2 && $1=
+ test -n "[$]$1" && ac_cv_path_$1=[$]$1
+ fi
+fi
+if test -z "$ac_cv_path_$1" && test -n "$gcc_cv_tool_dirs"; then
+ AC_PATH_PROG([$1], [$2], [], [$gcc_cv_tool_dirs])
+fi
+if test -z "$ac_cv_path_$1" ; then
+ NCN_STRICT_CHECK_TARGET_TOOLS([$1], [$2])
+else
+ $1=$ac_cv_path_$1
+fi
+]) []dnl # ACX_CHECK_INSTALLED_TARGET_TOOL
+
+###
+# AC_PROG_CPP_WERROR
+# Used for autoconf 2.5x to force AC_PREPROC_IFELSE to reject code which
+# triggers warnings from the preprocessor. Will be in autoconf 2.58.
+# For now, using this also overrides header checks to use only the
+# preprocessor (matches 2.13 behavior; matching 2.58's behavior is a
+# bit harder from here).
+# Eventually autoconf will default to checking headers with the compiler
+# instead, and we'll have to do this differently.
+
+AC_DEFUN([AC_PROG_CPP_WERROR],
+[AC_REQUIRE([AC_PROG_CPP])dnl
+m4_define([AC_CHECK_HEADER],m4_defn([_AC_CHECK_HEADER_OLD]))
+ac_c_preproc_warn_flag=yes])# AC_PROG_CPP_WERROR
+
+# Test for GNAT.
+# We require the gnatbind & gnatmake programs, as well as a compiler driver
+# that understands Ada. We use the user's CC setting, already found, and
+# possibly add $1 to the command-line parameters.
+#
+# Sets the shell variable have_gnat to yes or no as appropriate, and
+# substitutes GNATBIND and GNATMAKE.
+AC_DEFUN([ACX_PROG_GNAT],
+[AC_REQUIRE([AC_CHECK_TOOL_PREFIX])
+AC_REQUIRE([AC_PROG_CC])
+AC_CHECK_TOOL(GNATBIND, gnatbind, no)
+AC_CHECK_TOOL(GNATMAKE, gnatmake, no)
+AC_CACHE_CHECK([whether compiler driver understands Ada],
+ acx_cv_cc_gcc_supports_ada,
+[cat >conftest.adb <<EOF
+procedure conftest is begin null; end conftest;
+EOF
+acx_cv_cc_gcc_supports_ada=no
+# There is a bug in old released versions of GCC which causes the
+# driver to exit successfully when the appropriate language module
+# has not been installed. This is fixed in 2.95.4, 3.0.2, and 3.1.
+# Therefore we must check for the error message as well as an
+# unsuccessful exit.
+# Other compilers, like HP Tru64 UNIX cc, exit successfully when
+# given a .adb file, but produce no object file. So we must check
+# if an object file was really produced to guard against this.
+errors=`(${CC} $1[]m4_ifval([$1], [ ])-c conftest.adb) 2>&1 || echo failure`
+if test x"$errors" = x && test -f conftest.$ac_objext; then
+ acx_cv_cc_gcc_supports_ada=yes
+fi
+rm -f conftest.*])
+
+if test "x$GNATBIND" != xno && test "x$GNATMAKE" != xno && test x$acx_cv_cc_gcc_supports_ada != xno; then
+ have_gnat=yes
+else
+ have_gnat=no
+fi
+])
+
+dnl 'make compare' can be significantly faster, if cmp itself can
+dnl skip bytes instead of using tail. The test being performed is
+dnl "if cmp --ignore-initial=2 t1 t2 && ! cmp --ignore-initial=1 t1 t2"
+dnl but we need to sink errors and handle broken shells. We also test
+dnl for the parameter format "cmp file1 file2 skip1 skip2" which is
+dnl accepted by cmp on some systems.
+AC_DEFUN([ACX_PROG_CMP_IGNORE_INITIAL],
+[AC_CACHE_CHECK([how to compare bootstrapped objects], gcc_cv_prog_cmp_skip,
+[ echo abfoo >t1
+ echo cdfoo >t2
+ gcc_cv_prog_cmp_skip='tail +16c $$f1 > tmp-foo1; tail +16c $$f2 > tmp-foo2; cmp tmp-foo1 tmp-foo2'
+ if cmp t1 t2 2 2 > /dev/null 2>&1; then
+ if cmp t1 t2 1 1 > /dev/null 2>&1; then
+ :
+ else
+ gcc_cv_prog_cmp_skip='cmp $$f1 $$f2 16 16'
+ fi
+ fi
+ if cmp --ignore-initial=2 t1 t2 > /dev/null 2>&1; then
+ if cmp --ignore-initial=1 t1 t2 > /dev/null 2>&1; then
+ :
+ else
+ gcc_cv_prog_cmp_skip='cmp --ignore-initial=16 $$f1 $$f2'
+ fi
+ fi
+ rm t1 t2
+])
+do_compare="$gcc_cv_prog_cmp_skip"
+AC_SUBST(do_compare)
+])
+
+dnl See whether we can include both string.h and strings.h.
+AC_DEFUN([ACX_HEADER_STRING],
+[AC_CACHE_CHECK([whether string.h and strings.h may both be included],
+ gcc_cv_header_string,
+[AC_TRY_COMPILE([#include <string.h>
+#include <strings.h>], , gcc_cv_header_string=yes, gcc_cv_header_string=no)])
+if test $gcc_cv_header_string = yes; then
+ AC_DEFINE(STRING_WITH_STRINGS, 1, [Define if you can safely include both <string.h> and <strings.h>.])
+fi
+])
+
+dnl See if stdbool.h properly defines bool and true/false.
+dnl Check whether _Bool is built-in.
+AC_DEFUN([ACX_HEADER_STDBOOL],
+[AC_CACHE_CHECK([for working stdbool.h],
+ ac_cv_header_stdbool_h,
+[AC_TRY_COMPILE([#include <stdbool.h>],
+[bool foo = false;],
+ac_cv_header_stdbool_h=yes, ac_cv_header_stdbool_h=no)])
+if test $ac_cv_header_stdbool_h = yes; then
+ AC_DEFINE(HAVE_STDBOOL_H, 1,
+ [Define if you have a working <stdbool.h> header file.])
+fi
+AC_CACHE_CHECK(for built-in _Bool, gcc_cv_c__bool,
+[AC_TRY_COMPILE(,
+[_Bool foo;],
+gcc_cv_c__bool=yes, gcc_cv_c__bool=no)
+])
+if test $gcc_cv_c__bool = yes; then
+ AC_DEFINE(HAVE__BOOL, 1, [Define if the \`_Bool' type is built-in.])
+fi
+])
+
+dnl See if hard links work and if not, try to substitute $1 or simple copy.
+AC_DEFUN([ACX_PROG_LN],
+[AC_MSG_CHECKING(whether ln works)
+AC_CACHE_VAL(acx_cv_prog_LN,
+[rm -f conftestdata_t
+echo >conftestdata_f
+if ln conftestdata_f conftestdata_t 2>/dev/null
+then
+ acx_cv_prog_LN=ln
+else
+ acx_cv_prog_LN=no
+fi
+rm -f conftestdata_f conftestdata_t
+])dnl
+if test $acx_cv_prog_LN = no; then
+ LN="ifelse([$1],,cp,[$1])"
+ AC_MSG_RESULT([no, using $LN])
+else
+ LN="$acx_cv_prog_LN"
+ AC_MSG_RESULT(yes)
+fi
+AC_SUBST(LN)dnl
+])
+
+dnl GCC_TARGET_TOOL(PROGRAM, TARGET-VAR, HOST-VAR, IN-TREE-TOOL, LANGUAGE)
+AC_DEFUN([GCC_TARGET_TOOL],
+[AC_MSG_CHECKING(where to find the target $1)
+if test "x${build}" != "x${host}" ; then
+ if expr "x[$]$2" : "x/" > /dev/null; then
+ # We already found the complete path
+ ac_dir=`dirname [$]$2`
+ AC_MSG_RESULT(pre-installed in $ac_dir)
+ else
+ # Canadian cross, just use what we found
+ AC_MSG_RESULT(pre-installed)
+ fi
+else
+ ifelse([$4],,,
+ [ok=yes
+ case " ${configdirs} " in
+ *" patsubst([$4], [/.*], []) "*) ;;
+ *) ok=no ;;
+ esac
+ ifelse([$5],,,
+ [case ,${enable_languages}, in
+ *,$5,*) ;;
+ *) ok=no ;;
+ esac])
+ if test $ok = yes; then
+ # An in-tree tool is available and we can use it
+ $2='$$r/$(HOST_SUBDIR)/$4'
+ AC_MSG_RESULT(just compiled)
+ el])if expr "x[$]$2" : "x/" > /dev/null; then
+ # We already found the complete path
+ ac_dir=`dirname [$]$2`
+ AC_MSG_RESULT(pre-installed in $ac_dir)
+ elif test "x$target" = "x$host"; then
+ # We can use an host tool
+ $2='$($3)'
+ AC_MSG_RESULT(host tool)
+ else
+ # We need a cross tool
+ AC_MSG_RESULT(pre-installed)
+ fi
+fi
+AC_SUBST($2)])
+
+
+dnl Locate a program and check that its version is acceptable.
+dnl ACX_PROG_CHECK_VER(var, name, version-switch,
+dnl version-extract-regexp, version-glob)
+AC_DEFUN([ACX_CHECK_PROG_VER],[
+ AC_CHECK_PROG([$1], [$2], [$2])
+ if test -n "[$]$1"; then
+ # Found it, now check the version.
+ AC_CACHE_CHECK([for modern $2],
+ [gcc_cv_prog_$2_modern],
+ [ac_prog_version=`eval [$]$1 $3 2>&1 |
+ sed -n 's/^.*patsubst([[$4]],/,\/).*$/\1/p'`
+
+ [case $ac_prog_version in
+ '') gcc_cv_prog_$2_modern=no;;
+ $5) gcc_cv_prog_$2_modern=yes;;
+ *) gcc_cv_prog_$2_modern=no;;
+ esac]
+ ])
+ else
+ gcc_cv_prog_$2_modern=no
+ fi
+ if test $gcc_cv_prog_$2_modern = no; then
+ $1="${CONFIG_SHELL-/bin/sh} $ac_aux_dir/missing $2"
+ fi
+])
+
+dnl Support the --with-pkgversion configure option.
+dnl ACX_PKGVERSION(default-pkgversion)
+AC_DEFUN([ACX_PKGVERSION],[
+ AC_ARG_WITH(pkgversion,
+ AS_HELP_STRING([--with-pkgversion=PKG],
+ [Use PKG in the version string in place of "$1"]),
+ [case "$withval" in
+ yes) AC_MSG_ERROR([package version not specified]) ;;
+ no) PKGVERSION= ;;
+ *) PKGVERSION="($withval) " ;;
+ esac],
+ PKGVERSION="($1) "
+ )
+ AC_SUBST(PKGVERSION)
+])
+
+dnl Support the --with-bugurl configure option.
+dnl ACX_BUGURL(default-bugurl)
+AC_DEFUN([ACX_BUGURL],[
+ AC_ARG_WITH(bugurl,
+ AS_HELP_STRING([--with-bugurl=URL],
+ [Direct users to URL to report a bug]),
+ [case "$withval" in
+ yes) AC_MSG_ERROR([bug URL not specified]) ;;
+ no) BUGURL=
+ ;;
+ *) BUGURL="$withval"
+ ;;
+ esac],
+ BUGURL="$1"
+ )
+ case ${BUGURL} in
+ "")
+ REPORT_BUGS_TO=
+ REPORT_BUGS_TEXI=
+ ;;
+ *)
+ REPORT_BUGS_TO="<$BUGURL>"
+ REPORT_BUGS_TEXI=@uref{`echo "$BUGURL" | sed 's/@/@@/g'`}
+ ;;
+ esac;
+ AC_SUBST(REPORT_BUGS_TO)
+ AC_SUBST(REPORT_BUGS_TEXI)
+])
+
+dnl ####
+dnl # ACX_CHECK_CYGWIN_CAT_WORKS
+dnl # On Cygwin hosts, check that the cat command ignores
+dnl # carriage returns as otherwise builds will not work.
+dnl # See binutils PR 4334 for more details.
+AC_DEFUN([ACX_CHECK_CYGWIN_CAT_WORKS],[
+AC_MSG_CHECKING([to see if cat works as expected])
+echo a >cygwin-cat-check
+if test `cat cygwin-cat-check` = a ; then
+ rm cygwin-cat-check
+ AC_MSG_RESULT(yes)
+else
+ rm cygwin-cat-check
+ AC_MSG_RESULT(no)
+ AC_MSG_ERROR([The cat command does not ignore carriage return characters.
+ Please either mount the build directory in binary mode or run the following
+ commands before running any configure script:
+set -o igncr
+export SHELLOPTS
+ ])
+fi
+])
diff --git a/config_subdir.m4 b/config_subdir.m4
index 1c79098..aa88053 100644
--- a/config_subdir.m4
+++ b/config_subdir.m4
@@ -11,16 +11,3 @@ 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],
-[echo -e '#!/bin/sh\nexec "`dirname "'\$'0"`/configure" $2 "'\$'@"' > "$srcdir/$1/configure.gnu"
-])
-])
diff --git a/configure.ac b/configure.ac
index 1022808..cd461d3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,9 +1,19 @@
AC_PREREQ(2.64)
-AC_INIT([openocd], [0.9.0],
- [OpenOCD Mailing List <openocd-***@lists.sourceforge.net>])
+AC_INIT([openocd], [0.9.0])
AC_CONFIG_SRCDIR([src/openocd.c])
+m4_include([acx.m4])
+ACX_PKGVERSION([OpenOCD])
+ACX_BUGURL([openocd-***@lists.sourceforge.net])
+
+AC_DEFINE_UNQUOTED([PKGVERSION], ["$PKGVERSION"],
+ [Define to the package version.])dnl
+AC_DEFINE_UNQUOTED([REPORT_BUGS_TO], ["$REPORT_BUGS_TO"],
+ [Define to the URL or email address for report bugs to.])dnl
+
m4_include([config_subdir.m4])dnl
+m4_include([lib-link.m4])
+m4_include([expat.m4])
# check for makeinfo before calling AM_INIT_AUTOMAKE
AC_CHECK_PROG([MAKEINFO], [makeinfo], [makeinfo])
@@ -140,9 +150,14 @@ AC_C_BIGENDIAN
AC_CHECK_FUNCS([strndup])
AC_CHECK_FUNCS([strnlen])
AC_CHECK_FUNCS([gettimeofday])
+AC_CHECK_FUNCS([nanosleep])
AC_CHECK_FUNCS([usleep])
AC_CHECK_FUNCS([vasprintf])
+AC_CHECK_TYPE([struct timespec],
+ [AC_DEFINE(HAVE_STRUCT_TIMESPEC, 1, [Define to 1 if you have the struct timespec type])],
+ [], [[#include <time.h>]])
+
build_bitbang=no
build_bitq=no
is_cygwin=no
@@ -196,11 +211,13 @@ __EOF__
m4_define([ADAPTER_ARG], [m4_argn([1], $1)])
m4_define([ADAPTER_DESC], [m4_argn([2], $1)])
m4_define([ADAPTER_SYM], [m4_argn([3], $1)])
-m4_define([ADAPTER_VAR], [enable_[]ADAPTER_ARG($1)])
+m4_define([ADAPTER_VAR], [enable_[]m4_translit(ADAPTER_ARG($1), [-], [_])])
m4_define([ADAPTER_OPT], [m4_translit(ADAPTER_ARG($1), [_], [-])])
m4_define([USB1_ADAPTERS],
[[[ftdi], [MPSSE mode of FTDI based devices], [FTDI]],
+ [[ice-1000], [Analog Devices ICE-1000], [ICE_1000]],
+ [[ice-2000], [Analog Devices ICE-2000], [ICE_2000]],
[[stlink], [ST-Link JTAG Programmer], [HLADAPTER_STLINK]],
[[ti_icdi], [TI ICDI JTAG Programmer], [HLADAPTER_ICDI]],
[[ulink], [Keil ULINK JTAG Programmer], [ULINK]],
@@ -279,6 +296,8 @@ AC_ARG_WITH(ftd2xx-lib,
with_ftd2xx_lib=static
])
+AM_EXPAT_LINK
+
AC_ARG_ENABLE([doxygen-html],
AS_HELP_STRING([--disable-doxygen-html],
[Disable building Doxygen manual as HTML.]),
@@ -594,8 +613,6 @@ case $host in
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.])
@@ -781,7 +798,8 @@ fi
if test $use_internal_jimtcl = yes; then
if test -f "$srcdir/jimtcl/configure.ac"; then
- AX_CONFIG_SUBDIR_OPTION([jimtcl], [--disable-install-jim])
+ ac_configure_args="$ac_configure_args --disable-install-jim"
+ AC_CONFIG_SUBDIRS([jimtcl])
else
AC_MSG_ERROR([jimtcl not found, run git submodule init and git submodule update.])
fi
diff --git a/contrib/loaders/flash/aducm302x.s b/contrib/loaders/flash/aducm302x.s
new file mode 100644
index 0000000..a057b63
--- /dev/null
+++ b/contrib/loaders/flash/aducm302x.s
@@ -0,0 +1,77 @@
+/***************************************************************************
+ * Copyright (C) 2016 Analog Devices, 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 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
+ ***************************************************************************/
+
+ .text
+ .syntax unified
+ .cpu cortex-m3
+ .thumb
+ .thumb_func
+
+/*
+ * Params :
+ * r0 = workarea start
+ * r1 = workarea end
+ * r2 = target address
+ * r3 = count (64bit double words)
+ *
+ * Clobbered:
+ * r4 = pFLASH_CTRL_BASE
+ * r5 = FLASHWRITECMD
+ * r6 - tmp
+ * r7 - rp
+ * r8 - wp, tmp
+ */
+
+write:
+ ldr r4, pFLASH_CTRL_BASE
+ ldr r5, FLASHWRITECMD
+
+wait_fifo:
+ ldr r8, [r0, #0] /* read wp */
+ cmp r8, #0 /* abort if wp == 0 */
+ beq exit
+ ldr r7, [r0, #4] /* read rp */
+ cmp r7, r8 /* wait until rp != wp */
+ beq wait_fifo
+
+mainloop:
+ str r2, [r4, #0xc] /* KH_ADDR - write address */
+ add r2, r2, #8 /* increment target address */
+ ldr r6, [r7], #4
+ ldr r8, [r7], #4
+ str r6, [r4, #0x10] /* KH_DATA0 - write data */
+ str r8, [r4, #0x14] /* KH_DATA1 - write data */
+ str r5, [r4, #8] /* CMD - enable write */
+busy:
+ ldr r8, [r4, #0]
+ tst r8, #4
+ beq busy
+
+ cmp r7, r1 /* wrap rp at end of buffer */
+ it cs
+ addcs r7, r0, #8 /* skip loader args */
+ str r7, [r0, #4] /* store rp */
+ subs r3, r3, #1 /* decrement word count */
+ cbz r3, exit /* loop if not done */
+ b wait_fifo
+exit:
+ bkpt #0
+
+pFLASH_CTRL_BASE: .word 0x40018000
+FLASHWRITECMD: .word 0x4
diff --git a/doc/openocd.texi b/doc/openocd.texi
index 511bc6c..1ad7b37 100644
--- a/doc/openocd.texi
+++ b/doc/openocd.texi
@@ -62,6 +62,8 @@ Free Documentation License''.
* About:: About OpenOCD
* Developers:: OpenOCD Developer Resources
* Debug Adapter Hardware:: Debug Adapter Hardware
+* Supported Targets:: Supported Targets
+* Supported Boards:: Supported Boards
* About Jim-Tcl:: About Jim-Tcl
* Running:: Running OpenOCD
* OpenOCD Project Setup:: OpenOCD Project Setup
@@ -355,6 +357,29 @@ For more information, visit:
@b{ZY1000} See: @url{http://www.ultsol.com/index.php/component/content/article/8/210-zylin-zy1000-main}
+@section USB Analog Devices ICE-1000 and ICE-2000
+
+The Analog Devices ICE-1000 and ICE-2000 support debugging Analog Devices
+processors. Both of them support JTAG and SWD.
+
+ICE-1000 supports frequency up to 5 MHz (1 MHz, 2 MHz, 5 MHz).
+ICE-2000 supports frequency up to 46 MHz (1 MHz, 2 MHz, 5 MHz, 9 MHz, 15 MHz, 23 MHz, 46 MHz).
+
+ICE-1000 and ICE-2000 feature a multi-color LED for indicating emulator status:
+
+@itemize @bullet
+@item @b{Green}
+@* indicates the emulator is ready for operations.
+@item @b{Yellow}
+@* indicates the emulator has an issue.
+@item @b{Magenta}
+@* indicates the emulator is in JTAG mode.
+@item @b{Cyan}
+@* indicates the emulator is in SWD mode.
+@end itemize
+
+For more information, visit: @url{http://www.analog.com/ice1000} and @url{http://www.analog.com/ice2000}
+
@section USB FT2232 Based
There are many USB JTAG dongles on the market, many of them based
@@ -602,6 +627,104 @@ produced, PDF schematics are easily found and it is easy to make.
@end itemize
+@node Supported Targets
+@chapter Supported Targets
+
+OpenOCD supports many targets. Below are some of them.
+
+@section Analog Devices
+
+OpenOCD supports the following targets from Analog Devices.
+
+@subsection ADuCM3027/9
+@cindex ADuCM3027
+@cindex ADuCM3029
+
+These parts are supported through @file{target/aducm3027.cfg} and
+@file{target/aducm3029.cfg}. These two parts only support SWD.
+
+@subsection ADSP-SC570/571/572/573
+@cindex ADSP-SC570
+@cindex ADSP-SC571
+@cindex ADSP-SC572
+@cindex ADSP-SC573
+
+These parts are supported through @file{target/adspsc57x.cfg}.
+This config file uses JTAG as transport by default.
+You can make it to use SWD as transport by comment out @code{transport select jtag}
+and uncomment @code{transport select swd} near the top of that config file.
+This config file do a system reset by default when GDB attaches OpenOCD.
+If you don't want to reset the target, you can edit the @code{gdb-attach}
+event handler toward the end of the config file to change @code{reset} to @code{halt}.
+
+If the part is locked, you have two ways to unlock the part:
+
+@itemize @bullet
+
+@item @b{through OpenOCD command line}
+
+@* You can use @option{-c} to set up userkey before the config file
+
+@example
+openocd -f interface/ice1000.cfg \
+ -c "set USERKEY0 0x12345678; set USERKEY1 0x9abcdef0; \
+ set USERKEY2 0x00000000; set USERKEY3 0x5f5f5f5f; list" \
+ -f target/adspsc57x.cfg
+@end example
+
+@item @b{edit the config file}
+
+@* you can uncomment these four lines in the config file:
+
+@example
+#set USERKEY0 0x00000000
+#set USERKEY1 0x00000000
+#set USERKEY2 0x00000000
+#set USERKEY3 0x00000000
+@end example
+
+and change @code{0x00000000} to the correct userkey.
+
+@end itemize
+
+@subsection ADSP-SC582/583/584/587/589
+@cindex ADSP-SC582
+@cindex ADSP-SC583
+@cindex ADSP-SC584
+@cindex ADSP-SC587
+@cindex ADSP-SC589
+
+These parts are supported through @file{target/adspsc58x.cfg}.
+The usage is as same as @file{target/adspsc57x.cfg} except that
+@file{target/adspsc58x.cfg} does not support system reset.
+
+@node Supported Boards
+@chapter Supported Boards
+
+OpenOCD supports many boards. Below are some of them.
+
+@section Analog Devices
+
+OpenOCD supports the following boards from Analog Devices.
+
+@subsection ADSP-SC573 EZ-KIT
+@cindex ADSP-SC573 EZ-KIT
+
+This board is supported throught @file{board/adspsc573_ezkit.cfg}.
+This board config file disables MMU and then initializes SDRAM when GDB connects to OpenOCD.
+
+@subsection ADSP-SC584 EZ-BRD
+@cindex ADSP-SC584 EZ-BRD
+
+This board is supported throught @file{board/adspsc584_ezbrd.cfg}.
+This board config file disables MMU and then initializes SDRAM when GDB connects to OpenOCD.
+
+@subsection ADSP-SC589 EZ-BRD
+@cindex ADSP-SC589 EZ-BRD
+
+This board is supported throught @file{board/adspsc589_ezbrd.cfg}.
+This board config file disables MMU and then initializes SDRAM when GDB connects to OpenOCD.
+
@node About Jim-Tcl
@chapter About Jim-Tcl
@cindex Jim-Tcl
@@ -2609,6 +2732,25 @@ For example adapter definitions, see the configuration files shipped in the
@file{interface/ftdi} directory.
@end deffn
+@deffn {Interface Driver} {ice1000}
+Analog Devices ICE-1000 USB emulator. It supports JTAG and SWD transports.
+@end deffn
+
+@deffn {Interface Driver} {ice2000}
+Analog Devices ICE-2000 USB emulator. It supports JTAG and SWD transports.
+It has one driver-specific command:
+
+@deffn {Config Command} {ice2000_voltage} @option{1}|@option{2}|@option{3}
+Set voltage:
+@itemize @minus
+@item @option{1}: 1.8 V
+@item @option{2}: 2.5 V
+@item @option{3}: 3.3 V
+@end itemize
+@end deffn
+
+@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
@@ -4921,6 +5063,22 @@ at91samd bootloader 16384
@end deffn
+@deffn {Flash Driver} aducm302x
+The ADuCM3027/9 microcontrollers from Analog Devices include internal
+flash and use ARM Cortex-M3 cores.
+The flash size on ADuCM3027 is 128KB.
+The flash size on ADuCM3029 is 256KB.
+The flash start address is 0 on both.
+
+@example
+# ADuCM3027
+flash bank $_FLASHNAME aducm302x 0 0x20000 0 0 $_TARGETNAME
+
+# ADuCM3029
+flash bank $_FLASHNAME aducm302x 0 0x40000 0 0 $_TARGETNAME
+@end example
+@end deffn
+
@anchor{at91sam3}
@deffn {Flash Driver} at91sam3
@cindex at91sam3
@@ -8460,11 +8618,9 @@ Cyg_Thread::thread_list, Cyg_Scheduler_Base::current_thread.
@item ThreadX symbols
_tx_thread_current_ptr, _tx_thread_created_ptr, _tx_thread_created_count.
@item FreeRTOS symbols
-@raggedright
pxCurrentTCB, pxReadyTasksLists, xDelayedTaskList1, xDelayedTaskList2,
pxDelayedTaskList, pxOverflowDelayedTaskList, xPendingReadyList,
uxCurrentNumberOfTasks, uxTopUsedPriority.
-@end raggedright
@item linux symbols
init_task.
@item ChibiOS symbols
diff --git a/expat.m4 b/expat.m4
new file mode 100644
index 0000000..62616a8
--- /dev/null
+++ b/expat.m4
@@ -0,0 +1,57 @@
+dnl Copyright (C) 2000-2002 Free Software Foundation, Inc.
+dnl This file is free software, distributed under the terms of the GNU
+dnl General Public License. As a special exception to the GNU General
+dnl Public License, this file may be distributed as part of a program
+dnl that contains a configuration script generated by Autoconf, under
+dnl the same distribution terms as the rest of that program.
+
+dnl From Bruno Haible.
+
+AC_DEFUN([AM_EXPAT_LINKFLAGS_BODY],
+[
+ dnl Prerequisites of AC_LIB_LINKFLAGS_BODY.
+ AC_REQUIRE([AC_LIB_PREPARE_PREFIX])
+ AC_REQUIRE([AC_LIB_RPATH])
+
+ dnl Search for libexpat and define LIBEXPAT, LTLIBEXPAT and INCEXPAT
+ dnl accordingly.
+ AC_LIB_LINKFLAGS_BODY([expat])
+])
+
+AC_DEFUN([AM_EXPAT_LINK],
+[
+ dnl Search for libexpat and define LIBEXPAT, LTLIBEXPAT and INCEXPAT
+ dnl accordingly.
+ AC_REQUIRE([AM_EXPAT_LINKFLAGS_BODY])
+
+ dnl Add $INCEXPAT to CPPFLAGS before performing the following checks,
+ dnl because if the user has installed libexpat and not disabled its use
+ dnl via --without-libexpat-prefix, he wants to use it. The first
+ dnl AC_TRY_LINK will then fail, the second AC_TRY_LINK will succeed.
+ am_save_CPPFLAGS="$CPPFLAGS"
+ AC_LIB_APPENDTOVAR([CPPFLAGS], [$INCEXPAT])
+
+ AC_CACHE_CHECK(for expat, am_cv_lib_expat, [
+ am_cv_lib_expat=no
+ am_save_LIBS="$LIBS"
+ LIBS="$LIBS $LIBEXPAT"
+ AC_TRY_LINK([#include <expat.h>],
+ [XML_ParserCreate(NULL);],
+ am_cv_lib_expat=yes)
+ LIBS="$am_save_LIBS"
+ ])
+
+ if test "$am_cv_lib_expat" = yes; then
+ AC_DEFINE(HAVE_LIBEXPAT, 1, [Define if you have the libexpat.])
+ AC_MSG_CHECKING([how to link with libexpat])
+ AC_MSG_RESULT([$LIBEXPAT])
+ else
+ dnl If $LIBEXPAT didn't lead to a usable library, we don't need $INCEXPAT
+ dnl either.
+ CPPFLAGS="$am_save_CPPFLAGS"
+ LIBEXPAT=
+ LTLIBEXPAT=
+ fi
+ AC_SUBST(LIBEXPAT)
+ AC_SUBST(LTLIBEXPAT)
+])
diff --git a/git-rev b/git-rev
new file mode 100644
index 0000000..e3d10b1
--- /dev/null
+++ b/git-rev
@@ -0,0 +1 @@
+-g2ab4fc6
diff --git a/guess-rev.sh b/guess-rev.sh
index 7adbe28..140e201 100755
--- a/guess-rev.sh
+++ b/guess-rev.sh
@@ -14,6 +14,13 @@ usage() {
cd "${1:-.}" || usage
+# If there is a file named as "git-rev", just use the revision
+# in that file.
+if [ -e git-rev ]; then
+ awk '{printf $0}' git-rev
+ exit
+fi
+
# Check for git and a git repo.
if head=`git rev-parse --verify --short HEAD 2>/dev/null`; then
@@ -24,7 +31,7 @@ if head=`git rev-parse --verify --short HEAD 2>/dev/null`; then
# If we are past a tagged commit (like "v2.6.30-rc5-302-g72357d5"),
# we pretty print it.
if atag="`git describe 2>/dev/null`"; then
- echo "$atag" | awk -F- '{printf("-%05d-%s", $(NF-1),$(NF))}'
+ echo "$atag" | awk -F- '{printf("-%s", $(NF))}'
# If we don't have a tag at all we print -g{commitish}.
else
diff --git a/lib-link.m4 b/lib-link.m4
new file mode 100644
index 0000000..eeb200d
--- /dev/null
+++ b/lib-link.m4
@@ -0,0 +1,551 @@
+# lib-link.m4 serial 4 (gettext-0.12)
+dnl Copyright (C) 2001-2003 Free Software Foundation, Inc.
+dnl This file is free software, distributed under the terms of the GNU
+dnl General Public License. As a special exception to the GNU General
+dnl Public License, this file may be distributed as part of a program
+dnl that contains a configuration script generated by Autoconf, under
+dnl the same distribution terms as the rest of that program.
+
+dnl From Bruno Haible.
+
+dnl AC_LIB_LINKFLAGS(name [, dependencies]) searches for libname and
+dnl the libraries corresponding to explicit and implicit dependencies.
+dnl Sets and AC_SUBSTs the LIB${NAME} and LTLIB${NAME} variables and
+dnl augments the CPPFLAGS variable.
+AC_DEFUN([AC_LIB_LINKFLAGS],
+[
+ AC_REQUIRE([AC_LIB_PREPARE_PREFIX])
+ AC_REQUIRE([AC_LIB_RPATH])
+ define([Name],[translit([$1],[./-], [___])])
+ define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-],
+ [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])])
+ AC_CACHE_CHECK([how to link with lib[]$1], [ac_cv_lib[]Name[]_libs], [
+ AC_LIB_LINKFLAGS_BODY([$1], [$2])
+ ac_cv_lib[]Name[]_libs="$LIB[]NAME"
+ ac_cv_lib[]Name[]_ltlibs="$LTLIB[]NAME"
+ ac_cv_lib[]Name[]_cppflags="$INC[]NAME"
+ ])
+ LIB[]NAME="$ac_cv_lib[]Name[]_libs"
+ LTLIB[]NAME="$ac_cv_lib[]Name[]_ltlibs"
+ INC[]NAME="$ac_cv_lib[]Name[]_cppflags"
+ AC_LIB_APPENDTOVAR([CPPFLAGS], [$INC]NAME)
+ AC_SUBST([LIB]NAME)
+ AC_SUBST([LTLIB]NAME)
+ dnl Also set HAVE_LIB[]NAME so that AC_LIB_HAVE_LINKFLAGS can reuse the
+ dnl results of this search when this library appears as a dependency.
+ HAVE_LIB[]NAME=yes
+ undefine([Name])
+ undefine([NAME])
+])
+
+dnl AC_LIB_HAVE_LINKFLAGS(name, dependencies, includes, testcode)
+dnl searches for libname and the libraries corresponding to explicit and
+dnl implicit dependencies, together with the specified include files and
+dnl the ability to compile and link the specified testcode. If found, it
+dnl sets and AC_SUBSTs HAVE_LIB${NAME}=yes and the LIB${NAME} and
+dnl LTLIB${NAME} variables and augments the CPPFLAGS variable, and
+dnl #defines HAVE_LIB${NAME} to 1. Otherwise, it sets and AC_SUBSTs
+dnl HAVE_LIB${NAME}=no and LIB${NAME} and LTLIB${NAME} to empty.
+AC_DEFUN([AC_LIB_HAVE_LINKFLAGS],
+[
+ AC_REQUIRE([AC_LIB_PREPARE_PREFIX])
+ AC_REQUIRE([AC_LIB_RPATH])
+ define([Name],[translit([$1],[./-], [___])])
+ define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-],
+ [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])])
+
+ dnl Search for lib[]Name and define LIB[]NAME, LTLIB[]NAME and INC[]NAME
+ dnl accordingly.
+ AC_LIB_LINKFLAGS_BODY([$1], [$2])
+
+ dnl Add $INC[]NAME to CPPFLAGS before performing the following checks,
+ dnl because if the user has installed lib[]Name and not disabled its use
+ dnl via --without-lib[]Name-prefix, he wants to use it.
+ ac_save_CPPFLAGS="$CPPFLAGS"
+ AC_LIB_APPENDTOVAR([CPPFLAGS], [$INC]NAME)
+
+ AC_CACHE_CHECK([for lib[]$1], [ac_cv_lib[]Name], [
+ ac_save_LIBS="$LIBS"
+ LIBS="$LIBS $LIB[]NAME"
+ AC_TRY_LINK([$3], [$4], [ac_cv_lib[]Name=yes], [ac_cv_lib[]Name=no])
+ LIBS="$ac_save_LIBS"
+ ])
+ if test "$ac_cv_lib[]Name" = yes; then
+ HAVE_LIB[]NAME=yes
+ AC_DEFINE([HAVE_LIB]NAME, 1, [Define if you have the $1 library.])
+ AC_MSG_CHECKING([how to link with lib[]$1])
+ AC_MSG_RESULT([$LIB[]NAME])
+ else
+ HAVE_LIB[]NAME=no
+ dnl If $LIB[]NAME didn't lead to a usable library, we don't need
+ dnl $INC[]NAME either.
+ CPPFLAGS="$ac_save_CPPFLAGS"
+ LIB[]NAME=
+ LTLIB[]NAME=
+ fi
+ AC_SUBST([HAVE_LIB]NAME)
+ AC_SUBST([LIB]NAME)
+ AC_SUBST([LTLIB]NAME)
+ undefine([Name])
+ undefine([NAME])
+])
+
+dnl Determine the platform dependent parameters needed to use rpath:
+dnl libext, shlibext, hardcode_libdir_flag_spec, hardcode_libdir_separator,
+dnl hardcode_direct, hardcode_minus_L.
+AC_DEFUN([AC_LIB_RPATH],
+[
+ AC_REQUIRE([AC_PROG_CC]) dnl we use $CC, $GCC, $LDFLAGS
+ AC_REQUIRE([AC_LIB_PROG_LD]) dnl we use $LD, $with_gnu_ld
+ AC_REQUIRE([AC_CANONICAL_HOST]) dnl we use $host
+ AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT]) dnl we use $ac_aux_dir
+ AC_CACHE_CHECK([for shared library run path origin], acl_cv_rpath, [
+ CC="$CC" GCC="$GCC" LDFLAGS="$LDFLAGS" LD="$LD" with_gnu_ld="$with_gnu_ld" \
+ ${CONFIG_SHELL-/bin/sh} "$ac_aux_dir/config.rpath" "$host" > conftest.sh
+ . ./conftest.sh
+ rm -f ./conftest.sh
+ acl_cv_rpath=done
+ ])
+ wl="$acl_cv_wl"
+ libext="$acl_cv_libext"
+ shlibext="$acl_cv_shlibext"
+ hardcode_libdir_flag_spec="$acl_cv_hardcode_libdir_flag_spec"
+ hardcode_libdir_separator="$acl_cv_hardcode_libdir_separator"
+ hardcode_direct="$acl_cv_hardcode_direct"
+ hardcode_minus_L="$acl_cv_hardcode_minus_L"
+ dnl Determine whether the user wants rpath handling at all.
+ AC_ARG_ENABLE(rpath,
+ [ --disable-rpath do not hardcode runtime library paths],
+ :, enable_rpath=yes)
+])
+
+dnl AC_LIB_LINKFLAGS_BODY(name [, dependencies]) searches for libname and
+dnl the libraries corresponding to explicit and implicit dependencies.
+dnl Sets the LIB${NAME}, LTLIB${NAME} and INC${NAME} variables.
+AC_DEFUN([AC_LIB_LINKFLAGS_BODY],
+[
+ define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-],
+ [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])])
+ dnl By default, look in $includedir and $libdir.
+ use_additional=yes
+ AC_LIB_WITH_FINAL_PREFIX([
+ eval additional_includedir=\"$includedir\"
+ eval additional_libdir=\"$libdir\"
+ ])
+ AC_LIB_ARG_WITH([lib$1-prefix],
+[ --with-lib$1-prefix[=DIR] search for lib$1 in DIR/include and DIR/lib
+ --without-lib$1-prefix don't search for lib$1 in includedir and libdir],
+[
+ if test "X$withval" = "Xno"; then
+ use_additional=no
+ else
+ if test "X$withval" = "X"; then
+ AC_LIB_WITH_FINAL_PREFIX([
+ eval additional_includedir=\"$includedir\"
+ eval additional_libdir=\"$libdir\"
+ ])
+ else
+ additional_includedir="$withval/include"
+ additional_libdir="$withval/lib"
+ fi
+ fi
+])
+ dnl Search the library and its dependencies in $additional_libdir and
+ dnl $LDFLAGS. Using breadth-first-seach.
+ LIB[]NAME=
+ LTLIB[]NAME=
+ INC[]NAME=
+ rpathdirs=
+ ltrpathdirs=
+ names_already_handled=
+ names_next_round='$1 $2'
+ while test -n "$names_next_round"; do
+ names_this_round="$names_next_round"
+ names_next_round=
+ for name in $names_this_round; do
+ already_handled=
+ for n in $names_already_handled; do
+ if test "$n" = "$name"; then
+ already_handled=yes
+ break
+ fi
+ done
+ if test -z "$already_handled"; then
+ names_already_handled="$names_already_handled $name"
+ dnl See if it was already located by an earlier AC_LIB_LINKFLAGS
+ dnl or AC_LIB_HAVE_LINKFLAGS call.
+ uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./-|ABCDEFGHIJKLMNOPQRSTUVWXYZ___|'`
+ eval value=\"\$HAVE_LIB$uppername\"
+ if test -n "$value"; then
+ if test "$value" = yes; then
+ eval value=\"\$LIB$uppername\"
+ test -z "$value" || LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$value"
+ eval value=\"\$LTLIB$uppername\"
+ test -z "$value" || LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$value"
+ else
+ dnl An earlier call to AC_LIB_HAVE_LINKFLAGS has determined
+ dnl that this library doesn't exist. So just drop it.
+ :
+ fi
+ else
+ dnl Search the library lib$name in $additional_libdir and $LDFLAGS
+ dnl and the already constructed $LIBNAME/$LTLIBNAME.
+ found_dir=
+ found_la=
+ found_so=
+ found_a=
+ if test $use_additional = yes; then
+ if test -n "$shlibext" && test -f "$additional_libdir/lib$name.$shlibext"; then
+ found_dir="$additional_libdir"
+ found_so="$additional_libdir/lib$name.$shlibext"
+ if test -f "$additional_libdir/lib$name.la"; then
+ found_la="$additional_libdir/lib$name.la"
+ fi
+ else
+ if test -f "$additional_libdir/lib$name.$libext"; then
+ found_dir="$additional_libdir"
+ found_a="$additional_libdir/lib$name.$libext"
+ if test -f "$additional_libdir/lib$name.la"; then
+ found_la="$additional_libdir/lib$name.la"
+ fi
+ fi
+ fi
+ fi
+ if test "X$found_dir" = "X"; then
+ for x in $LDFLAGS $LTLIB[]NAME; do
+ AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+ case "$x" in
+ -L*)
+ dir=`echo "X$x" | sed -e 's/^X-L//'`
+ if test -n "$shlibext" && test -f "$dir/lib$name.$shlibext"; then
+ found_dir="$dir"
+ found_so="$dir/lib$name.$shlibext"
+ if test -f "$dir/lib$name.la"; then
+ found_la="$dir/lib$name.la"
+ fi
+ else
+ if test -f "$dir/lib$name.$libext"; then
+ found_dir="$dir"
+ found_a="$dir/lib$name.$libext"
+ if test -f "$dir/lib$name.la"; then
+ found_la="$dir/lib$name.la"
+ fi
+ fi
+ fi
+ ;;
+ esac
+ if test "X$found_dir" != "X"; then
+ break
+ fi
+ done
+ fi
+ if test "X$found_dir" != "X"; then
+ dnl Found the library.
+ LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$found_dir -l$name"
+ if test "X$found_so" != "X"; then
+ dnl Linking with a shared library. We attempt to hardcode its
+ dnl directory into the executable's runpath, unless it's the
+ dnl standard /usr/lib.
+ if test "$enable_rpath" = no || test "X$found_dir" = "X/usr/lib"; then
+ dnl No hardcoding is needed.
+ LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so"
+ else
+ dnl Use an explicit option to hardcode DIR into the resulting
+ dnl binary.
+ dnl Potentially add DIR to ltrpathdirs.
+ dnl The ltrpathdirs will be appended to $LTLIBNAME at the end.
+ haveit=
+ for x in $ltrpathdirs; do
+ if test "X$x" = "X$found_dir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ ltrpathdirs="$ltrpathdirs $found_dir"
+ fi
+ dnl The hardcoding into $LIBNAME is system dependent.
+ if test "$hardcode_direct" = yes; then
+ dnl Using DIR/libNAME.so during linking hardcodes DIR into the
+ dnl resulting binary.
+ LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so"
+ else
+ if test -n "$hardcode_libdir_flag_spec" && test "$hardcode_minus_L" = no; then
+ dnl Use an explicit option to hardcode DIR into the resulting
+ dnl binary.
+ LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so"
+ dnl Potentially add DIR to rpathdirs.
+ dnl The rpathdirs will be appended to $LIBNAME at the end.
+ haveit=
+ for x in $rpathdirs; do
+ if test "X$x" = "X$found_dir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ rpathdirs="$rpathdirs $found_dir"
+ fi
+ else
+ dnl Rely on "-L$found_dir".
+ dnl But don't add it if it's already contained in the LDFLAGS
+ dnl or the already constructed $LIBNAME
+ haveit=
+ for x in $LDFLAGS $LIB[]NAME; do
+ AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+ if test "X$x" = "X-L$found_dir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir"
+ fi
+ if test "$hardcode_minus_L" != no; then
+ dnl FIXME: Not sure whether we should use
+ dnl "-L$found_dir -l$name" or "-L$found_dir $found_so"
+ dnl here.
+ LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so"
+ else
+ dnl We cannot use $hardcode_runpath_var and LD_RUN_PATH
+ dnl here, because this doesn't fit in flags passed to the
+ dnl compiler. So give up. No hardcoding. This affects only
+ dnl very old systems.
+ dnl FIXME: Not sure whether we should use
+ dnl "-L$found_dir -l$name" or "-L$found_dir $found_so"
+ dnl here.
+ LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name"
+ fi
+ fi
+ fi
+ fi
+ else
+ if test "X$found_a" != "X"; then
+ dnl Linking with a static library.
+ LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_a"
+ else
+ dnl We shouldn't come here, but anyway it's good to have a
+ dnl fallback.
+ LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir -l$name"
+ fi
+ fi
+ dnl Assume the include files are nearby.
+ additional_includedir=
+ case "$found_dir" in
+ */lib | */lib/)
+ basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e 's,/lib/*$,,'`
+ additional_includedir="$basedir/include"
+ ;;
+ esac
+ if test "X$additional_includedir" != "X"; then
+ dnl Potentially add $additional_includedir to $INCNAME.
+ dnl But don't add it
+ dnl 1. if it's the standard /usr/include,
+ dnl 2. if it's /usr/local/include and we are using GCC on Linux,
+ dnl 3. if it's already present in $CPPFLAGS or the already
+ dnl constructed $INCNAME,
+ dnl 4. if it doesn't exist as a directory.
+ if test "X$additional_includedir" != "X/usr/include"; then
+ haveit=
+ if test "X$additional_includedir" = "X/usr/local/include"; then
+ if test -n "$GCC"; then
+ case $host_os in
+ linux*) haveit=yes;;
+ esac
+ fi
+ fi
+ if test -z "$haveit"; then
+ for x in $CPPFLAGS $INC[]NAME; do
+ AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+ if test "X$x" = "X-I$additional_includedir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ if test -d "$additional_includedir"; then
+ dnl Really add $additional_includedir to $INCNAME.
+ INC[]NAME="${INC[]NAME}${INC[]NAME:+ }-I$additional_includedir"
+ fi
+ fi
+ fi
+ fi
+ fi
+ dnl Look for dependencies.
+ if test -n "$found_la"; then
+ dnl Read the .la file. It defines the variables
+ dnl dlname, library_names, old_library, dependency_libs, current,
+ dnl age, revision, installed, dlopen, dlpreopen, libdir.
+ save_libdir="$libdir"
+ case "$found_la" in
+ */* | *\\*) . "$found_la" ;;
+ *) . "./$found_la" ;;
+ esac
+ libdir="$save_libdir"
+ dnl We use only dependency_libs.
+ for dep in $dependency_libs; do
+ case "$dep" in
+ -L*)
+ additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'`
+ dnl Potentially add $additional_libdir to $LIBNAME and $LTLIBNAME.
+ dnl But don't add it
+ dnl 1. if it's the standard /usr/lib,
+ dnl 2. if it's /usr/local/lib and we are using GCC on Linux,
+ dnl 3. if it's already present in $LDFLAGS or the already
+ dnl constructed $LIBNAME,
+ dnl 4. if it doesn't exist as a directory.
+ if test "X$additional_libdir" != "X/usr/lib"; then
+ haveit=
+ if test "X$additional_libdir" = "X/usr/local/lib"; then
+ if test -n "$GCC"; then
+ case $host_os in
+ linux*) haveit=yes;;
+ esac
+ fi
+ fi
+ if test -z "$haveit"; then
+ haveit=
+ for x in $LDFLAGS $LIB[]NAME; do
+ AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+ if test "X$x" = "X-L$additional_libdir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ if test -d "$additional_libdir"; then
+ dnl Really add $additional_libdir to $LIBNAME.
+ LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$additional_libdir"
+ fi
+ fi
+ haveit=
+ for x in $LDFLAGS $LTLIB[]NAME; do
+ AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+ if test "X$x" = "X-L$additional_libdir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ if test -d "$additional_libdir"; then
+ dnl Really add $additional_libdir to $LTLIBNAME.
+ LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$additional_libdir"
+ fi
+ fi
+ fi
+ fi
+ ;;
+ -R*)
+ dir=`echo "X$dep" | sed -e 's/^X-R//'`
+ if test "$enable_rpath" != no; then
+ dnl Potentially add DIR to rpathdirs.
+ dnl The rpathdirs will be appended to $LIBNAME at the end.
+ haveit=
+ for x in $rpathdirs; do
+ if test "X$x" = "X$dir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ rpathdirs="$rpathdirs $dir"
+ fi
+ dnl Potentially add DIR to ltrpathdirs.
+ dnl The ltrpathdirs will be appended to $LTLIBNAME at the end.
+ haveit=
+ for x in $ltrpathdirs; do
+ if test "X$x" = "X$dir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ ltrpathdirs="$ltrpathdirs $dir"
+ fi
+ fi
+ ;;
+ -l*)
+ dnl Handle this in the next round.
+ names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'`
+ ;;
+ *.la)
+ dnl Handle this in the next round. Throw away the .la's
+ dnl directory; it is already contained in a preceding -L
+ dnl option.
+ names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'`
+ ;;
+ *)
+ dnl Most likely an immediate library name.
+ LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$dep"
+ LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$dep"
+ ;;
+ esac
+ done
+ fi
+ else
+ dnl Didn't find the library; assume it is in the system directories
+ dnl known to the linker and runtime loader. (All the system
+ dnl directories known to the linker should also be known to the
+ dnl runtime loader, otherwise the system is severely misconfigured.)
+ LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name"
+ LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-l$name"
+ fi
+ fi
+ fi
+ done
+ done
+ if test "X$rpathdirs" != "X"; then
+ if test -n "$hardcode_libdir_separator"; then
+ dnl Weird platform: only the last -rpath option counts, the user must
+ dnl pass all path elements in one option. We can arrange that for a
+ dnl single library, but not when more than one $LIBNAMEs are used.
+ alldirs=
+ for found_dir in $rpathdirs; do
+ alldirs="${alldirs}${alldirs:+$hardcode_libdir_separator}$found_dir"
+ done
+ dnl Note: hardcode_libdir_flag_spec uses $libdir and $wl.
+ acl_save_libdir="$libdir"
+ libdir="$alldirs"
+ eval flag=\"$hardcode_libdir_flag_spec\"
+ libdir="$acl_save_libdir"
+ LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag"
+ else
+ dnl The -rpath options are cumulative.
+ for found_dir in $rpathdirs; do
+ acl_save_libdir="$libdir"
+ libdir="$found_dir"
+ eval flag=\"$hardcode_libdir_flag_spec\"
+ libdir="$acl_save_libdir"
+ LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag"
+ done
+ fi
+ fi
+ if test "X$ltrpathdirs" != "X"; then
+ dnl When using libtool, the option that works for both libraries and
+ dnl executables is -R. The -R options are cumulative.
+ for found_dir in $ltrpathdirs; do
+ LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-R$found_dir"
+ done
+ fi
+])
+
+dnl AC_LIB_APPENDTOVAR(VAR, CONTENTS) appends the elements of CONTENTS to VAR,
+dnl unless already present in VAR.
+dnl Works only for CPPFLAGS, not for LIB* variables because that sometimes
+dnl contains two or three consecutive elements that belong together.
+AC_DEFUN([AC_LIB_APPENDTOVAR],
+[
+ for element in [$2]; do
+ haveit=
+ for x in $[$1]; do
+ AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+ if test "X$x" = "X$element"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ [$1]="${[$1]}${[$1]:+ }$element"
+ fi
+ done
+])
diff --git a/openocd_blackfin_config.dtd b/openocd_blackfin_config.dtd
new file mode 100644
index 0000000..0681643
--- /dev/null
+++ b/openocd_blackfin_config.dtd
@@ -0,0 +1,11 @@
+<!-- The root element of a Blackfin target config is <blackfin-config>. -->
+
+<!ELEMENT blackfin-config (processor)>
+<!ATTLIST blackfin-config version CDATA #FIXED "1.0">
+
+<!ELEMENT processor (config)>
+<!ATTLIST processor name CDATA #REQUIRED>
+
+<!ELEMENT config EMPTY>
+<!ATTLIST config name CDATA #REQUIRED
+ value CDATA #REQUIRED>
diff --git a/openocd_memory_map.dtd b/openocd_memory_map.dtd
new file mode 100644
index 0000000..239dfbc
--- /dev/null
+++ b/openocd_memory_map.dtd
@@ -0,0 +1,22 @@
+<!-- The root element of a memory map is <memory-map>. -->
+
+<!ELEMENT memory-map (processor)>
+<!ATTLIST memory-map version CDATA #FIXED "1.0">
+
+<!ELEMENT processor (core, memory)>
+<!ATTLIST processor name CDATA #REQUIRED>
+
+<!ELEMENT core (memory)>
+<!ATTLIST core name CDATA #REQUIRED
+ start CDATA #REQUIRED
+ length CDATA #REQUIRED>
+
+<!ELEMENT memory (property)>
+<!ATTLIST memory name CDATA #REQUIRED
+ start CDATA #REQUIRED
+ length CDATA #REQUIRED
+ access CDATA #REQUIRED>
+
+<!ELEMENT property (#PCDATA)>
+<!ATTLIST property name CDATA #REQUIRED>
+
diff --git a/src/Makefile.am b/src/Makefile.am
index 26e02d0..d45c579 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -30,6 +30,8 @@ if ULINK
openocd_LDADD += -lm
endif
+openocd_LDADD += $(LIBEXPAT)
+
libopenocd_la_SOURCES = \
hello.c \
openocd.c
diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am
index 878fc26..a727a21 100644
--- a/src/flash/nor/Makefile.am
+++ b/src/flash/nor/Makefile.am
@@ -9,6 +9,7 @@ libocdflashnor_la_SOURCES = \
NOR_DRIVERS = \
aduc702x.c \
+ aducm302x.c \
at91sam4.c \
at91sam4l.c \
at91samd.c \
diff --git a/src/flash/nor/aducm302x.c b/src/flash/nor/aducm302x.c
new file mode 100644
index 0000000..723ea93
--- /dev/null
+++ b/src/flash/nor/aducm302x.c
@@ -0,0 +1,593 @@
+/***************************************************************************
+ * Copyright (C) 2014, 2016 Analog Devices, 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 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+//#include "jtag/interface.h"
+#include "imp.h"
+#include <target/algorithm.h>
+#include <target/armv7m.h>
+
+
+/* ADuCM302x ID registers */
+#define SYS_ADIID 0x40002020
+#define SYS_CHIPID 0x40002024
+
+/* ADuCM302x cache flash control registers */
+#define STAT 0x40018000
+#define IEN 0x40018004
+#define CMD 0x40018008
+#define KH_ADDR 0x4001800c
+#define KH_DATA0 0x40018010
+#define KH_DATA1 0x40018014
+#define PAGE_ADDR0 0x40018018
+#define PAGE_ADDR1 0x4001801c
+#define KEY 0x40018020
+#define WR_ABORT_ADDR 0x40018024
+#define WRPROT 0x40018028
+#define SIGNATURE 0x4001802c
+#define UCFG 0x40018030
+#define TIME_PARAM0 0x40018034
+#define TIME_PARAM1 0x40018038
+#define ABORT_EN_LO 0x4001803c
+#define ABORT_EN_HI 0x40018040
+#define ECC_CFG 0x40018044
+#define ECC_ADDR 0x40018048
+
+#define USER_KEY 0x676c7565
+
+#define STAT_CMDBUSY (1 << 0)
+#define STAT_WRCLOSE (1 << 1)
+#define STAT_CMDCOMP (1 << 2)
+#define STAT_WRALCOMP (1 << 3)
+#define STAT_CMDFAIL_MASK (3 << 4)
+#define STAT_CMDFAIL_SUCCESS (0 << 4)
+#define STAT_CMDFAIL_IGNORED (1 << 4)
+#define STAT_CMDFAIL_VERIFY_ERR (2 << 4)
+#define STAT_CMDFAIL_ABORT (3 << 4)
+#define STAT_SLEEPING (1 << 6)
+#define STAT_ECCERRCMD_MASK (3 << 7)
+#define STAT_ECCERRCMD_SUCCESS (0 << 7)
+#define STAT_ECCERRCMD_ERR_2BIT (1 << 7)
+#define STAT_ECCERRCMD_ERR_1BIT (2 << 7)
+#define STAT_ECCERRCMD_ERR_1OR2 (3 << 7)
+#define STAT_ECCRDERR_MASK (3 << 9)
+#define STAT_ECCRDERR_SUCCESS (0 << 9)
+#define STAT_ECCRDERR_ERR_2BIT (1 << 9)
+#define STAT_ECCRDERR_ERR_1BIT (2 << 9)
+#define STAT_ECCRDERR_ERR_1OR2 (3 << 9)
+#define STAT_OVERLAP (1 << 11)
+#define STAT_SIGNERR (1 << 13)
+#define STAT_INIT (1 << 14)
+#define STAT_ECCINFOSIGN_MASK (2 << 15)
+#define STAT_ECCINFOSIGN_SUCCESS (0 << 15)
+#define STAT_ECCINFOSIGN_ERR_2BIT (1 << 15)
+#define STAT_ECCINFOSIGN_ERR_1BIT (2 << 15)
+#define STAT_ECCINFOSIGN_ERR_1OR2 (3 << 15)
+#define STAT_ECCERRCNT_MASK (7 << 17)
+#define STAT_ECCICODE_MASK (3 << 25)
+#define STAT_ECCICODE_SUCCESS (0 << 25)
+#define STAT_ECCICODE_ERR_2BIT (1 << 25)
+#define STAT_ECCICODE_ERR_1BIT (2 << 25)
+#define STAT_ECCDCODE_MASK (3 << 27)
+#define STAT_ECCDCODE_SUCCESS (0 << 27)
+#define STAT_ECCDCODE_ERR_2BIT (1 << 27)
+#define STAT_ECCDCODE_ERR_1BIT (2 << 27)
+#define STAT_CACHESRAMPERR (1 << 29)
+
+#define CMD_IDLE 0
+#define CMD_ABORT 1
+#define CMD_SLEEP 2
+#define CMD_SIGN 3
+#define CMD_WRITE 4
+#define CMD_CHECK 5
+#define CMD_ERASEPAGE 6
+#define CMD_MASSERASE 7
+
+struct aducm302x_flash_bank {
+ const char *target_name;
+ bool probed;
+
+ /* flash geometry */
+ uint32_t pagesize;
+};
+
+static int aducm302x_probe(struct flash_bank *bank)
+{
+ struct target *target = bank->target;
+ struct aducm302x_flash_bank *aducm302x_info = bank->driver_priv;
+ uint16_t adiid, chipid;
+ int i;
+
+ LOG_DEBUG("bank=%p", bank);
+
+ if (aducm302x_info->probed)
+ return ERROR_OK;
+
+ /* Read ID register to make sure this is an ADuCM302x */
+ target_read_u16(target, SYS_ADIID, &adiid);
+ target_read_u16(target, SYS_CHIPID, &chipid);
+ LOG_DEBUG("ADIID 0x%" PRIx16 ", CHIPID 0x%" PRIx16 "", adiid, chipid);
+
+ if (adiid != 0x4144) {
+ LOG_WARNING("not an Analog Devices implemented Cortex based part");
+ return ERROR_FLASH_OPERATION_FAILED;
+ }
+
+ if (chipid != 0x0282) {
+ LOG_WARNING("unknown part (not ADuCM3027/9)");
+ return ERROR_FLASH_OPERATION_FAILED;
+ }
+
+ /* Clear the remap bit */
+ target_write_u32(target, 0x40018054, 0x1);
+
+ aducm302x_info->pagesize = 2048;
+ bank->num_sectors = bank->size / aducm302x_info->pagesize;
+ bank->sectors = malloc(bank->num_sectors * sizeof(struct flash_sector));
+ if (bank->sectors == NULL) {
+ LOG_ERROR("malloc failed");
+ return ERROR_FAIL;
+ }
+ for (i = 0; i < bank->num_sectors; i++) {
+ bank->sectors[i].offset = i * aducm302x_info->pagesize;
+ bank->sectors[i].size = aducm302x_info->pagesize;
+ bank->sectors[i].is_erased = -1;
+ bank->sectors[i].is_protected = -1;
+ }
+
+ aducm302x_info->probed = true;
+
+ return ERROR_OK;
+}
+
+static int aducm302x_check_cmdfail(uint32_t flash_stat)
+{
+ if ((flash_stat & STAT_CMDFAIL_MASK) == STAT_CMDFAIL_SUCCESS)
+ return ERROR_OK;
+
+ if ((flash_stat & STAT_CMDFAIL_MASK) == STAT_CMDFAIL_IGNORED)
+ LOG_ERROR("command ignored for attempted access of a protected or out of memory location)");
+ else if ((flash_stat & STAT_CMDFAIL_MASK) == STAT_CMDFAIL_VERIFY_ERR)
+ LOG_ERROR("verify error occurred for failed erase or failed signature check");
+ else if ((flash_stat & STAT_CMDFAIL_MASK) == STAT_CMDFAIL_ABORT)
+ LOG_ERROR("command aborted by either user code or a system interrupt");
+
+ return ERROR_FLASH_OPERATION_FAILED;
+}
+
+static int aducm302x_mass_erase(struct flash_bank *bank)
+{
+ struct target *target = bank->target;
+ uint32_t flash_stat;
+ int retval, i;
+
+ /* Write user key */
+ target_write_u32(target, KEY, USER_KEY);
+ /* Write massive erase command */
+ target_write_u32(target, CMD, CMD_MASSERASE);
+ /* Wait until erase complete */
+ do {
+ target_read_u32(target, STAT, &flash_stat);
+ } while ((flash_stat & STAT_CMDCOMP) == 0);
+
+ retval = aducm302x_check_cmdfail(flash_stat);
+ if (retval != ERROR_OK)
+ return retval;
+
+ for (i = 0; i < bank->num_sectors; i++)
+ bank->sectors[i].is_erased = 1;
+
+ return ERROR_OK;
+}
+
+static int aducm302x_erase(struct flash_bank *bank, int first, int last)
+{
+ struct aducm302x_flash_bank *aducm302x_info = bank->driver_priv;
+ struct target *target = bank->target;
+ uint32_t flash_stat;
+ int retval, i;
+
+ LOG_DEBUG("bank=%p first=%d last = %d", bank, first, last);
+
+ if (target->state != TARGET_HALTED) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ if (!aducm302x_info->probed)
+ return ERROR_FLASH_BANK_NOT_PROBED;
+
+ if (first < 0 || last < first || last >= bank->num_sectors)
+ return ERROR_FLASH_SECTOR_INVALID;
+
+ if (first == 0 && last == bank->num_sectors - 1) {
+ retval = aducm302x_mass_erase(bank);
+ return retval;
+ }
+
+ for (i = first; i <= last; i++) {
+ /* Address is first word in page */
+ target_write_u32(target, PAGE_ADDR0, i * aducm302x_info->pagesize);
+ /* Write user key */
+ target_write_u32(target, KEY, USER_KEY);
+ /* Write page erase command */
+ target_write_u32(target, CMD, CMD_ERASEPAGE);
+ /* Wait until erase complete */
+ do {
+ target_read_u32(target, STAT, &flash_stat);
+ } while ((flash_stat & STAT_CMDCOMP) == 0);
+
+ retval = aducm302x_check_cmdfail(flash_stat);
+ if (retval != ERROR_OK)
+ return retval;
+
+ bank->sectors[i].is_erased = 1;
+ }
+
+ return ERROR_OK;
+}
+
+static int aducm302x_protect(struct flash_bank *bank, int set, int first, int last)
+{
+ struct aducm302x_flash_bank *aducm302x_info = bank->driver_priv;
+ struct target *target = bank->target;
+ uint32_t wrprot;
+ int i;
+
+ if (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");
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+
+ if (!aducm302x_info->probed)
+ return ERROR_FLASH_BANK_NOT_PROBED;
+
+ /* One protect block has 4 pages. So the first should be 0, 4, 8, ...
+ The last should be 3, 7, 11, ... */
+ if (first < 0 || (first & 0x3) || last <= first || (last & 0x3) != 0x3
+ || last >= 4 * 32) {
+ LOG_ERROR("Can't protect unaligned or out-of-range pages.");
+ return ERROR_FLASH_SECTOR_INVALID;
+ }
+
+ /* Convert from pages to protect blocks */
+ first /= 4;
+ last /= 4;
+
+ target_read_u32(target, WRPROT, &wrprot);
+
+ for (i = first; i <= last; i++)
+ wrprot &= ~(1 << i);
+
+ LOG_DEBUG("WRPROT 0x%"PRIx32, wrprot);
+
+ target_write_u32(target, WRPROT, wrprot);
+
+ return ERROR_OK;
+}
+
+static int aducm302x_protect_check(struct flash_bank *bank)
+{
+ struct aducm302x_flash_bank *aducm302x_info = bank->driver_priv;
+ struct target *target = bank->target;
+ uint32_t wrprot;
+ int i;
+
+ if (target->state != TARGET_HALTED) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ if (!aducm302x_info->probed)
+ return ERROR_FLASH_BANK_NOT_PROBED;
+
+ for (i = 0; i < bank->num_sectors; i++)
+ bank->sectors[i].is_protected = -1;
+
+ target_read_u32(target, WRPROT, &wrprot);
+
+ for (i = 0; i < 32; i++) {
+ bank->sectors[i * 4].is_protected = !(wrprot & (1 << i));
+ bank->sectors[i * 4 + 1].is_protected = !(wrprot & (1 << i));
+ bank->sectors[i * 4 + 2].is_protected = !(wrprot & (1 << i));
+ bank->sectors[i * 4 + 3].is_protected = !(wrprot & (1 << i));
+ }
+
+ return ERROR_OK;
+}
+
+/* see contrib/loaders/flash/aducm302x.s for source code */
+static const uint8_t aducm302x_write_code[] = {
+ /* write: */
+ 0xdf, 0xf8, 0x4c, 0x40,
+ 0x13, 0x4d,
+ /* wait_fifo: */
+ 0xd0, 0xf8, 0x00, 0x80,
+ 0xb8, 0xf1, 0x00, 0x0f,
+ 0x00, 0xf0, 0x1e, 0x80,
+ 0x47, 0x68,
+ 0x47, 0x45,
+ 0x3f, 0xf4, 0xf6, 0xaf,
+ /* mainloop: */
+ 0xe2, 0x60,
+ 0x02, 0xf1, 0x08, 0x02,
+ 0x57, 0xf8, 0x04, 0x6b,
+ 0x57, 0xf8, 0x04, 0x8b,
+ 0x26, 0x61,
+ 0xc4, 0xf8, 0x14, 0x80,
+ 0xa5, 0x60,
+ /* busy: */
+ 0xd4, 0xf8, 0x00, 0x80,
+ 0x18, 0xf0, 0x04, 0x0f,
+ 0x3f, 0xf4, 0xfa, 0xaf,
+ 0x8f, 0x42,
+ 0x28, 0xbf,
+ 0x00, 0xf1, 0x08, 0x07,
+ 0x47, 0x60,
+ 0x01, 0x3b,
+ 0x0b, 0xb1,
+ 0xff, 0xf7, 0xdc, 0xbf,
+ /* exit: */
+ 0x00, 0xbe,
+ /* pFLASH_CTRL_BASE: */
+ 0x00, 0x80, 0x01, 0x40,
+ /* FLASHWRITECMD: */
+ 0x04, 0x00, 0x00, 0x00
+};
+
+static int aducm302x_write_block(struct flash_bank *bank, const uint8_t *buffer,
+ uint32_t offset, uint32_t dwcount)
+{
+ struct target *target = bank->target;
+ uint32_t buffer_size = 16384 + 8; /* 8 bytes for wp and rp */
+ 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;
+
+ /* power of two, and multiple of 8 bytes */
+ static const unsigned buf_min = 128;
+
+ LOG_DEBUG("bank=%p buffer=%p offset=%08"PRIx32" dwcount=%"PRIx32,
+ bank, buffer, offset, dwcount);
+
+ /* For small buffers it's faster not to download the algorithm */
+ if (dwcount * 8 < buf_min)
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+
+ /* flash write code */
+ if (target_alloc_working_area(target, sizeof(aducm302x_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 (dwcount * 8 < buffer_size)
+ buffer_size = dwcount * 8 + 8;
+
+ /* memory buffer */
+ while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) {
+ buffer_size = (buffer_size - 8) / 2;
+ /* make sure it's multiple of 8 bytes */
+ buffer_size = buffer_size / 8 * 8;
+ if (buffer_size <= buf_min) {
+ target_free_working_area(target, write_algorithm);
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+ }
+ /* 8 bytes for wp and rp */
+ buffer_size += 8;
+ LOG_DEBUG("retry target_alloc_working_area(%s, size=%"PRIu32")",
+ target_name(target), buffer_size);
+ }
+
+ target_write_buffer(target, write_algorithm->address,
+ sizeof(aducm302x_write_code), aducm302x_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, dwcount);
+
+ retval = target_run_flash_async_algorithm(target,
+ buffer, dwcount, 8,
+ 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 ADuCM302x 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[0]);
+ destroy_reg_param(®_params[0]);
+ destroy_reg_param(®_params[0]);
+
+ return retval;
+}
+
+static int aducm302x_write(struct flash_bank *bank, const uint8_t *buffer,
+ uint32_t offset, uint32_t count)
+{
+ struct aducm302x_flash_bank *aducm302x_info = bank->driver_priv;
+ struct target *target = bank->target;
+ uint32_t address = offset;
+ uint32_t dwords_remaining, bytes_remaining;
+ uint32_t flash_stat;
+ int retval;
+
+ LOG_DEBUG("bank=%p buffer=%p offset=%08"PRIx32" count=%"PRIx32,
+ bank, buffer, offset, count);
+
+ if (bank->target->state != TARGET_HALTED) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ if (!aducm302x_info->probed)
+ return ERROR_FLASH_BANK_NOT_PROBED;
+
+ if (offset & 0x7) {
+ uint8_t first_dword[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+ /* read the bytes from target into the write buffer */
+ target_read_buffer(target, offset & (~ 0x7), offset & 0x7, first_dword);
+
+ bytes_remaining = 8 - (offset & 0x7);
+ if (bytes_remaining > count)
+ bytes_remaining = count;
+ memcpy(first_dword + (offset & 0x7), buffer, bytes_remaining);
+
+ /* write one double word */
+ target_write_u32(target, KH_ADDR, address & (~ 0x7));
+ target_write_buffer(target, KH_DATA0, 4, first_dword);
+ target_write_buffer(target, KH_DATA1, 4, first_dword + 4);
+ target_write_u32(target, CMD, CMD_WRITE);
+
+ do {
+ target_read_u32(target, STAT, &flash_stat);
+ } while ((flash_stat & STAT_CMDCOMP) == 0);
+
+ retval = aducm302x_check_cmdfail(flash_stat);
+ if (retval != ERROR_OK)
+ return retval;
+
+ count -= bytes_remaining;
+ address &= ~ 0x7;
+ }
+
+ dwords_remaining = count / 8;
+ bytes_remaining = count % 8;
+
+ if (dwords_remaining > 0) {
+ retval = aducm302x_write_block(bank, buffer, offset, dwords_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) {
+ LOG_ERROR("flash writing failed");
+ return ERROR_FLASH_OPERATION_FAILED;
+ }
+ } else {
+ buffer += dwords_remaining * 8;
+ address += dwords_remaining * 8;
+ dwords_remaining = 0;
+ }
+ }
+
+ while (dwords_remaining > 0) {
+ target_write_u32(target, KH_ADDR, address);
+ target_write_buffer(target, KH_DATA0, 4, buffer);
+ target_write_buffer(target, KH_DATA1, 4, buffer + 4);
+ target_write_u32(target, CMD, CMD_WRITE);
+
+ do {
+ target_read_u32(target, STAT, &flash_stat);
+ } while ((flash_stat & STAT_CMDCOMP) == 0);
+
+ retval = aducm302x_check_cmdfail(flash_stat);
+ if (retval != ERROR_OK)
+ return retval;
+
+ buffer += 8;
+ address += 8;
+ dwords_remaining--;
+ }
+
+ 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_remaining);
+
+ /* write one double word */
+ target_write_u32(target, KH_ADDR, address);
+ target_write_buffer(target, KH_DATA0, 4, last_dword);
+ target_write_buffer(target, KH_DATA1, 4, last_dword + 4);
+ target_write_u32(target, CMD, CMD_WRITE);
+
+ do {
+ target_read_u32(target, STAT, &flash_stat);
+ } while ((flash_stat & STAT_CMDCOMP) == 0);
+
+ retval = aducm302x_check_cmdfail(flash_stat);
+ if (retval != ERROR_OK)
+ return retval;
+ }
+
+ return ERROR_OK;
+}
+
+FLASH_BANK_COMMAND_HANDLER(aducm302x_flash_bank_command)
+{
+ struct aducm302x_flash_bank *aducm302x_info;
+
+ if (CMD_ARGC < 6)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ aducm302x_info = calloc(sizeof(struct aducm302x_flash_bank), 1);
+ bank->base = 0x0;
+ bank->driver_priv = aducm302x_info;
+
+ aducm302x_info->target_name = "ADuCM302x";
+
+ /* part wasn't probed for info yet */
+ aducm302x_info->probed = false;
+
+ return ERROR_OK;
+}
+
+struct flash_driver aducm302x_flash = {
+ .name = "aducm302x",
+ .usage = NULL,
+ .commands = NULL,
+ .flash_bank_command = aducm302x_flash_bank_command,
+ .erase = aducm302x_erase,
+ .protect = aducm302x_protect,
+ .write = aducm302x_write,
+ .read = default_flash_read,
+ .probe = aducm302x_probe,
+ .erase_check = default_flash_blank_check,
+ .protect_check = aducm302x_protect_check,
+ .info = NULL,
+ .auto_probe = aducm302x_probe,
+};
diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c
index fead797..b267482 100644
--- a/src/flash/nor/drivers.c
+++ b/src/flash/nor/drivers.c
@@ -59,6 +59,7 @@ extern struct flash_driver nrf51_flash;
extern struct flash_driver mrvlqspi_flash;
extern struct flash_driver psoc4_flash;
extern struct flash_driver sim3x_flash;
+extern struct flash_driver aducm302x_flash;
/**
* The list of built-in flash drivers.
@@ -102,6 +103,7 @@ static struct flash_driver *flash_drivers[] = {
&mrvlqspi_flash,
&psoc4_flash,
&sim3x_flash,
+ &aducm302x_flash,
NULL,
};
diff --git a/src/flash/nor/lpcspifi.c b/src/flash/nor/lpcspifi.c
index 3b383eb..402f5f5 100644
--- a/src/flash/nor/lpcspifi.c
+++ b/src/flash/nor/lpcspifi.c
@@ -195,7 +195,7 @@ static int lpcspifi_set_hw_mode(struct flash_bank *bank)
+ SPIFI_INIT_STACK_SIZE, &spifi_init_algorithm);
if (retval != ERROR_OK) {
LOG_ERROR("Insufficient working area to initialize SPIFI "\
- "module. You must allocate at least %zdB of working "\
+ "module. You must allocate at least %"PRIzd"B of working "\
"area in order to use this driver.",
sizeof(spifi_init_code) + SPIFI_INIT_STACK_SIZE
);
@@ -537,7 +537,7 @@ static int lpcspifi_erase(struct flash_bank *bank, int first, int last)
&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.",
+ " area of at least %"PRIzd"B in order to erase SPIFI flash.",
sizeof(lpcspifi_flash_erase_code));
return retval;
}
@@ -695,7 +695,7 @@ static int lpcspifi_write(struct flash_bank *bank, const uint8_t *buffer,
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.",
+ " a working area > %"PRIzd"B in order to write to SPIFI flash.",
sizeof(lpcspifi_flash_write_code));
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
};
@@ -717,14 +717,14 @@ static int lpcspifi_write(struct flash_bank *bank, const uint8_t *buffer,
target_free_working_area(target, write_algorithm);
LOG_ERROR("Insufficient working area. Please allocate at least"\
- " %zdB of working area to enable flash writes.",
+ " %"PRIzd"B 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"\
+ " slow. Increase working area size to at least %"PRIzd"B"\
" to reduce write times.",
(size_t)(sizeof(lpcspifi_flash_write_code) + page_size)
);
diff --git a/src/flash/nor/mrvlqspi.c b/src/flash/nor/mrvlqspi.c
index 0dfe6f8..e135528 100644
--- a/src/flash/nor/mrvlqspi.c
+++ b/src/flash/nor/mrvlqspi.c
@@ -677,7 +677,7 @@ static int mrvlqspi_flash_write(struct flash_bank *bank, const uint8_t *buffer,
if (target_alloc_working_area(target, sizeof(mrvlqspi_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.",
+ " a working area > %"PRIz"dB in order to write to SPIFI flash.",
sizeof(mrvlqspi_flash_write_code));
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
};
@@ -699,14 +699,14 @@ static int mrvlqspi_flash_write(struct flash_bank *bank, const uint8_t *buffer,
target_free_working_area(target, write_algorithm);
LOG_ERROR("Insufficient working area. Please allocate at least"\
- " %zdB of working area to enable flash writes.",
+ " %"PRIz"dB of working area to enable flash writes.",
sizeof(mrvlqspi_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"\
+ " slow. Increase working area size to at least %"PRIz"dB"\
" to reduce write times.",
(size_t)(sizeof(mrvlqspi_flash_write_code) + page_size)
);
diff --git a/src/helper/command.h b/src/helper/command.h
index 0eda5b5..74bbd45 100644
--- a/src/helper/command.h
+++ b/src/helper/command.h
@@ -26,14 +26,7 @@
#include <jim-nvp.h>
-/* 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,
diff --git a/src/helper/configuration.c b/src/helper/configuration.c
index dde1491..50be4e0 100644
--- a/src/helper/configuration.c
+++ b/src/helper/configuration.c
@@ -33,6 +33,8 @@ static char **config_file_names;
static size_t num_script_dirs;
static char **script_search_dirs;
+static char* firmware_file_name;
+
void add_script_search_dir(const char *dir)
{
num_script_dirs++;
@@ -170,3 +172,17 @@ char *get_home_dir(const char *append_path)
return home_path;
}
+
+int set_firmware_filename(const char *filename)
+{
+ firmware_file_name = strdup(filename);
+ if (firmware_file_name)
+ return ERROR_OK;
+ else
+ return ERROR_FAIL;
+}
+
+char *get_firmware_filename(void)
+{
+ return firmware_file_name;
+}
diff --git a/src/helper/configuration.h b/src/helper/configuration.h
index 7b9f711..7cdc317 100644
--- a/src/helper/configuration.h
+++ b/src/helper/configuration.h
@@ -42,4 +42,7 @@ 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);
+int set_firmware_filename(const char *name);
+char *get_firmware_filename(void);
+
#endif /* CONFIGURATION_H */
diff --git a/src/helper/log.c b/src/helper/log.c
index c15b95d..414411b 100644
--- a/src/helper/log.c
+++ b/src/helper/log.c
@@ -412,12 +412,12 @@ void keep_alive()
if (gdb_actual_connections)
LOG_WARNING("keep_alive() was not invoked in the "
"1000ms timelimit. GDB alive packet not "
- "sent! (%lld). Workaround: increase "
+ "sent! (%"PRIlld"). 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 "
+ "1000ms timelimit (%"PRIlld"). This may cause "
"trouble with GDB connections.",
current_time-last_time);
}
diff --git a/src/helper/log.h b/src/helper/log.h
index 7f9f32c..e0b46a6 100644
--- a/src/helper/log.h
+++ b/src/helper/log.h
@@ -29,13 +29,22 @@
#include <helper/command.h>
-/* 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
+#ifdef IS_MINGW
+ #define PRIzu "Iu"
+ #define PRIzd "Id"
+ #define PRIzx "Ix"
+ #define PRIju "I64u"
+ #define PRIjd "I64d"
+ #define PRIllu "I64u"
+ #define PRIlld "I64d"
#else
-#define PRINTF_ATTRIBUTE_FORMAT printf
+ #define PRIzu "zu"
+ #define PRIzd "zd"
+ #define PRIzx "zx"
+ #define PRIju "ju"
+ #define PRIjd "jd"
+ #define PRIllu "llu"
+ #define PRIlld "lld"
#endif
/* logging priorities
diff --git a/src/helper/replacements.h b/src/helper/replacements.h
index 2776602..6d43425 100644
--- a/src/helper/replacements.h
+++ b/src/helper/replacements.h
@@ -132,6 +132,14 @@ static inline unsigned usleep(unsigned int usecs)
#endif
#endif /* HAVE_USLEEP */
+#ifndef HAVE_NANOSLEEP
+#include <unistd.h>
+#ifndef HAVE_STRUCT_TIMESPEC
+struct timespec { unsigned long tv_sec, tv_nsec; };
+#endif
+#define nanosleep(req, rem) usleep((req)->tv_sec * 1000 * 1000 + (req)->tv_nsec / 1000)
+#endif
+
/* Windows specific */
#ifdef _WIN32
diff --git a/src/helper/types.h b/src/helper/types.h
index 3f0724c..daee0ae 100644
--- a/src/helper/types.h
+++ b/src/helper/types.h
@@ -289,6 +289,12 @@ static inline int parity_u32(uint32_t x)
#endif
}
+#ifdef _WIN32
+#define PRIz "I"
+#else
+#define PRIz "z"
+#endif
+
#if defined(__ECOS)
/* eCos plain lacks these definition... A series of upstream patches
diff --git a/src/jtag/adapter.c b/src/jtag/adapter.c
index 2f5f6b4..5d626aa 100644
--- a/src/jtag/adapter.c
+++ b/src/jtag/adapter.c
@@ -49,6 +49,7 @@
extern struct jtag_interface *jtag_interface;
const char * const jtag_only[] = { "jtag", NULL };
+const char * const jtag_and_swd[] = { "jtag", "swd", NULL };
static int jim_adapter_name(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
{
diff --git a/src/jtag/core.c b/src/jtag/core.c
index 74c2731..a3b84e0 100644
--- a/src/jtag/core.c
+++ b/src/jtag/core.c
@@ -132,6 +132,11 @@ static struct jtag_interface *jtag;
/* configuration */
struct jtag_interface *jtag_interface;
+const char *jtag_get_name(void)
+{
+ return jtag == NULL ? NULL : jtag->name;
+}
+
void jtag_set_flush_queue_sleep(int ms)
{
jtag_flush_queue_sleep = ms;
@@ -1392,7 +1397,6 @@ int jtag_init_inner(struct command_context *cmd_ctx)
{
struct jtag_tap *tap;
int retval;
- bool issue_setup = true;
LOG_DEBUG("Init JTAG chain");
@@ -1425,24 +1429,8 @@ int jtag_init_inner(struct command_context *cmd_ctx)
* 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;
- }
+ if (retval != ERROR_OK)
+ return retval;
/* Now look at IR values. Problems here will prevent real
* communication. They mostly mean that the IR length is
@@ -1451,19 +1439,10 @@ int jtag_init_inner(struct command_context *cmd_ctx)
* 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");
+ if (retval != ERROR_OK)
+ return retval;
+ jtag_notify_event(JTAG_TAP_EVENT_SETUP);
return ERROR_OK;
}
diff --git a/src/jtag/drivers/Makefile.am b/src/jtag/drivers/Makefile.am
index aea2b38..d18197d 100644
--- a/src/jtag/drivers/Makefile.am
+++ b/src/jtag/drivers/Makefile.am
@@ -126,6 +126,13 @@ endif
if OPENJTAG
DRIVERFILES += openjtag.c
endif
+if ICE_1000
+DRIVERFILES += ice1000.c
+else
+if ICE_2000
+DRIVERFILES += ice1000.c
+endif
+endif
if CMSIS_DAP
DRIVERFILES += cmsis_dap_usb.c
diff --git a/src/jtag/drivers/ft2232.c b/src/jtag/drivers/ft2232.c
index 6f8a0fc..ab6c961 100644
--- a/src/jtag/drivers/ft2232.c
+++ b/src/jtag/drivers/ft2232.c
@@ -83,6 +83,7 @@
#include <jtag/interface.h>
#include <transport/transport.h>
#include <helper/time_support.h>
+#include "ft2232.h"
#if IS_CYGWIN == 1
#include <windows.h>
@@ -195,6 +196,7 @@ static int lisa_l_init(void);
static int flossjtag_init(void);
static int xds100v2_init(void);
static int digilent_hs1_init(void);
+static int gnice_init(void);
/* reset procedures for supported layouts */
static void ftx23_reset(int trst, int srst);
@@ -214,6 +216,7 @@ 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);
+static void gnice_reset(int trst, int srst);
/* blink procedures for layouts that support a blinking led */
static void olimex_jtag_blink(void);
@@ -224,6 +227,7 @@ static void signalyzer_h_blink(void);
static void ktlink_blink(void);
static void lisa_l_blink(void);
static void flossjtag_blink(void);
+static void gnice_blink(void);
/* common transport support options */
@@ -345,6 +349,11 @@ static const struct ft2232_layout ft2232_layouts[] = {
.reset = digilent_hs1_reset,
.channel = INTERFACE_A,
},
+ { .name = "gnice",
+ .init = gnice_init,
+ .reset = gnice_reset,
+ .blink = gnice_blink,
+ },
{ .name = NULL, /* END OF TABLE */ },
};
@@ -596,7 +605,7 @@ static int ft2232_read(uint8_t *buf, uint32_t size, uint32_t *bytes_read)
return ERROR_OK;
}
-static bool ft2232_device_is_highspeed(void)
+bool ft2232_device_is_highspeed()
{
#if BUILD_FT2232_FTD2XX == 1
return (ftdi_device == FT_DEVICE_2232H) || (ftdi_device == FT_DEVICE_4232H)
@@ -4248,6 +4257,57 @@ static void digilent_hs1_reset(int trst, int srst)
/* Dummy function, no reset signals supported. */
}
+/********************************************************************
+ * Support for gnICE
+ *******************************************************************/
+
+static int gnice_init(void)
+{
+ nTRST = 0x2;
+
+ low_output = 0x8; /* TMS */
+ low_direction = 0xb; /* TCK | TDI | TMS */
+
+ if (ft2232_set_data_bits_low_byte(low_output,low_direction) != ERROR_OK) {
+ LOG_ERROR("couldn't initialize FT2232 with 'gnICE' layout");
+ return ERROR_JTAG_INIT_FAILED;
+ }
+
+ high_output = 0x2; /* nTRST */
+ high_direction = 0xa; /* nTRST | nLED */
+
+ if (ft2232_set_data_bits_high_byte(high_output,high_direction) != ERROR_OK)
+ {
+ LOG_ERROR("couldn't initialize FT2232 with 'gnICE' layout");
+ return ERROR_JTAG_INIT_FAILED;
+ }
+
+ return ERROR_OK;
+}
+
+static void gnice_reset(int trst, int srst)
+{
+ if (trst == 1)
+ high_output &= ~nTRST;
+ else if (trst == 0)
+ high_output |= nTRST;
+
+ buffer_write(0x82);
+ buffer_write(high_output);
+ buffer_write(high_direction);
+ LOG_DEBUG("trst: %i, high_output: 0x%2.2x, high_direction: 0x%2.2x", trst, high_output, high_direction);
+}
+
+static void gnice_blink(void)
+{
+ /* LED connected to ACBUS3 */
+ high_output ^= 0x08;
+
+ buffer_write(0x82); // command "set data bits high byte"
+ buffer_write(high_output);
+ buffer_write(high_direction);
+}
+
static const struct command_registration ft2232_command_handlers[] = {
{
.name = "ft2232_device_desc",
diff --git a/src/jtag/drivers/ft2232.h b/src/jtag/drivers/ft2232.h
new file mode 100644
index 0000000..951213c
--- /dev/null
+++ b/src/jtag/drivers/ft2232.h
@@ -0,0 +1 @@
+extern bool ft2232_device_is_highspeed(void);
diff --git a/src/jtag/drivers/ftdi.c b/src/jtag/drivers/ftdi.c
index 14c5908..1a94a6c 100644
--- a/src/jtag/drivers/ftdi.c
+++ b/src/jtag/drivers/ftdi.c
@@ -598,18 +598,18 @@ static void ftdi_execute_command(struct jtag_command *cmd)
static int ftdi_execute_queue(void)
{
/* blink, if the current layout has that feature */
+ static int on = 0;
struct signal *led = find_signal_by_name("LED");
- if (led)
- ftdi_set_signal(led, '1');
+ if (led) {
+ ftdi_set_signal(led, on ? '1' : '0');
+ on ^= 1;
+ }
for (struct jtag_command *cmd = jtag_command_queue; cmd; cmd = cmd->next) {
/* fill the write buffer with the desired command */
ftdi_execute_command(cmd);
}
- if (led)
- ftdi_set_signal(led, '0');
-
int retval = mpsse_flush(mpsse_ctx);
if (retval != ERROR_OK)
LOG_ERROR("error while flushing MPSSE queue: %d", retval);
@@ -660,6 +660,11 @@ static int ftdi_initialize(void)
static int ftdi_quit(void)
{
+ struct signal *led = find_signal_by_name("LED");
+ if (led)
+ ftdi_set_signal(led, '0');
+
+ mpsse_flush(mpsse_ctx);
mpsse_close(mpsse_ctx);
free(swd_cmd_queue);
@@ -943,7 +948,7 @@ static void ftdi_swd_swdio_en(bool enable)
*/
static int ftdi_swd_run_queue(struct adiv5_dap *dap)
{
- LOG_DEBUG("Executing %zu queued transactions", swd_cmd_queue_length);
+ LOG_DEBUG("Executing %"PRIz"u queued transactions", swd_cmd_queue_length);
int retval;
struct signal *led = find_signal_by_name("LED");
@@ -1019,7 +1024,7 @@ static void ftdi_swd_queue_cmd(struct adiv5_dap *dap, uint8_t cmd, uint32_t *dst
if (q != NULL) {
swd_cmd_queue = q;
swd_cmd_queue_alloced *= 2;
- LOG_DEBUG("Increased SWD command queue to %zu elements", swd_cmd_queue_alloced);
+ LOG_DEBUG("Increased SWD command queue to %"PRIz"u elements", swd_cmd_queue_alloced);
}
}
diff --git a/src/jtag/drivers/ice1000.c b/src/jtag/drivers/ice1000.c
new file mode 100644
index 0000000..b122edc
--- /dev/null
+++ b/src/jtag/drivers/ice1000.c
@@ -0,0 +1,2304 @@
+/***************************************************************************
+* Copyright (C) 2011 by Analog Devices, Inc. *
+* Based on ice100.c of UrJTAG *
+* Jie Zhang <***@analog.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 <jtag/interface.h>
+#include <jtag/swd.h>
+#include <target/image.h>
+#include <helper/log.h>
+#include <helper/configuration.h>
+#include "libusb1_common.h"
+
+/*
+ * Internal Structures
+ */
+
+/* JTAG TMS/TDI Data */
+typedef struct
+{
+ uint8_t tms; /* TMS data */
+ uint8_t tdi; /* TDI data */
+} tap_pairs;
+
+/* swd_packet can be used to describe a read packet, a write packet,
+ an acknowledge response or a data phase. */
+struct swd_packet
+{
+ /* IN or OUT */
+ bool is_out;
+ /* bit position of ACK */
+ int ack_pos;
+ /* bit position of data */
+ int data_pos;
+ /* bit position of parity if it's an IN */
+ int parity_pos;
+ /* buffer for the data OUT */
+ const uint8_t *out;
+ /* buffer for the data IN */
+ void *in;
+ /* data length in bits */
+ uint32_t length;
+};
+
+/* For collecting data */
+typedef struct
+{
+ int32_t idx; /* Index where data is to be collected */
+ int32_t pos; /* Bit position where data is to be collected */
+ void *ptr; /* This can point to a scan_command or swd_packet */
+} dat_dat;
+
+/* Master scan control structure */
+typedef struct
+{
+ int32_t total; /* Max number of tap pointers */
+ int32_t cur_idx; /* Where to add next, or total */
+ int32_t bit_pos; /* Position to place next bit */
+ int32_t num_dat; /* Total posible data collection points */
+ int32_t cur_dat; /* Index to dat array for data to be collected */
+ int32_t rcv_dat; /* Index to retreive collected data */
+ dat_dat *dat; /* Pointer to data collection points */
+ unsigned char *cmd; /* Pointer to command, which encompasses pairs */
+ tap_pairs *pairs; /* Pointer to tap pairs array */
+} num_tap_pairs;
+
+/* Cable params_t structure with our data */
+typedef struct
+{
+ libusb_device_handle *usb_handle; /* USB handle */
+ uint32_t cur_freq; /* JTAG Frequency */
+ uint32_t cur_voltage; /* Voltage 1: 1.8V, 2: 2.5V, 3: 3.3/5V, ICE-2000 only */
+ uint32_t cur_delay; /* Delay, ICE-2000 only */
+ uint16_t version; /* Firmware Version */
+ uint32_t default_scanlen; /* #Scan pairs in scan */
+ uint32_t trigger_scanlen; /* High water mark */
+ uint32_t tap_pair_start_idx; /* depends on firmware version */
+ uint32_t num_rcv_hdr_bytes; /* Number of data bytes in received raw scan data header */
+ uint32_t max_raw_data_tx_items; /* depends on firmware version */
+ int32_t wr_ep; /* USB End Write Point */
+ int32_t wr_timeout; /* USB Write Timeout */
+ int32_t wr_buf_sz; /* USB Write Buffer Size */
+ int32_t r_ep; /* USB End Read Point */
+ int32_t r_timeout; /* USB Read Timeout */
+ int32_t r_buf_sz; /* USB Read Buffer Size */
+ num_tap_pairs tap_info; /* For collecting and sending tap scans */
+} params_t;
+
+/* Emulators's USB Data structure */
+typedef struct
+{
+ uint32_t command; /* What to do */
+ uint32_t buffer; /* used for Kit only, always initialized to 0 */
+ uint32_t count; /* Amount of data in bytes to send */
+} usb_command_block;
+
+
+/*
+ * Internal Prototypes
+ */
+
+static int perform_scan(uint8_t **rdata);
+static int do_rawscan(uint8_t firstpkt, uint8_t lastpkt,
+ int32_t collect_dof, int32_t dif_cnt, uint8_t *raw_buf,
+ uint8_t *out);
+static int add_scan_data(int32_t, uint8_t *, bool, struct scan_command *);
+static uint8_t *get_recv_data(int32_t, int32_t, uint8_t *);
+static uint16_t do_host_cmd(uint8_t cmd, uint8_t param, int32_t r_data);
+static uint32_t do_single_reg_value(uint8_t reg, int32_t r_data,
+ int32_t wr_data, uint32_t data);
+
+static int ice1000_swd_switch_seq(struct adiv5_dap *dap, enum swd_special_seq seq);
+static int ice1000_swd_run_queue(struct adiv5_dap *dap);
+
+/*
+ * Debug Macros
+ */
+
+#if 0 /* set to 1 to output debug info about scans */
+
+//#define DSP_SCAN_DATA
+#define DUMP_EACH_RCV_DATA
+//#define DSP_SCAN_CAUSE
+#define DEBUG(...) printf(__VA_ARGS__)
+
+#else
+
+#define DEBUG(...)
+
+#endif
+
+
+/*
+ * Internal Data, defines and Macros
+ */
+#define ICE_DEFAULT_SCAN_LEN 0x7FF0 /* Max DIF is 0x2AAA8, but DMA is only 16 bits. */
+#define ICE_TRIGGER_SCAN_LEN 0x7FD8 /* Start checking for RTI/TLR for xmit */
+
+#define SELECTIVE_RAW_SCAN_HDR_SZ 12
+
+#define DAT_SZ 0x8000 /* size allocated for reading data */
+#define DAT_SZ_INC 0x40 /* size to increase if data full */
+
+/* USB Emulator Commands */
+#define HOST_GET_FW_VERSION 0x01 /* get the firmware version */
+#define HOST_REQUEST_RX_DATA 0x02 /* host request to transmit data */
+#define HOST_REQUEST_TX_DATA 0x04 /* host request to transmit data */
+#define HOST_GET_SINGLE_REG 0x08 /* set a JTAG register */
+#define HOST_SET_SINGLE_REG 0x09 /* set a JTAG register */
+#define HOST_PROGRAM_FLASH 0x0C /* program flash */
+#define HOST_HARD_RESET_JTAG_CTRLR 0x0E /* do a hard reset on JTAG controller */
+#define HOST_SET_TRST 0x1F /* changes TRST Line state */
+#define HOST_GET_TRST 0x20 /* gets TRST Line state */
+#define HOST_DO_SELECTIVE_RAW_SCAN 0x21 /* Return only data needed */
+#define HOST_SET_2000_VOLTAGE 0x24
+#define HOST_SET_INTERFACE_MODE 0x25
+#define HOST_DISCONNECT 0x27
+
+/* Registers */
+#define REG_AUX 0x00
+#define REG_SCR 0x04
+#define REG_FREQ 0x40
+
+#define SCR_DEFAULT 0x30A0461
+#define SCR_TRST_BIT 0x0000040
+
+/* Ice USB controls */
+#define ICE_1000_WRITE_ENDPOINT 0x06
+#define ICE_1000_READ_ENDPOINT 0x05
+#define ICE_1000_USB_WRITE_TIMEOUT 10000
+#define ICE_1000_USB_READ_TIMEOUT 30000
+#define ICE_1000_WRITE_BUFFER_SIZE 0x9800
+#define ICE_1000_READ_BUFFER_SIZE 0x8000
+
+
+/* frequency settings for ICE-1000 */
+#define MAX_FREQ_1000 3
+static const uint8_t freq_set_1000[MAX_FREQ_1000] = { 45, 22, 8 };
+static const uint32_t avail_freqs_1000[MAX_FREQ_1000] = { 1000000, 2000000, 5000000 };
+/* frequency settings for ICE-2000 */
+#define MAX_FREQ_2000 7
+static const uint8_t freq_set_2000[MAX_FREQ_2000] = { 45, 22, 8, 4, 2, 1, 0 };
+static const uint32_t avail_freqs_2000[MAX_FREQ_2000] = { 1000000, 2000000, 5000000, 9000000, 15000000, 23000000, 46000000 };
+
+/*
+ * Internal Macros
+ */
+
+#define adi_usb_read_or_ret(buf, len) \
+ do { \
+ int __ret, __actual, __size = (len); \
+ __ret = libusb_bulk_transfer(cable_params.usb_handle, \
+ cable_params.r_ep | LIBUSB_ENDPOINT_IN, \
+ (unsigned char *)(buf), __size, \
+ &__actual, cable_params.r_timeout); \
+ if (__ret || __actual != __size) \
+ { \
+ LOG_ERROR("unable to read from usb to " #buf ": " \
+ "wanted %i bytes but only received %i bytes", \
+ __size, __actual); \
+ return ERROR_FAIL; \
+ } \
+ } while (0)
+
+#define adi_usb_write_or_ret(buf, len) \
+ do { \
+ int __ret, __actual, __size = (len); \
+ __ret = libusb_bulk_transfer(cable_params.usb_handle, \
+ cable_params.wr_ep | LIBUSB_ENDPOINT_OUT, \
+ (unsigned char *)(buf), __size, \
+ &__actual, cable_params.wr_timeout); \
+ if (__ret || __actual != __size) \
+ { \
+ LOG_ERROR("unable to write from " #buf " to usb: " \
+ "wanted %i bytes but only wrote %i bytes", \
+ __size, __actual); \
+ return ERROR_FAIL; \
+ } \
+ } while (0)
+
+
+static params_t cable_params;
+
+static bool swd_mode;
+
+/*
+ * System Interface Functions
+ */
+
+extern struct jtag_interface *jtag_interface;
+static const char *adi_cable_name(void)
+{
+ if (jtag_interface == NULL)
+ return "";
+
+ if (strcmp(jtag_interface->name, "ice1000") == 0)
+ return "ICE-1000";
+ else if (strcmp(jtag_interface->name, "ice2000") == 0)
+ return "ICE-2000";
+ else
+ return "unknown";
+}
+
+/*
+ * Gets available Frequency index.
+ */
+static int adi_get_freq(uint32_t freq, int arr_sz, const uint32_t *freq_arr)
+{
+ int i;
+
+ /* Verify Frequency is valid */
+ for (i = 0; i < arr_sz; i++)
+ {
+ if (freq == freq_arr[i])
+ {
+ /* spot on */
+ break;
+ }
+ else if (freq < freq_arr[i])
+ {
+ /* an in between frequency */
+ if (i > 0)
+ i--;
+ break;
+ }
+ }
+
+ if (i == arr_sz)
+ {
+ /* must of entered something above the max! */
+ i--;
+ }
+
+ return i;
+}
+
+/*
+ * Sets ICE-1000 Frequency
+ */
+static void ice1000_set_freq(uint32_t freq)
+{
+ params_t *params = &cable_params;
+
+ /* Verify Frequency is valid */
+ if (freq != params->cur_freq)
+ {
+ /* only change if different from current settings */
+ int idx = adi_get_freq(freq, MAX_FREQ_1000, &avail_freqs_1000[0]);
+
+ if (avail_freqs_1000[idx] != params->cur_freq)
+ {
+ /* only change if different from current settings
+ * this call's frequency may have been not one of
+ * the defined settings, but ends up there */
+ params->cur_freq = freq;
+ do_single_reg_value(REG_FREQ, 1, 1, freq_set_1000[idx]);
+ }
+ }
+}
+
+static int ice2000_validate_ircapture(int test_data_length, int total_ir_length,
+ const uint8_t *ir_test_in, uint8_t *ir_test_out)
+{
+ int retval, i;
+
+ if (test_data_length % 64)
+ return ERROR_FAIL;
+
+ jtag_add_plain_ir_scan(test_data_length + total_ir_length,
+ ir_test_in, ir_test_out, TAP_IDLE);
+
+ LOG_DEBUG("IR capture validation scan");
+ retval = jtag_execute_queue();
+ if (retval != ERROR_OK)
+ return retval;
+
+ for (i = 0; i < test_data_length / 64; i++)
+ {
+ uint64_t val_in, val_out;
+ val_in = buf_get_u64(ir_test_in, i * 64, 64);
+ val_out = buf_get_u64(ir_test_out, total_ir_length + i * 64, 64);
+ if (val_in != val_out)
+ return ERROR_FAIL;
+ }
+
+ return ERROR_OK;
+}
+
+static void ice2000_set_voltage_freq_delay(uint32_t voltage, uint32_t freq, uint32_t delay)
+{
+ uint32_t value = freq | (delay << 8) | (voltage << 16);
+
+ do_single_reg_value(REG_FREQ, 1, 1, value);
+}
+
+/* TEST_DATA_LENGTH % 64 should be 0 */
+#define TEST_DATA_LENGTH 0x8000
+
+static int ice2000_find_delay(uint32_t voltage, uint32_t freq)
+{
+ struct jtag_tap *tap;
+ int total_ir_length, test_data_length, ir_test_length;
+ uint8_t *ir_test_in, *ir_test_out;
+ params_t *params = &cable_params;
+ int delay, delay_window_size;
+ int first_good_delay = -1, last_good_delay = -1;
+ int retval;
+ int i;
+ int idx;
+
+ /* FIXME find a way to do delay test for SWD mode */
+ if (swd_mode)
+ return ERROR_OK;
+
+ total_ir_length = 0;
+ tap = jtag_tap_next_enabled(NULL);
+ for (; tap != NULL; tap = jtag_tap_next_enabled(tap))
+ total_ir_length += tap->ir_length;
+
+ test_data_length = TEST_DATA_LENGTH;
+ ir_test_length = DIV_ROUND_UP(test_data_length + total_ir_length, 8);
+
+ ir_test_in = malloc(ir_test_length);
+ if (ir_test_in == NULL)
+ return ERROR_FAIL;
+ ir_test_out = malloc(ir_test_length);
+ if (ir_test_out == NULL)
+ {
+ free(ir_test_in);
+ return ERROR_FAIL;
+ }
+
+ /* fill random test data */
+ for (i = 0; i < test_data_length / 8; i++)
+ ir_test_in[i] = rand();
+
+ /* after this scan, all TAPs will capture BYPASS instructions */
+ buf_set_ones(ir_test_in + test_data_length / 8, total_ir_length);
+
+ /* the good delay window size is roughly one cycle. the delay chip
+ is 0.25ns. */
+ idx = adi_get_freq(freq, MAX_FREQ_2000, &avail_freqs_2000[0]);
+ delay_window_size = 1000000000 / avail_freqs_2000[idx] * 4;
+
+ jtag_add_reset(0, 0);
+ jtag_add_tlr();
+ retval = jtag_execute_queue();
+ if (retval != ERROR_OK)
+ goto done;
+
+ for (delay = 0; delay <= 0xff; delay++)
+ {
+ ice2000_set_voltage_freq_delay(voltage, freq_set_2000[idx], delay);
+
+ if (ice2000_validate_ircapture(test_data_length, total_ir_length,
+ ir_test_in, ir_test_out) == ERROR_OK)
+ {
+ if (first_good_delay < 0)
+ first_good_delay = delay;
+
+ last_good_delay = delay;
+ }
+ else
+ {
+ if (last_good_delay > 0)
+ break;
+ }
+ }
+
+ /* if we cannot find a good delay */
+ if (first_good_delay < 0)
+ retval = ERROR_FAIL;
+
+ /* if we find a whole window of good delays */
+ else if (first_good_delay > 0 && last_good_delay < 0xff)
+ params->cur_delay = (first_good_delay + last_good_delay) / 2;
+
+ /* all delays are valid, just pick the middle one */
+ else if (first_good_delay == 0 && last_good_delay == 0xff)
+ params->cur_delay = (first_good_delay + last_good_delay) / 2;
+
+ /* we only find a partial window */
+ else if (first_good_delay == 0 && last_good_delay < 0xff)
+ {
+ /* we still can get the best value */
+ if (last_good_delay - delay_window_size / 2 >= 0)
+ params->cur_delay = last_good_delay - delay_window_size / 2;
+ /* or make sure the margin is big enough (10 is just a guess) */
+ else if (last_good_delay >= 10)
+ params->cur_delay = 0;
+ /* otherwise we just fail */
+ else
+ retval = ERROR_FAIL;
+ }
+
+ /* we only find a partial window */
+ else /* first_good_delay > 0 && last_good_delay == 0xff */
+ {
+ /* we still can get the best value */
+ if (first_good_delay + delay_window_size / 2 <= 0xff)
+ params->cur_delay = first_good_delay + delay_window_size / 2;
+ /* or make sure the margin is big enough (10 is just a guess) */
+ else if (0xff - first_good_delay >= 10)
+ params->cur_delay = first_good_delay;
+ /* otherwise we just fail */
+ else
+ retval = ERROR_FAIL;
+ }
+
+ /* restore the original settings */
+ idx = adi_get_freq(params->cur_freq, MAX_FREQ_2000, &avail_freqs_2000[0]);
+ ice2000_set_voltage_freq_delay(params->cur_voltage, freq_set_2000[idx], params->cur_delay);
+
+done:
+ free(ir_test_in);
+ free(ir_test_out);
+
+ if (retval == ERROR_OK)
+ LOG_INFO("%s delay %d", adi_cable_name(), params->cur_delay);
+ else
+ LOG_ERROR("%s cannot find a good delay", adi_cable_name());
+
+ return retval;
+}
+
+/*
+ * Sets ICE-2000 Frequency
+ */
+static int ice2000_set_freq(uint32_t freq)
+{
+ params_t *params = &cable_params;
+ int idx = adi_get_freq(freq, MAX_FREQ_2000, &avail_freqs_2000[0]);
+
+ /* only change if different from current settings */
+ if (avail_freqs_2000[idx] != params->cur_freq)
+ {
+ if (ice2000_find_delay(params->cur_voltage, avail_freqs_2000[idx]) != ERROR_OK)
+ return ERROR_FAIL;
+ params->cur_freq = freq;
+ ice2000_set_voltage_freq_delay(params->cur_voltage, freq_set_2000[idx], params->cur_delay);
+ }
+
+ return ERROR_OK;
+}
+/* Calculate the CRC using forward CRC-16-CCITT algorithm. */
+
+static uint16_t
+crc16_ccitt(const uint8_t *data, int length, uint16_t crc)
+{
+ int i;
+
+ for (i = 0; i < length; i++)
+ {
+ uint8_t b = data[i];
+ int j;
+
+ for (j = 0; j < 8; j++)
+ {
+ bool add = ((crc >> 15) != (b >> 7));
+ crc <<= 1;
+ b <<= 1;
+ if (add)
+ crc ^= 0x1021;
+ }
+ }
+
+ return crc;
+}
+
+static int
+ice1000_send_flash_data(struct image *firmware, uint16_t *crcp)
+{
+ /* ICE_1000_READ_BUFFER_SIZE / 4 (i.e. 0x2000) was chosen by experiments.
+ It might not be related to ICE_1000_READ_BUFFER_SIZE at all. */
+ uint8_t buffer[ICE_1000_READ_BUFFER_SIZE / 4];
+ uint8_t first = 1, last = 0;
+ int i;
+ uint16_t crc = 0xffff;
+
+ for (i = 0; i < firmware->num_sections; i++)
+ {
+ size_t section_size;
+ uint8_t *section_buffer;
+ int remaining;
+ uint32_t address;
+ size_t size_read;
+ int ret;
+
+ section_size = firmware->sections[i].size;
+ section_buffer = malloc(section_size);
+ if (section_buffer == NULL)
+ {
+ LOG_ERROR("error allocating buffer for section (%d bytes)",
+ firmware->sections[i].size);
+ return ERROR_FAIL;
+ }
+
+ ret = image_read_section(firmware, i, 0, section_size, section_buffer, &size_read);
+ if (ret != ERROR_OK || size_read != section_size)
+ {
+ free(section_buffer);
+ return ret;
+ }
+
+ crc = crc16_ccitt(section_buffer, section_size, crc);
+
+ remaining = section_size;
+ address = firmware->sections[i].base_address;
+
+ while (remaining)
+ {
+ usb_command_block usb_cmd_blk;
+ uint32_t count;
+
+ LOG_INFO("updating ...");
+
+ if (remaining < ICE_1000_READ_BUFFER_SIZE / 4 - 16)
+ count = remaining;
+ else
+ count = ICE_1000_READ_BUFFER_SIZE / 4 - 16;
+ remaining -= count;
+ if (remaining == 0)
+ last = 1;
+
+ buffer[0] = first;
+ buffer[1] = last;
+ buffer[2] = HOST_PROGRAM_FLASH;
+ buffer[3] = 0;
+ memcpy(buffer + 4, &address, 4);
+ memcpy(buffer + 8, &count, 4);
+ memcpy(buffer + 12, &crc, 2);
+ memcpy(buffer + 16, section_buffer + section_size - remaining - count, count);
+
+ usb_cmd_blk.command = HOST_REQUEST_TX_DATA;
+ usb_cmd_blk.count = count + 16;
+ usb_cmd_blk.buffer = 0;
+ adi_usb_write_or_ret(&usb_cmd_blk, sizeof (usb_cmd_blk));
+
+ adi_usb_write_or_ret(buffer, usb_cmd_blk.count);
+
+ first = 0;
+
+ address += count;
+ }
+
+ free(section_buffer);
+ }
+
+ *crcp = crc;
+
+ LOG_INFO("done");
+
+ return ERROR_OK;
+}
+
+/* The CRC is stored in the output buffer after programming the firmware
+ into the flash. Read the buffer after programming get the CRC. */
+
+static int
+ice1000_firmware_crc(uint16_t *p)
+{
+ usb_command_block usb_cmd_blk;
+
+ usb_cmd_blk.command = HOST_REQUEST_RX_DATA;
+ usb_cmd_blk.count = 2;
+ usb_cmd_blk.buffer = 0;
+
+ adi_usb_write_or_ret(&usb_cmd_blk, sizeof (usb_cmd_blk));
+
+ adi_usb_read_or_ret(p, sizeof (*p));
+
+ return ERROR_OK;
+}
+
+static int
+ice1000_update_firmware(const char *filename)
+{
+ struct image ice1000_firmware_image;
+ unsigned short crc1, crc2;
+ int ret;
+
+ LOG_INFO("Updating to firmware %s", filename);
+
+ ret = image_open(&ice1000_firmware_image, filename, "ihex");
+ if (ret != ERROR_OK)
+ return ret;
+
+ ret = ice1000_send_flash_data(&ice1000_firmware_image, &crc1);
+ if (ret != ERROR_OK)
+ return ret;
+
+ if ((ret = ice1000_firmware_crc(&crc2)) != ERROR_OK)
+ return ret;
+
+ image_close(&ice1000_firmware_image);
+
+ if (crc1 == crc2)
+ return ERROR_OK;
+ else
+ {
+ LOG_ERROR("CRCs do NOT match");
+ return ERROR_FAIL;
+ }
+}
+
+/*
+ * This function sets us up the cable and data
+ */
+static int adi_connect(const uint16_t *vids, const uint16_t *pids)
+{
+ const char *cable_name = adi_cable_name();
+ libusb_device_handle *dev;
+ libusb_device *udev;
+ struct libusb_config_descriptor *config;
+ uint8_t configuration;
+ char *firmware_filename = get_firmware_filename();
+ int i, ret;
+
+ ret = libusb_init(NULL);
+ if (ret)
+ {
+ LOG_ERROR("libusb initialization failed.");
+ return ERROR_FAIL;
+ }
+
+ ret = jtag_libusb_open(vids, pids, NULL, &dev);
+ if (ret != ERROR_OK)
+ return ret;
+
+ udev = libusb_get_device(dev);
+ libusb_get_active_config_descriptor(udev, &config);
+ configuration = config->bConfigurationValue;
+ libusb_free_config_descriptor (config);
+ libusb_set_configuration(dev, configuration);
+ ret = libusb_claim_interface(dev, 0);
+ if (ret)
+ {
+ LOG_ERROR("libusb_claim_interface failed: %d", ret);
+ libusb_close(dev);
+ return ERROR_FAIL;
+ }
+ else
+ {
+ LOG_DEBUG("usb interface claimed!");
+ }
+
+ cable_params.tap_info.dat = malloc(sizeof(dat_dat) * DAT_SZ);
+ if (!cable_params.tap_info.dat)
+ {
+ LOG_ERROR("malloc(%"PRIzd") fails", sizeof(dat_dat) * DAT_SZ);
+ libusb_release_interface(dev, 0);
+ libusb_close(dev);
+ return ERROR_FAIL;
+ }
+
+ /* Initialize receive data array to unused */
+ for (i = 0; i < DAT_SZ; ++i)
+ {
+ cable_params.tap_info.dat[i].idx = -1;
+ cable_params.tap_info.dat[i].pos = -1;
+ }
+
+ cable_params.usb_handle = dev;
+ cable_params.tap_info.bit_pos = 0x80;
+ cable_params.tap_info.num_dat = DAT_SZ;
+ cable_params.tap_info.rcv_dat = -1;
+ cable_params.tap_info.cur_dat = -1;
+
+ cable_params.default_scanlen = ICE_DEFAULT_SCAN_LEN;
+ cable_params.trigger_scanlen = ICE_TRIGGER_SCAN_LEN;
+ cable_params.wr_ep = ICE_1000_WRITE_ENDPOINT;
+ cable_params.r_ep = ICE_1000_READ_ENDPOINT;
+ cable_params.wr_timeout = ICE_1000_USB_WRITE_TIMEOUT;
+ cable_params.r_timeout = ICE_1000_USB_READ_TIMEOUT;
+ cable_params.wr_buf_sz = ICE_1000_WRITE_BUFFER_SIZE;
+ cable_params.r_buf_sz = ICE_1000_READ_BUFFER_SIZE;
+
+ cable_params.version = do_host_cmd(HOST_GET_FW_VERSION, 0, 1);
+
+ LOG_INFO("%s firmware version is %d.%d.%d",
+ cable_name,
+ ((cable_params.version >> 8) & 0xFF),
+ ((cable_params.version >> 4) & 0x0F),
+ ((cable_params.version) & 0x0F));
+
+ if (cable_params.version <= 0x0101)
+ LOG_WARNING("This firmware version is obsolete. Please update to the latest version.");
+
+ if (firmware_filename)
+ {
+ ret = ice1000_update_firmware(firmware_filename);
+ if (ret == ERROR_OK)
+ LOG_INFO("The firmware has been updated successfully. "
+ "Please unplug the %s cable and reconnect it to finish the update process.", cable_name);
+ else
+ LOG_ERROR("The firmware failed to update.");
+ return ERROR_JTAG_INIT_FAILED;
+ }
+
+ /* Set frequency to lowest value */
+ if (strcmp (cable_name, "ICE-2000") == 0)
+ {
+ /* Turn on the voltage regulators */
+ do_host_cmd(HOST_SET_2000_VOLTAGE, 1, 0);
+
+ do_host_cmd(HOST_SET_INTERFACE_MODE, swd_mode ? 1 : 0, 0);
+
+ /* If user has not set the voltage, default it to 3.3V. */
+ if (cable_params.cur_voltage == 0)
+ cable_params.cur_voltage = 3;
+
+ if (cable_params.cur_voltage == 1)
+ LOG_INFO("%s voltage 1.8V", cable_name);
+ else if (cable_params.cur_voltage == 2)
+ LOG_INFO("%s voltage 2.5V", cable_name);
+ else /* cable_params.cur_voltage == 3 */
+ LOG_INFO("%s voltage 3.3V", cable_name);
+
+ /* Set the frequency to the lowest. */
+ cable_params.cur_freq = avail_freqs_2000[0];
+
+ /* Set the delay to 0. */
+ ice2000_set_voltage_freq_delay(cable_params.cur_voltage, freq_set_2000[0], 0);
+ }
+ else if (strcmp (cable_name, "ICE-1000") == 0)
+ {
+ do_host_cmd(HOST_SET_INTERFACE_MODE, swd_mode ? 1 : 0, 0);
+
+ ice1000_set_freq(avail_freqs_1000[0]);
+ }
+
+ /* HOST_HARD_RESET_JTAG_CTRLR will toggle TRST. This command has to be
+ sent after voltage regulators are turned on for ICE-2000. */
+ do_host_cmd(HOST_HARD_RESET_JTAG_CTRLR, 0, 0);
+
+ /* There is a bug in implementation of HOST_HARD_RESET_JTAG_CTRLR command
+ in 1.0.1 or earlier version firmware which does not hold TRST for enough
+ time. The processors, which ICE-1000/2000 usually work with, like legacy
+ Blackfin and ADSP-SC589 requires at least 4 JTAG CLKs. As a workaround,
+ we hold TRST low for 4 us, which should be enough even for the lowest
+ frequecy we can set, 1 MHz. */
+ if (cable_params.version <= 0x0101)
+ {
+ do_host_cmd(HOST_SET_TRST, 1, 0);
+ usleep(4);
+ do_host_cmd(HOST_SET_TRST, 0, 0);
+ }
+
+ cable_params.tap_pair_start_idx = SELECTIVE_RAW_SCAN_HDR_SZ;
+ cable_params.max_raw_data_tx_items = cable_params.wr_buf_sz - cable_params.tap_pair_start_idx;
+ cable_params.num_rcv_hdr_bytes = cable_params.tap_pair_start_idx;
+
+ if (strcmp (cable_name, "ICE-1000") == 0 || strcmp (cable_name, "ICE-2000") == 0) {
+ if (swd_mode)
+ ice1000_swd_switch_seq(NULL, JTAG_TO_SWD);
+ else
+ ice1000_swd_switch_seq(NULL, SWD_TO_JTAG);
+ ice1000_swd_run_queue(NULL);
+ }
+
+ return ERROR_OK;
+}
+
+/*
+ * takes tdi and tms and sends it out right away
+ */
+static int adi_clock(int32_t tms, int32_t tdi, int32_t cnt)
+{
+ num_tap_pairs *tap_info = &cable_params.tap_info;
+
+ if (tap_info->pairs == NULL)
+ {
+ unsigned char *cmd;
+ int32_t new_sz = cable_params.default_scanlen;
+ uint8_t bit_set;
+ int i, j;
+
+ cmd = malloc((sizeof (tap_pairs) * new_sz) + 1 + cable_params.tap_pair_start_idx);
+ if (cmd == NULL)
+ {
+ LOG_ERROR("malloc(%"PRIzd") fails",
+ (sizeof (tap_pairs) * new_sz) + 1 + cable_params.tap_pair_start_idx);
+ return ERROR_FAIL;
+ }
+
+ tap_info->cmd = cmd;
+ /* point our pairs to the space that was allocated */
+ tap_info->pairs = (tap_pairs *)(cmd + cable_params.tap_pair_start_idx); /* new pointer */
+
+ /* initialize some of our structure */
+
+ bit_set = 0x80;
+ i = 0;
+ tap_info->pairs[i].tms = 0;
+ tap_info->pairs[i].tdi = 0;
+
+ /* go through and set tms and tdi to the appropriate values */
+ for (j = 0; j < cnt; j++)
+ {
+ tap_info->pairs[i].tms |= tms ? bit_set : 0;
+ tap_info->pairs[i].tdi |= tdi ? bit_set : 0;
+ bit_set >>= 1;
+ if (!bit_set)
+ {
+ /* start over again */
+ bit_set = 0x80;
+ i++;
+ tap_info->pairs[i].tms = 0;
+ tap_info->pairs[i].tdi = 0;
+ }
+ }
+
+ tap_info->total = new_sz;
+ tap_info->cur_idx = cnt / 8; /* we scan in multiples of 32 */
+ tap_info->bit_pos = bit_set;
+
+ return ERROR_OK;
+ }
+ else
+ {
+ int i, j;
+ uint8_t bit_set;
+
+ bit_set = tap_info->bit_pos;
+ i = tap_info->cur_idx;
+
+ for (j = 0; j < cnt; j++)
+ {
+ tap_info->pairs[i].tms |= tms ? bit_set : 0;
+ tap_info->pairs[i].tdi |= tdi ? bit_set : 0;
+ bit_set >>= 1;
+ if (!bit_set)
+ {
+ /* start over again */
+ bit_set = 0x80;
+ i++;
+ tap_info->pairs[i].tms = 0;
+ tap_info->pairs[i].tdi = 0;
+ }
+ }
+
+ tap_info->cur_idx = i;
+ tap_info->bit_pos = bit_set;
+
+ return ERROR_OK;
+ }
+}
+
+static int ice1000_init(void)
+{
+ const uint16_t vids[] = { 0x064b, 0 };
+ const uint16_t pids[] = { 0x0617, 0 };
+
+ int retval;
+
+ retval = adi_connect(vids, pids);
+ if (retval != ERROR_OK)
+ {
+ if (retval == -ENODEV)
+ LOG_ERROR("ICE-1000 emulator not found");
+
+ LOG_ERROR("cannot connect to ICE-1000 emulator");
+ }
+
+ return retval;
+}
+
+static int ice2000_init(void)
+{
+ const uint16_t vids[] = { 0x064b, 0 };
+ const uint16_t pids[] = { 0x0283, 0 };
+
+ int retval;
+
+ retval = adi_connect(vids, pids);
+ if (retval != ERROR_OK)
+ {
+ if (retval == -ENODEV)
+ LOG_ERROR("ICE-2000 emulator not found");
+
+ LOG_ERROR("cannot connect to ICE-2000 emulator");
+ }
+
+ return retval;
+}
+
+static int ice1000_quit(void)
+{
+ do_host_cmd(HOST_DISCONNECT, 0, 0);
+
+ if (cable_params.usb_handle != NULL)
+ {
+ libusb_release_interface(cable_params.usb_handle, 0);
+ libusb_close(cable_params.usb_handle);
+ }
+
+ free(cable_params.tap_info.dat);
+
+ return ERROR_OK;
+}
+
+static int ice2000_quit(void)
+{
+ /* Turn off the voltage regulators */
+ do_host_cmd(HOST_SET_2000_VOLTAGE, 0, 0);
+
+ do_host_cmd(HOST_DISCONNECT, 0, 0);
+
+ if (cable_params.usb_handle != NULL)
+ {
+ libusb_release_interface(cable_params.usb_handle, 0);
+ libusb_close(cable_params.usb_handle);
+ }
+
+ free(cable_params.tap_info.dat);
+
+ return ERROR_OK;
+}
+
+static int ice1000_speed(int speed)
+{
+ if (speed >= MAX_FREQ_1000 && speed < 0)
+ {
+ LOG_ERROR("bad speed %d, should between %d and %d.",
+ speed, 0, MAX_FREQ_1000 - 1);
+ return ERROR_FAIL;
+ }
+
+ ice1000_set_freq(avail_freqs_1000[speed]);
+
+ return ERROR_OK;
+}
+
+static int ice1000_speed_div(int speed, int *khz)
+{
+ *khz = avail_freqs_1000[speed] / 1000;
+ return ERROR_OK;
+}
+
+static int ice1000_khz(int khz, int *speed)
+{
+ *speed = adi_get_freq(khz * 1000, MAX_FREQ_1000, &avail_freqs_1000[0]);
+ return ERROR_OK;
+}
+
+static int ice2000_speed(int speed)
+{
+ if (speed >= MAX_FREQ_2000 && speed < 0)
+ {
+ LOG_ERROR("bad speed %d, should between %d and %d.",
+ speed, 0, MAX_FREQ_2000 - 1);
+ return ERROR_FAIL;
+ }
+
+ return ice2000_set_freq(avail_freqs_2000[speed]);
+}
+
+static int ice2000_speed_div(int speed, int *khz)
+{
+ *khz = avail_freqs_2000[speed] / 1000;
+ return ERROR_OK;
+}
+
+static int ice2000_khz(int khz, int *speed)
+{
+ *speed = adi_get_freq(khz * 1000, MAX_FREQ_2000, &avail_freqs_2000[0]);
+ return ERROR_OK;
+}
+
+/*
+ * Takes Data received (rcv_dataptr) and puts it in
+ * todo date out transfer
+ */
+static uint8_t *get_recv_data(int32_t len, int32_t idx_dat, uint8_t *rcv_data)
+{
+ uint8_t *buf;
+ num_tap_pairs *tap_info = &cable_params.tap_info;
+ int32_t dat_idx = tap_info->dat[idx_dat].idx;
+ uint8_t *rcvBuf = rcv_data + cable_params.num_rcv_hdr_bytes + dat_idx;
+ int32_t bit_set = tap_info->dat[idx_dat].pos;
+ int32_t i;
+
+#ifdef DUMP_EACH_RCV_DATA
+ DEBUG("Idx = %d; Read len = %d\n", dat_idx, len);
+#endif
+
+ buf = (uint8_t *)calloc(DIV_ROUND_UP(len, 8), 1);
+
+ if (buf == NULL)
+ LOG_ERROR("malloc(%d) fails", DIV_ROUND_UP(len, 8));
+
+ if (idx_dat < 0)
+ {
+ DEBUG("get_recv_data(): No Received Data\n");
+ return NULL;
+ }
+
+ for (i = 0; i < len; i++)
+ {
+ buf[i/8] |= ((*rcvBuf & bit_set) ? 1 : 0) << (i % 8);
+
+#ifdef DUMP_EACH_RCV_DATA
+ if (i % 8 == 0 && i != 0)
+ DEBUG("%d", buf[i/8 - 1]);
+ if (((i + 1) % 64) == 0)
+ putchar('\n');
+ else if (((i + 1) % 8) == 0)
+ putchar(' ');
+#endif
+ bit_set >>= 1;
+
+ if (!bit_set)
+ {
+ bit_set = 0x80;
+ rcvBuf++;
+ dat_idx++;
+ }
+ }
+
+ /* this is set for getting the extra TDO bits */
+ tap_info->dat[idx_dat].idx = dat_idx;
+ tap_info->dat[idx_dat].pos = bit_set;
+
+ return buf;
+}
+
+static int ice1000_tap_execute(void)
+{
+ num_tap_pairs *tap_info = &cable_params.tap_info;
+ uint8_t *buf;
+ int i, retval;
+
+ if (tap_info->cur_idx == 0 && tap_info->bit_pos == 0x80
+ && tap_info->cur_dat == -1)
+ return ERROR_OK;
+
+ buf = NULL;
+ perform_scan(&buf);
+
+ retval = ERROR_OK;
+
+ for (i = 0; i <= tap_info->cur_dat; i++)
+ {
+ uint8_t *buffer;
+ struct scan_command *command = tap_info->dat[i].ptr;
+
+ buffer = get_recv_data(jtag_scan_size(command), tap_info->rcv_dat, buf);
+ tap_info->rcv_dat++;
+ if (jtag_read_buffer(buffer, command) != ERROR_OK)
+ return ERROR_JTAG_QUEUE_FAILED;
+
+ free(buffer);
+ }
+
+ free(buf);
+ if (tap_info->pairs)
+ {
+ free(tap_info->cmd);
+ tap_info->pairs = NULL;
+ tap_info->cmd = NULL;
+ }
+ tap_info->total = 0;
+ tap_info->cur_idx = 0;
+ tap_info->bit_pos = 0x80;
+ tap_info->cur_dat = -1;
+ tap_info->rcv_dat = -1;
+
+ return retval;
+}
+
+static int ice1000_execute_reset(struct jtag_command *cmd)
+{
+ int retval;
+
+ retval = ice1000_tap_execute();
+ if (retval != ERROR_OK)
+ return retval;
+
+ 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);
+ }
+
+ do_host_cmd(HOST_SET_TRST, cmd->cmd.reset->trst ? 0 : 1, 0);
+ return ERROR_OK;
+}
+
+static void ice1000_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 valid end state", tap_state_name(state));
+ exit(-1);
+ }
+}
+
+static int ice1000_tap_ensure_space(unsigned int bits)
+{
+ int retval = ERROR_OK;
+
+ if (cable_params.tap_info.cur_idx + DIV_ROUND_UP(bits, 8) >= cable_params.trigger_scanlen)
+ retval = ice1000_tap_execute();
+
+ return retval;
+}
+
+static int ice1000_tap_append_step(int tms, int tdi)
+{
+ int retval;
+ retval = adi_clock(tms, tdi, 1);
+ return retval;
+}
+
+static void ice1000_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;
+ ice1000_tap_append_step(tms, 0);
+ }
+
+ tap_set_state(tap_get_end_state());
+}
+
+static void ice1000_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))
+ {
+ ice1000_tap_append_step(0, 0);
+ }
+ else if (path[i] == tap_state_transition(tap_get_state(), true))
+ {
+ ice1000_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 int ice1000_runtest(int num_cycles)
+{
+ int retval, i;
+ tap_state_t saved_end_state = tap_get_end_state();
+
+ retval = ice1000_tap_ensure_space(num_cycles + 16);
+ if (retval != ERROR_OK)
+ return retval;
+
+ if (tap_get_state() != TAP_IDLE)
+ {
+ ice1000_end_state(TAP_IDLE);
+ ice1000_state_move();
+ }
+
+ for (i = 0; i < num_cycles; i++)
+ ice1000_tap_append_step(0, 0);
+
+ /* finish in end_state */
+ ice1000_end_state(saved_end_state);
+ if (tap_get_state() != tap_get_end_state())
+ {
+ ice1000_state_move();
+ }
+
+ return ERROR_OK;
+}
+
+static int ice1000_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);
+
+ ice1000_end_state(cmd->cmd.runtest->end_state);
+
+ ice1000_runtest(cmd->cmd.runtest->num_cycles);
+
+ return ERROR_OK;
+}
+
+static int ice1000_execute_tlr_reset(struct jtag_command *cmd)
+{
+ DEBUG_JTAG_IO("statemove end in %i", cmd->cmd.statemove->end_state);
+
+ ice1000_end_state(cmd->cmd.statemove->end_state);
+ ice1000_state_move();
+
+ /* Move to Run-Test/Idle */
+ ice1000_tap_append_step(0, 0);
+ tap_set_state(TAP_IDLE);
+
+ return ERROR_OK;
+}
+
+static int ice1000_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]);
+
+ ice1000_path_move(cmd->cmd.pathmove->num_states,
+ cmd->cmd.pathmove->path);
+
+ return ERROR_OK;
+}
+
+/*
+ * This function takes CABLE_TRANSFER todo data,
+ * and adds it to the tms/tdi scan structure
+ * If reading data, sets that up too
+ */
+static int add_scan_data(int32_t num_bits, uint8_t *in, bool out, struct scan_command *command)
+{
+ int32_t bit_cnt = num_bits % 8;
+ int32_t byte_cnt = (num_bits >> 3) + (bit_cnt ? 1 : 0);
+ int32_t i, bit_set;
+ tap_pairs *tap_scan = NULL;
+ int32_t idx;
+ num_tap_pairs *tap_info = &cable_params.tap_info;
+
+ if (in == NULL)
+ LOG_WARNING("NO IN DATA!!!%s", out ? " BUT there is out data!" : "");
+
+ if (tap_info->pairs == NULL)
+ { /* really should never get here, but must not crash system. Would be rude */
+ int32_t new_sz = cable_params.default_scanlen + 4;
+ unsigned char *cmd;
+
+ cmd = malloc((sizeof (tap_pairs) * new_sz) + 1 + cable_params.tap_pair_start_idx);
+ if (cmd == NULL)
+ {
+ LOG_ERROR("malloc(%"PRIzd") fails",
+ (sizeof (tap_pairs) * new_sz) + 1 + cable_params.tap_pair_start_idx);
+ return ERROR_FAIL;
+ }
+
+ tap_info->cur_dat = -1;
+ tap_info->rcv_dat = -1;
+ tap_info->bit_pos = 0x80;
+ tap_info->total = new_sz;
+ tap_info->cmd = cmd; /* new pointer */
+ tap_info->pairs = (tap_pairs *)(cmd + cable_params.tap_pair_start_idx); /* new pointer */
+
+ tap_scan = tap_info->pairs;
+ tap_scan->tms = 0;
+ tap_scan->tdi = 0;
+ idx = tap_info->cur_idx = 1; /* first pair is 0 */
+ tap_scan++;
+ tap_scan->tdi = 0;
+ tap_scan->tms = 0;
+ }
+ else if ((tap_info->total - tap_info->cur_idx) < byte_cnt)
+ { /* to small, increase size! */
+ unsigned char *cmd;
+ int32_t new_sz;
+
+ DEBUG("Reallocating scan_data\n");
+
+ new_sz = tap_info->total + byte_cnt + 8;
+ cmd = realloc(tap_info->cmd, (sizeof (tap_pairs) * new_sz) + 4 + cable_params.tap_pair_start_idx);
+ if (cmd == NULL)
+ {
+ LOG_ERROR("realloc(%"PRIzd") fails",
+ (sizeof (tap_pairs) * new_sz) + 4 + cable_params.tap_pair_start_idx);
+ return ERROR_FAIL;
+ }
+
+ tap_info->total = new_sz; /* resize size */
+ tap_info->cmd = cmd; /* new pointer */
+ tap_info->pairs = (tap_pairs *)(cmd + cable_params.tap_pair_start_idx); /* new pointer */
+
+ tap_scan = tap_info->pairs;
+ idx = tap_info->cur_idx; /* to add on */
+ tap_scan = &tap_info->pairs[idx];
+ }
+ else
+ {
+ idx = tap_info->cur_idx; /* to add on */
+ tap_scan = &tap_info->pairs[idx];
+ }
+
+ bit_set = tap_info->bit_pos;
+
+ if (out)
+ { /* Setup where we start to read, can be more than 1 */
+ if (tap_info->rcv_dat == -1)
+ {
+ tap_info->rcv_dat = 0;
+ }
+ tap_info->cur_dat++;
+ if (tap_info->cur_dat >= tap_info->num_dat)
+ {
+ int32_t new_sz;
+ dat_dat *datPtr;
+
+ new_sz = tap_info->num_dat + DAT_SZ_INC;
+ datPtr = realloc(tap_info->dat, sizeof (dat_dat) * new_sz);
+ if (datPtr == NULL)
+ {
+ LOG_ERROR("realloc(%"PRIzd") fails",
+ sizeof (dat_dat) * new_sz);
+ return ERROR_FAIL;
+ }
+ tap_info->dat = datPtr;
+ tap_info->num_dat = new_sz;
+
+ }
+ tap_info->dat[tap_info->cur_dat].idx = idx;
+ tap_info->dat[tap_info->cur_dat].pos = bit_set;
+ tap_info->dat[tap_info->cur_dat].ptr = command;
+ }
+
+ /* Build Scan. If command is NULL, IN is TMS. Otherwise,
+ TMS will always be zero except the last bit! */
+ for (i = 0; i < num_bits; i++)
+ {
+ if (command != NULL)
+ {
+ tap_scan->tdi |= (in[i / 8] >> (i % 8)) & 0x1 ? bit_set : 0;
+ if (i == num_bits - 1)
+ tap_scan->tms |= bit_set;
+ }
+ else
+ tap_scan->tms |= (in[i / 8] >> (i % 8)) & 0x1 ? bit_set : 0;
+
+ bit_set >>= 1;
+ if (!bit_set)
+ {
+ bit_set = 0x80;
+ idx++;
+ tap_scan++;
+ tap_scan->tdi = 0;
+ tap_scan->tms = 0;
+ }
+ }
+
+ tap_info->cur_idx = idx;
+ tap_info->bit_pos = bit_set;
+
+ return ERROR_OK;
+}
+
+static int ice1000_scan(bool ir_scan, enum scan_type type, uint8_t *buffer,
+ int scan_size, struct scan_command *command)
+{
+ tap_state_t saved_end_state;
+ int retval;
+
+ retval = ice1000_tap_ensure_space(scan_size + 16);
+ if (retval != ERROR_OK)
+ return retval;
+
+ saved_end_state = tap_get_end_state();
+
+ /* Move to appropriate scan state */
+ ice1000_end_state(ir_scan ? TAP_IRSHIFT : TAP_DRSHIFT);
+
+ /* Only move if we're not already there */
+ if (tap_get_state() != tap_get_end_state())
+ ice1000_state_move();
+
+ ice1000_end_state(saved_end_state);
+
+ /* Scan */
+ add_scan_data(scan_size, buffer, type != SCAN_OUT, command);
+
+ /* We are in Exit1, go to Pause */
+ ice1000_tap_append_step(0, 0);
+
+ tap_set_state(ir_scan ? TAP_IRPAUSE : TAP_DRPAUSE);
+
+ if (tap_get_state() != tap_get_end_state())
+ {
+ ice1000_state_move();
+ }
+
+ return ERROR_OK;
+}
+
+static int ice1000_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));
+
+ ice1000_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);
+
+ type = jtag_scan_type(cmd->cmd.scan);
+ ice1000_scan(cmd->cmd.scan->ir_scan,
+ type, buffer, scan_size, cmd->cmd.scan);
+
+ free(buffer);
+
+ return ERROR_OK;
+}
+
+static int ice1000_execute_sleep(struct jtag_command *cmd)
+{
+ int retval;
+
+ retval = ice1000_tap_execute();
+ if (retval != ERROR_OK)
+ return retval;
+
+ DEBUG_JTAG_IO("sleep %" PRIi32 "", cmd->cmd.sleep->us);
+
+ jtag_sleep(cmd->cmd.sleep->us);
+ return ERROR_OK;
+}
+
+static int ice1000_execute_stableclocks(struct jtag_command *cmd)
+{
+ int tms;
+
+ switch (tap_get_state()) {
+ case TAP_RESET:
+ /* tms must be '1' to stay
+ * n TAP_RESET mode
+ */
+ tms = 1;
+ break;
+ case TAP_DRSHIFT:
+ case TAP_IDLE:
+ case TAP_DRPAUSE:
+ case TAP_IRSHIFT:
+ case TAP_IRPAUSE:
+ /* else, tms should be '0' */
+ tms = 0;
+ break;
+ default:
+ return ERROR_FAIL;
+ }
+
+ adi_clock(tms, 0, cmd->cmd.stableclocks->num_cycles);
+
+ return ERROR_OK;
+}
+
+static int ice1000_execute_tms(struct jtag_command *cmd)
+{
+ int num_bits = cmd->cmd.tms->num_bits;
+ uint8_t *bits = (uint8_t *)cmd->cmd.tms->bits;
+ int count = DIV_ROUND_UP(num_bits, 8);
+ int retval;
+
+ retval = ice1000_tap_ensure_space(count);
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = add_scan_data(num_bits, bits, false, NULL);
+
+ return retval;
+}
+
+static int ice1000_execute_command(struct jtag_command *cmd)
+{
+ int retval;
+
+ switch (cmd->type)
+ {
+ case JTAG_RESET:
+ retval = ice1000_execute_reset(cmd);
+ break;
+ case JTAG_RUNTEST:
+ retval = ice1000_execute_runtest(cmd);
+ break;
+ case JTAG_TLR_RESET:
+ retval = ice1000_execute_tlr_reset(cmd);
+ break;
+ case JTAG_PATHMOVE:
+ retval = ice1000_execute_pathmove(cmd);
+ break;
+ case JTAG_SCAN:
+ retval = ice1000_execute_scan(cmd);
+ break;
+ case JTAG_SLEEP:
+ retval = ice1000_execute_sleep(cmd);
+ break;
+ case JTAG_STABLECLOCKS:
+ retval = ice1000_execute_stableclocks(cmd);
+ break;
+ case JTAG_TMS:
+ retval = ice1000_execute_tms(cmd);
+ break;
+ default:
+ LOG_ERROR("BUG: unknown JTAG command type encountered");
+ retval = ERROR_JTAG_QUEUE_FAILED;
+ break;
+ }
+ return retval;
+}
+
+static int ice1000_execute_queue(void)
+{
+ struct jtag_command *cmd = jtag_command_queue;
+ int retval = ERROR_OK;
+
+ /* TODO add blink */
+ while (cmd != NULL)
+ {
+ if (ice1000_execute_command(cmd) != ERROR_OK)
+ retval = ERROR_JTAG_QUEUE_FAILED;
+ cmd = cmd->next;
+ }
+
+ if (retval != ERROR_OK)
+ return retval;
+
+ return ice1000_tap_execute();
+}
+
+/*
+ * Read & Write Registers
+ *
+ * XXX: error handling doesn't quite work with this return
+ * XXX: probably needs converting from memory arrays to byte shifts
+ * so we work regardless of host endian
+ */
+static uint32_t do_single_reg_value(uint8_t reg, int32_t r_data, int32_t wr_data, uint32_t data)
+{
+ usb_command_block usb_cmd_blk;
+ union {
+ uint8_t b[24];
+ uint32_t l[6];
+ } cmd_buffer;
+ uint32_t count = 0;
+ int32_t i, size = wr_data ? 8 : 4;
+
+ usb_cmd_blk.command = HOST_REQUEST_TX_DATA;
+ usb_cmd_blk.count = size;
+ usb_cmd_blk.buffer = 0;
+
+ adi_usb_write_or_ret(&usb_cmd_blk, sizeof(usb_cmd_blk));
+ i = 0;
+
+ /* send HOST_SET_SINGLE_REG command */
+ cmd_buffer.b[i++] = 1;
+ cmd_buffer.b[i++] = 0;
+ cmd_buffer.b[i++] = wr_data ? HOST_SET_SINGLE_REG : HOST_GET_SINGLE_REG;
+ cmd_buffer.b[i++] = reg;
+ if (wr_data)
+ {
+ cmd_buffer.l[i / 4] = data;
+ }
+
+ adi_usb_write_or_ret(cmd_buffer.b, size);
+
+ if (r_data)
+ adi_usb_read_or_ret(&count, sizeof (count));
+
+ return count;
+}
+
+/*
+ * Send Host Command.
+ *
+ * XXX: error handling doesn't quite work with this return
+ * XXX: probably needs converting from memory arrays to byte shifts
+ * so we work regardless of host endian
+ */
+static uint16_t do_host_cmd(uint8_t cmd, uint8_t param, int32_t r_data)
+{
+ usb_command_block usb_cmd_blk;
+ uint16_t results = 0;
+ union {
+ uint8_t b[20];
+ uint32_t l[20/4];
+ } cmd_buffer;
+ int32_t size = 5;
+
+ usb_cmd_blk.command = HOST_REQUEST_TX_DATA;
+ usb_cmd_blk.count = size;
+ usb_cmd_blk.buffer = 0;
+
+ adi_usb_write_or_ret(&usb_cmd_blk, sizeof(usb_cmd_blk));
+
+ /* send command */
+ cmd_buffer.b[0] = 0;
+ cmd_buffer.b[1] = 0;
+ cmd_buffer.b[2] = cmd;
+ cmd_buffer.b[3] = 0;
+ cmd_buffer.b[4] = 0;
+
+ if (cmd == HOST_SET_TRST)
+ cmd_buffer.b[0] = param;
+ else
+ cmd_buffer.b[4] = param;
+
+ adi_usb_write_or_ret(cmd_buffer.b, size);
+
+ if (r_data)
+ {
+ usb_cmd_blk.command = HOST_REQUEST_RX_DATA;
+ usb_cmd_blk.count = 2;
+ usb_cmd_blk.buffer = 0;
+
+ adi_usb_write_or_ret(&usb_cmd_blk, sizeof (usb_cmd_blk));
+
+ adi_usb_read_or_ret (&results, sizeof (results));
+ }
+
+ return results;
+}
+
+/*
+ * Controlling function to do a scan.
+ * rdata is a pointer to storage for the pointer
+ * allocated here to return data if needed
+ */
+static int perform_scan(uint8_t **rdata)
+{
+ num_tap_pairs *tap_info = &cable_params.tap_info;
+ uint8_t firstpkt = 1, lastpkt = 0, *in = NULL, *out = NULL;
+ int32_t idx, collect_data = 0;
+ uint32_t cur_len = tap_info->cur_idx;
+ uint32_t rem_len;
+
+ /* Data is scan as 32 bit words, so boundaries are adjusted here */
+ if (tap_info->bit_pos != 0x80) /* meaning no dangling bits? */
+ { /* yes, so straighten out! */
+ cur_len++;
+ tap_info->pairs[cur_len].tms = 0;
+ tap_info->pairs[cur_len].tdi = 0;
+ }
+
+ /* Pad with zeros */
+ cur_len++;
+ tap_info->pairs[cur_len].tms = 0;
+ tap_info->pairs[cur_len].tdi = 0;
+
+ while (cur_len & 0x03)
+ { /* expect to be in 32 bit words */
+ cur_len++;
+ tap_info->pairs[cur_len].tms = 0;
+ tap_info->pairs[cur_len].tdi = 0;
+ }
+
+ tap_info->cur_idx = cur_len;
+ rem_len = cur_len * sizeof (tap_pairs);
+
+ if (cur_len > cable_params.default_scanlen)
+ {
+ LOG_ERROR("TAP Scan length %d is greater than DIF Memory",
+ tap_info->cur_idx);
+ return ERROR_FAIL;
+ }
+
+ if (tap_info->cur_dat != -1)
+ { /* yes we have data, so allocate for data plus header */
+ size_t len;
+
+ len = cur_len + cable_params.tap_pair_start_idx + 16;
+ if (tap_info->dat[0].idx > 12)
+ len -= tap_info->dat[0].idx;
+
+ out = malloc(len);
+ if (out == NULL)
+ {
+ LOG_ERROR("malloc(%"PRIzd") fails", len);
+ return ERROR_FAIL;
+ }
+ *rdata = out;
+ collect_data = 1;
+ }
+ else
+ { /* no data, so allocate for just header */
+ out = malloc(cable_params.tap_pair_start_idx + 16);
+ if (out == NULL)
+ {
+ LOG_ERROR("malloc(%d) fails", cable_params.tap_pair_start_idx + 16);
+ return ERROR_FAIL;
+ }
+ collect_data = 0;
+ }
+
+ in = (uint8_t *)tap_info->pairs;
+ idx = 0;
+
+ /* Here if data is too large, we break it up into manageable chunks */
+ do
+ {
+ cur_len = (rem_len >= cable_params.max_raw_data_tx_items) ? cable_params.max_raw_data_tx_items : rem_len;
+
+ if (cur_len == rem_len)
+ lastpkt = 1;
+
+ do_rawscan(firstpkt, lastpkt, collect_data, cur_len, &in[idx] - cable_params.tap_pair_start_idx, out);
+
+ rem_len -= cur_len;
+ idx += cur_len;
+ firstpkt = 0;
+
+ } while (rem_len);
+
+ if (tap_info->cur_dat == -1)
+ { /* no data to return, so free it */
+ free(out);
+ }
+
+ return ERROR_OK;
+}
+
+/*
+ * description of raw scan packet structure:
+ *
+ * [0] : first packet flag (do setup work if needed)
+ * [1] : last packet flag (start the scan and cleanup if needed)
+ * [2] : command ID
+ * [3] : collect DOF flag (need to read DOF)
+ * [4-5] : DIF count
+ * [6-7] : scan length count
+ * [8-9] : first scan pair
+ * [10...] : more scan pairs
+ *
+ * Data input:
+ *
+ * firstpkt : Is this the first packet of the scan? 0 = NO
+ * lastpkt : Is this the last packet of the scan? 0 = NO
+ * collect_dof: Are we collecting data? 0 = NO
+ * dif_cnt : Number of bytes to send
+ * *raw_buf : Pointer to Scan Data buffer * cmd to send
+ * *out : Pointer to Scan Data buffer to receive
+ *
+ * XXX: probably needs converting from memory arrays to byte shifts
+ * so we work regardless of host endian
+ */
+static int do_rawscan(uint8_t firstpkt, uint8_t lastpkt,
+ int32_t collect_dof, int32_t dif_cnt,
+ uint8_t *raw_buf, uint8_t *out)
+{
+ usb_command_block usb_cmd_blk;
+ num_tap_pairs *tap_info = &cable_params.tap_info;
+ int32_t i, dof_start = 0;
+ uint32_t data;
+ uint32_t size = cable_params.tap_pair_start_idx + dif_cnt;
+
+ usb_cmd_blk.command = HOST_REQUEST_TX_DATA;
+ usb_cmd_blk.count = size;
+ usb_cmd_blk.buffer = 0;
+
+ /* first send Xmit request with the count of what will be sent */
+ adi_usb_write_or_ret(&usb_cmd_blk, sizeof (usb_cmd_blk));
+ i = 0;
+
+ /* send HOST_DO_SELECTIVE_RAW_SCAN command */
+ raw_buf[i++] = firstpkt;
+ raw_buf[i++] = lastpkt;
+ raw_buf[i++] = HOST_DO_SELECTIVE_RAW_SCAN;
+ if ((collect_dof && lastpkt) && (tap_info->dat[0].idx > 12))
+ {
+ int32_t j, offset;
+
+ dof_start = tap_info->dat[0].idx;
+ offset = dof_start & 7;
+ dof_start -= offset & 7;
+ tap_info->dat[0].idx = offset;
+
+ for (j = 1; j <= tap_info->cur_dat; j++)
+ {
+ tap_info->dat[j].idx -= dof_start;
+ }
+ }
+
+ raw_buf[i++] = collect_dof ? 1 : 0;
+ data = dif_cnt / 4; /* dif count in longs */
+ memcpy(raw_buf + i, &data, 4);
+ data = tap_info->cur_idx / 4; /* count in longs */
+ memcpy(raw_buf + i + 2, &data, 4);
+
+ { /* only Ice emulators use this */
+ memcpy(raw_buf + i + 4, &dof_start, 4);
+ }
+
+ adi_usb_write_or_ret(raw_buf, size);
+
+ if (lastpkt)
+ {
+ int32_t cur_rd_bytes = 0, tot_bytes_rd = 0, rd_bytes_left;
+
+ rd_bytes_left = cable_params.num_rcv_hdr_bytes + ((collect_dof) ? (tap_info->cur_idx - dof_start) : 0);
+
+ while (tot_bytes_rd < rd_bytes_left)
+ {
+ cur_rd_bytes = ((rd_bytes_left - tot_bytes_rd) > cable_params.r_buf_sz) ?
+ cable_params.r_buf_sz : (rd_bytes_left - tot_bytes_rd);
+
+ adi_usb_read_or_ret(out + tot_bytes_rd, cur_rd_bytes);
+ tot_bytes_rd += cur_rd_bytes;
+ }
+
+ if (out[0] != 2)
+ {
+ LOG_ERROR("Scan Error!");
+ return ERROR_FAIL;
+ }
+ }
+
+ return ERROR_OK;
+}
+
+static int ice1000_swd_init(void)
+{
+ LOG_INFO("%s SWD mode enabled", adi_cable_name());
+ swd_mode = true;
+ return ERROR_OK;
+}
+
+static int_least32_t ice1000_swd_frequency(struct adiv5_dap *dap, int_least32_t hz)
+{
+ if (hz > 0)
+ ice1000_set_freq(hz);
+
+ return hz;
+}
+
+static int_least32_t ice2000_swd_frequency(struct adiv5_dap *dap, int_least32_t hz)
+{
+ if (hz > 0)
+ ice2000_set_freq(hz);
+
+ return hz;
+}
+
+/* If DATA != NULL, this is for out. Otherwise, this is for in. */
+
+static int ice1000_swd_queue_packet(struct swd_packet *packet)
+{
+ uint32_t i, bit_set;
+ tap_pairs *tap_scan;
+ int32_t idx;
+ num_tap_pairs *tap_info = &cable_params.tap_info;
+
+ if (tap_info->pairs == NULL)
+ {
+ int32_t new_sz = cable_params.default_scanlen;
+ unsigned char *cmd;
+
+ cmd = malloc((sizeof (tap_pairs) * new_sz) + 1 + cable_params.tap_pair_start_idx);
+ if (cmd == NULL)
+ {
+ LOG_ERROR("malloc(%"PRIzd") fails",
+ (sizeof (tap_pairs) * new_sz) + 1 + cable_params.tap_pair_start_idx);
+ return ERROR_FAIL;
+ }
+
+ tap_info->cur_dat = -1;
+ tap_info->rcv_dat = -1;
+ tap_info->bit_pos = 0x80;
+ tap_info->total = new_sz;
+ tap_info->cmd = cmd;
+ tap_info->pairs = (tap_pairs *)(cmd + cable_params.tap_pair_start_idx);
+
+ tap_scan = tap_info->pairs;
+ tap_scan->tms = 0;
+ tap_scan->tdi = 0;
+ idx = tap_info->cur_idx = 1; /* first pair is 0 ??? */
+ tap_scan++;
+ tap_scan->tdi = 0;
+ tap_scan->tms = 0;
+ }
+ else
+ {
+ idx = tap_info->cur_idx;
+ tap_scan = &tap_info->pairs[idx];
+ }
+
+ bit_set = tap_info->bit_pos;
+
+ if (!packet->is_out)
+ {
+ if (tap_info->rcv_dat == -1)
+ {
+ tap_info->rcv_dat = 0;
+ }
+ tap_info->cur_dat++;
+ if (tap_info->cur_dat >= tap_info->num_dat)
+ {
+ int32_t new_sz;
+ dat_dat *datPtr;
+
+ new_sz = tap_info->num_dat + DAT_SZ_INC;
+ datPtr = realloc(tap_info->dat, sizeof (dat_dat) * new_sz);
+ if (datPtr == NULL)
+ {
+ LOG_ERROR("realloc(%"PRIzd") fails",
+ sizeof (dat_dat) * new_sz);
+ return ERROR_FAIL;
+ }
+ tap_info->dat = datPtr;
+ tap_info->num_dat = new_sz;
+
+ }
+ tap_info->dat[tap_info->cur_dat].idx = idx;
+ tap_info->dat[tap_info->cur_dat].pos = bit_set;
+ tap_info->dat[tap_info->cur_dat].ptr = packet;
+ }
+
+
+ for (i = 0; i < packet->length; i++)
+ {
+ if (packet->is_out)
+ tap_scan->tms |= (packet->out[i / 8] >> (i % 8)) & 0x1 ? bit_set : 0;
+ else
+ tap_scan->tdi |= bit_set;
+
+ bit_set >>= 1;
+ if (!bit_set)
+ {
+ bit_set = 0x80;
+ idx++;
+ tap_scan++;
+ tap_scan->tdi = 0;
+ tap_scan->tms = 0;
+ }
+ }
+
+ tap_info->cur_idx = idx;
+ tap_info->bit_pos = bit_set;
+
+ return ERROR_OK;
+}
+
+static int ice1000_swd_queue_data_out(const uint8_t *out, uint32_t len)
+{
+ struct swd_packet packet;
+ int retval;
+
+ memset(&packet, 0, sizeof(packet));
+
+ packet.is_out = true;
+ packet.out = out;
+ packet.length = len;
+
+ retval = ice1000_swd_queue_packet(&packet);
+
+ return retval;
+}
+
+static int ice1000_swd_queue_idle_cycles(uint32_t len)
+{
+ uint8_t *buffer;
+ int retval;
+
+ buffer = calloc(DIV_ROUND_UP(len, 8), 1);
+ if (buffer == NULL)
+ {
+ LOG_ERROR("malloc(%"PRIu32") fails", DIV_ROUND_UP(len, 8));
+ return ERROR_FAIL;
+ }
+
+ retval = ice1000_swd_queue_data_out(buffer, len);
+
+ free(buffer);
+
+ return retval;
+}
+
+static int ice1000_swd_run_queue(struct adiv5_dap *dap)
+{
+ num_tap_pairs *tap_info = &cable_params.tap_info;
+ uint8_t *buf;
+ int i, retval;
+
+ if (tap_info->cur_idx == 0 && tap_info->bit_pos == 0x80
+ && tap_info->cur_dat == -1)
+ return ERROR_OK;
+
+ /* A transaction must be followed by another transaction or at least
+ 8 idle cycles to ensure that data is clocked through the AP. */
+ ice1000_swd_queue_idle_cycles(8);
+
+ buf = NULL;
+ perform_scan(&buf);
+
+ retval = ERROR_OK;
+
+ for (i = 0; i <= tap_info->cur_dat; i++)
+ {
+ uint8_t *buffer;
+ struct swd_packet *packet = tap_info->dat[i].ptr;
+
+ buffer = get_recv_data(packet->length, tap_info->rcv_dat, buf);
+ int ack = buf_get_u32(buffer, packet->ack_pos, 3);
+
+ if (ack != SWD_ACK_OK)
+ {
+ free(buffer);
+ LOG_ERROR("SWD ack not OK: %d %s", ack,
+ ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK");
+ retval = ERROR_FAIL;
+ break;
+ }
+ else if (packet->in)
+ {
+ uint32_t data = buf_get_u32(buffer, packet->data_pos, 32);
+ int parity = buf_get_u32(buffer, packet->parity_pos, 1);
+
+ if (parity != parity_u32(data))
+ {
+ free(buffer);
+ LOG_ERROR("SWD Read data parity mismatch");
+ retval = ERROR_FAIL;
+ break;
+ }
+ else
+ {
+ uint32_t *p = packet->in;
+ *p = data;
+ }
+ }
+
+ free(buffer);
+ tap_info->rcv_dat++;
+ }
+
+ free(buf);
+ if (tap_info->pairs)
+ {
+ free(tap_info->cmd);
+ tap_info->pairs = NULL;
+ tap_info->cmd = NULL;
+ }
+ tap_info->total = 0;
+ tap_info->cur_idx = 0;
+ tap_info->bit_pos = 0x80;
+ tap_info->cur_dat = -1;
+ tap_info->rcv_dat = -1;
+
+ return retval;
+}
+
+static int ice1000_swd_switch_seq(struct adiv5_dap *dap, enum swd_special_seq seq)
+{
+ int retval;
+
+ switch (seq) {
+ case LINE_RESET:
+ LOG_DEBUG("SWD line reset");
+ retval = ice1000_swd_queue_data_out(swd_seq_line_reset, swd_seq_line_reset_len);
+ break;
+ case JTAG_TO_SWD:
+ LOG_DEBUG("JTAG-to-SWD");
+ retval = ice1000_swd_queue_data_out(swd_seq_jtag_to_swd, swd_seq_jtag_to_swd_len);
+ break;
+ case SWD_TO_JTAG:
+ LOG_DEBUG("SWD-to-JTAG");
+ retval = ice1000_swd_queue_data_out(swd_seq_swd_to_jtag, swd_seq_swd_to_jtag_len);
+ break;
+ default:
+ LOG_ERROR("Sequence %d not supported", seq);
+ retval = ERROR_FAIL;
+ }
+
+ return retval;
+}
+
+static int ice1000_swd_ensure_space(struct adiv5_dap *dap, unsigned int bits)
+{
+ int retval = ERROR_OK;
+
+ if (cable_params.tap_info.cur_idx + DIV_ROUND_UP(bits, 8) >= cable_params.trigger_scanlen)
+ retval = ice1000_swd_run_queue(dap);
+
+ return retval;
+}
+
+static int ice1000_swd_queue_cmd(struct adiv5_dap *dap, uint8_t cmd, uint32_t *dst, uint32_t data)
+{
+ uint8_t data_parity_trn[DIV_ROUND_UP(32 + 1, 8)];
+ struct swd_packet *packet;
+ int retval;
+
+ retval = ice1000_swd_ensure_space(dap, 8 + 38 + dap->memaccess_tck);
+ if (retval != ERROR_OK)
+ return retval;
+
+ packet = calloc(sizeof(struct swd_packet), 1);
+ if (packet == NULL)
+ return ERROR_FAIL;
+
+ cmd |= SWD_CMD_START | SWD_CMD_PARK;
+
+ retval = ice1000_swd_queue_data_out(&cmd, 8);
+ if (retval != ERROR_OK)
+ return retval;
+
+ if (cmd & SWD_CMD_RnW) {
+ /* Queue a read transaction */
+ packet->out = false;
+ packet->ack_pos = 0;
+ packet->data_pos = 3;
+ packet->parity_pos = 35;
+ packet->in = dst;
+ packet->length = 1 + 3 + 32 + 1 + 1;
+
+ retval = ice1000_swd_queue_packet(packet);
+ } else {
+ /* Queue a write transaction */
+ packet->out = false;
+ packet->ack_pos = 0;
+ packet->length = 1 + 3 + 1;
+
+ retval = ice1000_swd_queue_packet(packet);
+
+ buf_set_u32(data_parity_trn, 0, 32, data);
+ buf_set_u32(data_parity_trn, 32, 1, parity_u32(data));
+
+ if (retval == ERROR_OK)
+ retval = ice1000_swd_queue_data_out(data_parity_trn, 32 + 1);
+ }
+
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* Insert idle cycles after AP accesses to avoid WAIT */
+ if (cmd & SWD_CMD_APnDP)
+ retval = ice1000_swd_queue_idle_cycles(dap->memaccess_tck);
+
+ return retval;
+}
+
+static void ice1000_swd_write_reg(struct adiv5_dap *dap, uint8_t cmd, uint32_t value)
+{
+ int retval;
+ retval = ice1000_swd_queue_cmd(dap, cmd, NULL, value);
+ if (retval != ERROR_OK)
+ LOG_ERROR("%s SWD write register failed", adi_cable_name());
+}
+
+static void ice1000_swd_read_reg(struct adiv5_dap *dap, uint8_t cmd, uint32_t *value)
+{
+ int retval;
+ retval = ice1000_swd_queue_cmd(dap, cmd, value, 0);
+ if (retval != ERROR_OK)
+ LOG_ERROR("%s SWD read register failed", adi_cable_name());
+}
+
+COMMAND_HANDLER(ice2000_handle_voltage_command)
+{
+ uint32_t voltage;
+
+ if (CMD_ARGC != 1)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], voltage);
+
+ if (voltage == 0 || voltage > 3)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ /* This command can only be used before adi_connect */
+ if (cable_params.usb_handle)
+ return ERROR_FAIL;
+
+ cable_params.cur_voltage = voltage;
+
+ return ERROR_OK;
+}
+
+static const struct swd_driver ice1000_swd = {
+ .init = ice1000_swd_init,
+ .frequency = ice1000_swd_frequency,
+ .switch_seq = ice1000_swd_switch_seq,
+ .read_reg = ice1000_swd_read_reg,
+ .write_reg = ice1000_swd_write_reg,
+ .run = ice1000_swd_run_queue,
+};
+
+struct jtag_interface ice1000_interface = {
+ .name = "ice1000",
+ .supported = DEBUG_CAP_TMS_SEQ,
+ .commands = NULL,
+ .transports = jtag_and_swd,
+ .swd = &ice1000_swd,
+
+ .init = ice1000_init,
+ .quit = ice1000_quit,
+ .speed = ice1000_speed,
+ .speed_div = ice1000_speed_div,
+ .khz = ice1000_khz,
+ .execute_queue = ice1000_execute_queue,
+};
+
+static const struct swd_driver ice2000_swd = {
+ .init = ice1000_swd_init,
+ .frequency = ice2000_swd_frequency,
+ .switch_seq = ice1000_swd_switch_seq,
+ .read_reg = ice1000_swd_read_reg,
+ .write_reg = ice1000_swd_write_reg,
+ .run = ice1000_swd_run_queue,
+};
+
+static const struct command_registration ice2000_command_handlers[] = {
+ {
+ .name = "ice2000_voltage",
+ .handler = &ice2000_handle_voltage_command,
+ .mode = COMMAND_CONFIG,
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
+struct jtag_interface ice2000_interface = {
+ .name = "ice2000",
+ .supported = DEBUG_CAP_TMS_SEQ,
+ .commands = ice2000_command_handlers,
+ .transports = jtag_and_swd,
+ .swd = &ice2000_swd,
+
+ .init = ice2000_init,
+ .quit = ice2000_quit,
+ .speed = ice2000_speed,
+ .speed_div = ice2000_speed_div,
+ .khz = ice2000_khz,
+ .execute_queue = ice1000_execute_queue,
+};
diff --git a/src/jtag/interface.h b/src/jtag/interface.h
index e7b2014..284659b 100644
--- a/src/jtag/interface.h
+++ b/src/jtag/interface.h
@@ -327,6 +327,7 @@ struct jtag_interface {
};
extern const char * const jtag_only[];
+extern const char * const jtag_and_swd[];
void adapter_assert_reset(void);
void adapter_deassert_reset(void);
diff --git a/src/jtag/interfaces.c b/src/jtag/interfaces.c
index 62c5d45..ee037ae 100644
--- a/src/jtag/interfaces.c
+++ b/src/jtag/interfaces.c
@@ -131,6 +131,12 @@ extern struct jtag_interface bcm2835gpio_interface;
#if BUILD_CMSIS_DAP == 1
extern struct jtag_interface cmsis_dap_interface;
#endif
+#ifdef BUILD_ICE_1000
+extern struct jtag_interface ice1000_interface;
+#endif
+#ifdef BUILD_ICE_2000
+extern struct jtag_interface ice2000_interface;
+#endif
#endif /* standard drivers */
/**
@@ -230,6 +236,12 @@ struct jtag_interface *jtag_interfaces[] = {
#if BUILD_CMSIS_DAP == 1
&cmsis_dap_interface,
#endif
+#if BUILD_ICE_1000 == 1
+ &ice1000_interface,
+#endif
+#if BUILD_ICE_2000 == 1
+ &ice2000_interface,
+#endif
#endif /* standard drivers */
NULL,
};
diff --git a/src/jtag/jtag.h b/src/jtag/jtag.h
index eda4ccd..2418a46 100644
--- a/src/jtag/jtag.h
+++ b/src/jtag/jtag.h
@@ -231,6 +231,7 @@ int jtag_unregister_event_callback(jtag_event_handler_t f, void *x);
int jtag_call_event_callbacks(enum jtag_event event);
+const char *jtag_get_name(void);
/** @returns The current JTAG speed setting. */
int jtag_get_speed(int *speed);
diff --git a/src/openocd.c b/src/openocd.c
index d17af20..f121dd3 100644
--- a/src/openocd.c
+++ b/src/openocd.c
@@ -48,7 +48,7 @@
#endif
#define OPENOCD_VERSION \
- "Open On-Chip Debugger " VERSION RELSTR " (" PKGBLDDATE ")"
+ "Open On-Chip Debugger " PKGVERSION VERSION
static const char openocd_startup_tcl[] = {
#include "startup_tcl.inc"
@@ -184,6 +184,16 @@ COMMAND_HANDLER(handle_add_script_search_dir_command)
return ERROR_OK;
}
+COMMAND_HANDLER(handle_firmware_command)
+{
+ if (CMD_ARGC != 1)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ set_firmware_filename(CMD_ARGV[0]);
+
+ return ERROR_OK;
+}
+
static const struct command_registration openocd_command_handlers[] = {
{
.name = "version",
@@ -215,6 +225,12 @@ static const struct command_registration openocd_command_handlers[] = {
.help = "dir to search for config files and scripts",
.usage = "<directory>"
},
+ {
+ .name = "firmware",
+ .handler = &handle_firmware_command,
+ .mode = COMMAND_CONFIG,
+ .help = "Set the firmware to be load.",
+ },
COMMAND_REGISTRATION_DONE
};
@@ -327,9 +343,7 @@ int openocd_main(int argc, char *argv[])
if (ioutil_init(cmd_ctx) != ERROR_OK)
return EXIT_FAILURE;
- LOG_OUTPUT("For bug reports, read\n\t"
- "http://openocd.org/doc/doxygen/bugs.html"
- "\n");
+ LOG_OUTPUT("Report bugs to %s\n", REPORT_BUGS_TO);
command_context_mode(cmd_ctx, COMMAND_CONFIG);
command_set_output_handler(cmd_ctx, configuration_output_handler, NULL);
diff --git a/src/pld/pld.c b/src/pld/pld.c
index fb5d32e..ced98f9 100644
--- a/src/pld/pld.c
+++ b/src/pld/pld.c
@@ -158,7 +158,7 @@ COMMAND_HANDLER(handle_pld_load_command)
gettimeofday(&end, NULL);
timeval_subtract(&duration, &end, &start);
- command_print(CMD_CTX, "loaded file %s to pld device %u in %jis %jius",
+ command_print(CMD_CTX, "loaded file %s to pld device %u in %"PRIjd"s %"PRIjd"us",
CMD_ARGV[1], dev_id,
(intmax_t)duration.tv_sec, (intmax_t)duration.tv_usec);
}
diff --git a/src/rtos/rtos.c b/src/rtos/rtos.c
index 3420d06..15b536a 100644
--- a/src/rtos/rtos.c
+++ b/src/rtos/rtos.c
@@ -359,8 +359,9 @@ int rtos_thread_packet(struct connection *connection, char const *packet, int pa
gdb_put_packet(connection, out_str, strlen(out_str));
free(out_str);
}
- } else
- gdb_put_packet(connection, "l", 1);
+ } else {
+ gdb_put_packet(connection, "m1", 2);
+ }
return ERROR_OK;
} else if (strncmp(packet, "qsThreadInfo", 12) == 0) {
@@ -384,7 +385,7 @@ int rtos_thread_packet(struct connection *connection, char const *packet, int pa
size = snprintf(buffer, 19, "QC%016" PRIx64, target->rtos->current_thread);
gdb_put_packet(connection, buffer, size);
} else
- gdb_put_packet(connection, "QC0", 3);
+ gdb_put_packet(connection, "QC1", 3);
return ERROR_OK;
} else if (packet[0] == 'T') { /* Is thread alive? */
threadid_t threadid;
@@ -399,7 +400,7 @@ int rtos_thread_packet(struct connection *connection, char const *packet, int pa
}
}
}
- if (found != -1)
+ if (found != -1 || target->rtos == NULL)
gdb_put_packet(connection, "OK", 2); /* thread alive */
else
gdb_put_packet(connection, "E01", 3); /* thread not found */
diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c
index 4a33a30..63cf796 100644
--- a/src/server/gdb_server.c
+++ b/src/server/gdb_server.c
@@ -80,11 +80,6 @@ struct gdb_connection {
* 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.
@@ -832,6 +827,8 @@ static void gdb_fileio_reply(struct target *target, struct connection *connectio
sprintf(fileio_command, "F%s,%" PRIx32 "/%" PRIx32, target->fileio_info->identifier,
target->fileio_info->param_1,
target->fileio_info->param_2);
+ else if (strcmp(target->fileio_info->identifier, "signal") == 0)
+ sprintf(fileio_command, "T%02x", target->fileio_info->param_1);
else if (strcmp(target->fileio_info->identifier, "exit") == 0) {
/* If target hits exit syscall, report to GDB the program is terminated.
* In addition, let target run its own exit syscall handler. */
@@ -842,7 +839,12 @@ static void gdb_fileio_reply(struct target *target, struct connection *connectio
/* encounter unknown syscall, continue */
gdb_connection->frontend_state = TARGET_RUNNING;
- target_resume(target, 1, 0x0, 0, 0);
+
+ if (gdb_running_type == 'c')
+ target_resume(target, 1, 0x0, 1, 0);
+ else if (gdb_running_type == 's')
+ target_step(target, 1, 0x0, 0);
+
return;
}
@@ -932,7 +934,6 @@ static int gdb_new_connection(struct connection *connection)
gdb_connection->busy = 0;
gdb_connection->noack_mode = 0;
gdb_connection->sync = false;
- gdb_connection->mem_write_error = false;
gdb_connection->attached = true;
gdb_connection->target_desc.tdesc = NULL;
gdb_connection->target_desc.tdesc_length = 0;
@@ -966,6 +967,12 @@ static int gdb_new_connection(struct connection *connection)
gdb_putback_char(connection, initial_ack);
target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_ATTACH);
+ /* If target is halted, e.g. there is a halt command in gdb-attach
+ * event in the config file, we don't need sync.
+ */
+ if (gdb_service->target->state == TARGET_HALTED)
+ gdb_connection->sync = false;
+
if (gdb_use_memory_map) {
/* Connect must fail if the memory map can't be set up correctly.
*
@@ -1490,31 +1497,20 @@ static int gdb_write_memory_binary_packet(struct connection *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;
+ }
+
+ if (retval != ERROR_OK)
+ {
+ LOG_ERROR("Memory write failure!");
+ gdb_put_packet(connection, "E00", 3);
+ }
+ else
+ {
+ gdb_put_packet(connection, "OK", 2);
}
return ERROR_OK;
@@ -1539,7 +1535,7 @@ static int gdb_step_continue_packet(struct connection *connection,
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);
+ retval = target_resume(target, current, address, 1, 0);
} else if (packet[0] == 's') {
LOG_DEBUG("step");
/* step at current or address, don't handle breakpoints */
@@ -2591,7 +2587,7 @@ static int gdb_fileio_response_packet(struct connection *connection,
/* After File-I/O ends, keep continue or step */
if (gdb_running_type == 'c')
- retval = target_resume(target, 1, 0x0, 0, 0);
+ retval = target_resume(target, 1, 0x0, 1, 0);
else if (gdb_running_type == 's')
retval = target_step(target, 1, 0x0, 0);
else
@@ -2717,14 +2713,6 @@ static int gdb_input_inner(struct connection *connection)
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) {
diff --git a/src/server/server.c b/src/server/server.c
index 7e90d89..0ce5c9c 100644
--- a/src/server/server.c
+++ b/src/server/server.c
@@ -443,27 +443,6 @@ int server_loop(struct command_context *command_context)
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;
@@ -489,6 +468,27 @@ int server_loop(struct command_context *command_context)
c = c->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);
+ }
+ }
}
#ifdef _WIN32
@@ -540,6 +540,8 @@ int server_preinit(void)
SetConsoleCtrlHandler(ControlHandler, TRUE);
signal(SIGBREAK, sig_handler);
+#else
+ signal(SIGHUP, sig_handler);
#endif
signal(SIGINT, sig_handler);
signal(SIGTERM, sig_handler);
diff --git a/src/svf/svf.c b/src/svf/svf.c
index cf0cfae..e03fd94 100644
--- a/src/svf/svf.c
+++ b/src/svf/svf.c
@@ -532,7 +532,7 @@ COMMAND_HANDLER(handle_svf_command)
time_measure_s %= 60;
if (time_measure_ms < 1000)
command_print(CMD_CTX,
- "\r\nTime used: %dm%ds%lldms ",
+ "\r\nTime used: %dm%ds%"PRIlld"ms ",
time_measure_m,
time_measure_s,
time_measure_ms);
diff --git a/src/target/Makefile.am b/src/target/Makefile.am
index 2cec491..80ee5ea 100644
--- a/src/target/Makefile.am
+++ b/src/target/Makefile.am
@@ -36,6 +36,7 @@ libtarget_la_SOURCES = \
$(MIPS32_SRC) \
$(NDS32_SRC) \
$(INTEL_IA32_SRC) \
+ $(BLACKFIN_SRC) \
avrt.c \
dsp563xx.c \
dsp563xx_once.c \
@@ -50,7 +51,8 @@ TARGET_CORE_SRC = \
target.c \
target_request.c \
testee.c \
- smp.c
+ smp.c \
+ xml_support.c
ARMV4_5_SRC = \
armv4_5.c \
@@ -82,7 +84,8 @@ ARMV7_SRC = \
armv7m_trace.c \
cortex_m.c \
armv7a.c \
- cortex_a.c
+ cortex_a.c \
+ cortex_a_memory_map.c
ARM_DEBUG_SRC = \
arm_dpm.c \
@@ -106,6 +109,14 @@ AVR32_SRC = \
avr32_mem.c \
avr32_regs.c
+BLACKFIN_SRC = \
+ blackfin.c \
+ blackfin_config.c \
+ blackfin_insn.c \
+ blackfin_jtag.c \
+ blackfin_mem.c \
+ blackfin_memory_map.c
+
MIPS32_SRC = \
mips32.c \
mips_m4k.c \
@@ -157,12 +168,19 @@ noinst_HEADERS = \
armv7m.h \
armv7m_trace.h \
avrt.h \
+ blackfin.h \
+ blackfin_config.h \
+ blackfin_insn.h \
+ blackfin_jtag.h \
+ blackfin_mem.h \
+ blackfin_memory_map.h \
dsp563xx.h \
dsp563xx_once.h \
dsp5680xx.h \
breakpoints.h \
cortex_m.h \
cortex_a.h \
+ cortex_a_memory_map.h \
embeddedice.h \
etb.h \
etm.h \
@@ -199,7 +217,8 @@ noinst_HEADERS = \
nds32_v3m.h \
nds32_aice.h \
lakemont.h \
- x86_32_common.h
+ x86_32_common.h \
+ xml_support.h
ocddatadir = $(pkglibdir)
nobase_dist_ocddata_DATA =
diff --git a/src/target/adi_v5_jtag.c b/src/target/adi_v5_jtag.c
index c1e1286..3f6f9be 100644
--- a/src/target/adi_v5_jtag.c
+++ b/src/target/adi_v5_jtag.c
@@ -115,8 +115,6 @@ static int adi_jtag_dp_scan(struct adiv5_dap *dap,
* 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);
diff --git a/src/target/arm.h b/src/target/arm.h
index 27636cc..25227df 100644
--- a/src/target/arm.h
+++ b/src/target/arm.h
@@ -40,6 +40,11 @@
* support has not yet been integrated, affecting Cortex-M parts.
*/
+enum {
+ ARM_SP = 13,
+ ARM_PC = 15,
+};
+
/**
* Represent state of an ARM core.
*
@@ -131,9 +136,27 @@ struct arm {
/** Flag reporting whether semihosting is active. */
bool is_semihosting;
+ /** Flag reporting whether continue/step hits syscall or not. */
+ bool hit_syscall;
+
/** Value to be returned by semihosting SYS_ERRNO request. */
int semihosting_errno;
+ /** Flag reporting whether syscall is aborted. */
+ bool semihosting_ctrl_c;
+
+ /** Record syscall ID for other operations to do special processing for target. */
+ uint32_t active_syscall_id;
+
+ /** Semihosting result for some specific ARM system calls. */
+ uint32_t semihosting_result;
+
+ /** Values to be set by semihosting SYS_HEAPINFO operation. */
+ uint32_t heap_base;
+ uint32_t heap_limit;
+ uint32_t stack_base;
+ uint32_t stack_limit;
+
int (*setup_semihosting)(struct target *target, int enable);
/** Backpointer to the target. */
diff --git a/src/target/arm7_9_common.c b/src/target/arm7_9_common.c
index 617ee78..9b40bd1 100644
--- a/src/target/arm7_9_common.c
+++ b/src/target/arm7_9_common.c
@@ -829,9 +829,6 @@ int arm7_9_poll(struct target *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;
diff --git a/src/target/arm_adi_v5.c b/src/target/arm_adi_v5.c
index f7e58d0..09904db 100644
--- a/src/target/arm_adi_v5.c
+++ b/src/target/arm_adi_v5.c
@@ -77,6 +77,7 @@
#include "arm_adi_v5.h"
#include <helper/time_support.h>
+#if 0
/* ARM ADI Specification requires at least 10 bits used for TAR autoincrement */
/*
@@ -87,6 +88,7 @@ static uint32_t max_tar_block_size(uint32_t tar_autoincr_block, uint32_t address
{
return tar_autoincr_block - ((tar_autoincr_block - 1) & address);
}
+#endif
/***************************************************************************
* *
@@ -333,7 +335,7 @@ int mem_ap_write(struct adiv5_dap *dap, const uint8_t *buffer, uint32_t size, ui
while (nbytes > 0) {
uint32_t this_size = size;
-
+#if 0
/* Select packed transfer if possible */
if (addrinc && dap->packed_transfers && nbytes >= 4
&& max_tar_block_size(dap->tar_autoincr_block, address) >= 4) {
@@ -342,7 +344,9 @@ int mem_ap_write(struct adiv5_dap *dap, const uint8_t *buffer, uint32_t size, ui
} else {
retval = dap_setup_accessport_csw(dap, csw_size | csw_addrincr);
}
-
+#else
+ retval = dap_setup_accessport_csw(dap, csw_size | csw_addrincr);
+#endif
if (retval != ERROR_OK)
break;
@@ -395,6 +399,21 @@ int mem_ap_write(struct adiv5_dap *dap, const uint8_t *buffer, uint32_t size, ui
if (retval == ERROR_OK)
retval = dap_run(dap);
+ if (addrinc) {
+ uint32_t tar;
+ retval = dap_queue_ap_read(dap, AP_REG_TAR, &tar);
+ if (retval == ERROR_OK)
+ retval = dap_run(dap);
+ if (retval != ERROR_OK)
+ return retval;
+ /* Update TAR to reflect incremented address */
+ dap->ap_tar_value = tar;
+#if 0
+ if (tar != address)
+ LOG_ERROR("TAR auto-increment does not work");
+#endif
+ }
+
if (retval != ERROR_OK) {
uint32_t tar;
if (dap_queue_ap_read(dap, AP_REG_TAR, &tar) == ERROR_OK
@@ -468,7 +487,7 @@ int mem_ap_read(struct adiv5_dap *dap, uint8_t *buffer, uint32_t size, uint32_t
* and alignment. */
while (nbytes > 0) {
uint32_t this_size = size;
-
+#if 0
/* Select packed transfer if possible */
if (addrinc && dap->packed_transfers && nbytes >= 4
&& max_tar_block_size(dap->tar_autoincr_block, address) >= 4) {
@@ -477,6 +496,9 @@ int mem_ap_read(struct adiv5_dap *dap, uint8_t *buffer, uint32_t size, uint32_t
} else {
retval = dap_setup_accessport_csw(dap, csw_size | csw_addrincr);
}
+#else
+ retval = dap_setup_accessport_csw(dap, csw_size | csw_addrincr);
+#endif
if (retval != ERROR_OK)
break;
@@ -498,34 +520,47 @@ int mem_ap_read(struct adiv5_dap *dap, uint8_t *buffer, uint32_t size, uint32_t
if (retval == ERROR_OK)
retval = dap_run(dap);
+ if (addrinc) {
+ uint32_t tar;
+ retval = dap_queue_ap_read(dap, AP_REG_TAR, &tar);
+ if (retval == ERROR_OK)
+ retval = dap_run(dap);
+ if (retval != ERROR_OK)
+ return retval;
+ /* Update TAR to reflect incremented address */
+ dap->ap_tar_value = tar;
+#if 0
+ if (tar != address)
+ LOG_ERROR("TAR auto-increment does not work");
+#endif
+ }
+
/* Restore state */
address = adr;
nbytes = size * count;
read_ptr = read_buf;
- /* If something failed, read TAR to find out how much data was successfully read, so we can
- * at least give the caller what we have. */
+ /* If something failed, read TAR to find out how much data was successfully read. */
if (retval != ERROR_OK) {
uint32_t tar;
if (dap_queue_ap_read(dap, AP_REG_TAR, &tar) == ERROR_OK
- && dap_run(dap) == ERROR_OK) {
+ && dap_run(dap) == ERROR_OK)
LOG_ERROR("Failed to read memory at 0x%08"PRIx32, tar);
- if (nbytes > tar - address)
- nbytes = tar - address;
- } else {
+ else
LOG_ERROR("Failed to read memory and, additionally, failed to find out where");
- nbytes = 0;
- }
+
+ nbytes = 0;
}
/* Replay loop to populate caller's buffer from the correct word and byte lane */
while (nbytes > 0) {
uint32_t this_size = size;
-
+#if 0
if (addrinc && dap->packed_transfers && nbytes >= 4
&& max_tar_block_size(dap->tar_autoincr_block, address) >= 4) {
this_size = 4;
}
+#endif
if (dap->ti_be_32_quirks) {
switch (this_size) {
@@ -663,6 +698,11 @@ int ahbap_debugport_init(struct adiv5_dap *dap)
*/
dap->ap_current = !0;
dap_ap_select(dap, 0);
+ /* Make sure CTRLSEL bit is cleared */
+ retval = dap_queue_dp_write(dap, DP_SELECT, 0);
+ if (retval != ERROR_OK)
+ return retval;
+
dap->last_read = NULL;
for (size_t i = 0; i < 10; i++) {
@@ -1576,6 +1616,98 @@ COMMAND_HANDLER(dap_apsel_command)
return retval;
}
+static int jim_dap_readmem(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) {
+ Jim_SetResultFormatted(goi.interp,
+ "usage: %s <ap> <address>", cmd_name);
+ return JIM_ERR;
+ }
+
+ int e;
+ jim_wide ap;
+ e = Jim_GetOpt_Wide(&goi, &ap);
+ if (e != JIM_OK)
+ return e;
+
+ jim_wide address;
+ e = Jim_GetOpt_Wide(&goi, &address);
+ if (e != JIM_OK)
+ return e;
+
+ /* all args must be consumed */
+ if (goi.argc != 0)
+ return JIM_ERR;
+
+ struct command_context *cmd_ctx = current_command_context(goi.interp);
+ struct target *target = get_current_target(cmd_ctx);
+ struct arm *arm = target_to_arm(target);
+ struct adiv5_dap *dap = arm->dap;
+
+ uint32_t value;
+ int retval;
+
+ retval = mem_ap_sel_read_atomic_u32(dap, (uint8_t)ap, (uint32_t)address, &value);
+ if (retval != ERROR_OK)
+ return JIM_ERR;
+
+ Jim_SetResult(goi.interp, Jim_NewIntObj(goi.interp, value));
+
+ return JIM_OK;
+}
+
+static int jim_dap_writemem(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 != 3) {
+ Jim_SetResultFormatted(goi.interp,
+ "usage: %s <ap> <address> <value>", cmd_name);
+ return JIM_ERR;
+ }
+
+ int e;
+ jim_wide ap;
+ e = Jim_GetOpt_Wide(&goi, &ap);
+ if (e != JIM_OK)
+ return e;
+
+ jim_wide address;
+ e = Jim_GetOpt_Wide(&goi, &address);
+ if (e != JIM_OK)
+ return e;
+
+ jim_wide value;
+ e = Jim_GetOpt_Wide(&goi, &value);
+ if (e != JIM_OK)
+ return e;
+
+ /* all args must be consumed */
+ if (goi.argc != 0)
+ return JIM_ERR;
+
+ struct command_context *cmd_ctx = current_command_context(goi.interp);
+ struct target *target = get_current_target(cmd_ctx);
+ struct arm *arm = target_to_arm(target);
+ struct adiv5_dap *dap = arm->dap;
+
+ int retval;
+
+ retval = mem_ap_sel_write_atomic_u32(dap, (uint8_t)ap, (uint32_t)address, (uint32_t)value);
+ if (retval != ERROR_OK)
+ return JIM_ERR;
+
+ return JIM_OK;
+}
+
COMMAND_HANDLER(dap_apcsw_command)
{
struct target *target = get_current_target(CMD_CTX);
@@ -1722,6 +1854,20 @@ static const struct command_registration dap_commands[] = {
.usage = "[cycles]",
},
{
+ .name = "readmem",
+ .jim_handler = jim_dap_readmem,
+ .mode = COMMAND_EXEC,
+ .help = "read memory using MEM-AP",
+ .usage = "ap address",
+ },
+ {
+ .name = "writemem",
+ .jim_handler = jim_dap_writemem,
+ .mode = COMMAND_EXEC,
+ .help = "write memory using MEM-AP",
+ .usage = "ap address value",
+ },
+ {
.name = "ti_be_32_quirks",
.handler = dap_ti_be_32_quirks_command,
.mode = COMMAND_CONFIG,
diff --git a/src/target/arm_adi_v5.h b/src/target/arm_adi_v5.h
index 8d12608..00d4585 100644
--- a/src/target/arm_adi_v5.h
+++ b/src/target/arm_adi_v5.h
@@ -219,6 +219,9 @@ struct adiv5_dap {
* should be performed before the next access.
*/
bool do_reconnect;
+
+ uint32_t ahb_mem_start_address;
+ uint32_t ahb_mem_end_address;
};
/**
diff --git a/src/target/arm_dpm.c b/src/target/arm_dpm.c
index 5df625f..9824006 100644
--- a/src/target/arm_dpm.c
+++ b/src/target/arm_dpm.c
@@ -264,6 +264,16 @@ int arm_dpm_read_current_registers(struct arm_dpm *dpm)
/* update core mode and state, plus shadow mapping for R8..R14 */
arm_set_cpsr(arm, cpsr);
+ if (arm->spsr) {
+ uint32_t spsr;
+ retval = dpm->instr_read_data_r0(dpm, ARMV4_5_MRS(0, 1), &spsr);
+ if (retval != ERROR_OK)
+ goto fail;
+ buf_set_u32(arm->spsr->value, 0, 32, spsr);
+ arm->spsr->dirty = 0;
+ arm->spsr->valid = 1;
+ }
+
/* REVISIT we can probably avoid reading R1..R14, saving time... */
for (unsigned i = 1; i < 16; i++) {
r = arm_reg_current(arm, i);
@@ -871,6 +881,22 @@ static int dpm_remove_watchpoint(struct target *target, struct watchpoint *wp)
return retval;
}
+static int dpm_hit_watchpoint(struct target *target, struct watchpoint **hit_watchpoint)
+{
+ struct arm *arm = target_to_arm(target);
+ struct arm_dpm *dpm = arm->dpm;
+
+ for (unsigned i = 0; i < dpm->nwp; i++) {
+ /* since we only support only 1 watchpoint, no need for matching */
+ if (dpm->dwp[i].wp) {
+ *hit_watchpoint = dpm->dwp[i].wp;
+ return ERROR_OK;
+ }
+ }
+
+ return ERROR_FAIL;
+}
+
void arm_dpm_report_wfar(struct arm_dpm *dpm, uint32_t addr)
{
switch (dpm->arm->core_state) {
@@ -902,20 +928,20 @@ void arm_dpm_report_dscr(struct arm_dpm *dpm, uint32_t dscr)
/* Examine debug reason */
switch (DSCR_ENTRY(dscr)) {
- case 6: /* Data abort (v6 only) */
- case 7: /* Prefetch abort (v6 only) */
+ case DSCR_ENTRY_D_SIDE_ABORT: /* v6 only */
+ case DSCR_ENTRY_I_SIDE_ABORT: /* v6 only */
/* FALL THROUGH -- assume a v6 core in abort mode */
- case 0: /* HALT request from debugger */
- case 4: /* EDBGRQ */
+ case DSCR_ENTRY_HALT_REQ:
+ case DSCR_ENTRY_EXT_DBG_REQ:
target->debug_reason = DBG_REASON_DBGRQ;
break;
- case 1: /* HW breakpoint */
- case 3: /* SW BKPT */
- case 5: /* vector catch */
+ case DSCR_ENTRY_BREAKPOINT:
+ case DSCR_ENTRY_BKPT_INSTR:
+ case DSCR_ENTRY_VECT_CATCH:
target->debug_reason = DBG_REASON_BREAKPOINT;
break;
- case 2: /* asynch watchpoint */
- case 10:/* precise watchpoint */
+ case DSCR_ENTRY_IMPRECISE_WATCHPT:
+ case DSCR_ENTRY_PRECISE_WATCHPT:
target->debug_reason = DBG_REASON_WATCHPOINT;
break;
default:
@@ -968,6 +994,7 @@ int arm_dpm_setup(struct arm_dpm *dpm)
/* watchpoint setup */
target->type->add_watchpoint = dpm_add_watchpoint;
target->type->remove_watchpoint = dpm_remove_watchpoint;
+ target->type->hit_watchpoint = dpm_hit_watchpoint;
/* FIXME add vector catch support */
@@ -985,6 +1012,10 @@ int arm_dpm_setup(struct arm_dpm *dpm)
LOG_INFO("%s: hardware has %d breakpoints, %d watchpoints",
target_name(target), dpm->nbp, dpm->nwp);
+ if (dpm->nwp > 1) {
+ dpm->nwp = 1;
+ LOG_INFO("%s: but you can only set 1 watchpoint", target_name(target));
+ }
/* REVISIT ... and some of those breakpoints could match
* execution context IDs...
diff --git a/src/target/arm_dpm.h b/src/target/arm_dpm.h
index 73ed1bc..090bdab 100644
--- a/src/target/arm_dpm.h
+++ b/src/target/arm_dpm.h
@@ -173,16 +173,16 @@ void arm_dpm_report_wfar(struct arm_dpm *, uint32_t wfar);
/* 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)
+#define DSCR_ENTRY_HALT_REQ 0x0
+#define DSCR_ENTRY_BREAKPOINT 0x1
+#define DSCR_ENTRY_IMPRECISE_WATCHPT 0x2
+#define DSCR_ENTRY_BKPT_INSTR 0x3
+#define DSCR_ENTRY_EXT_DBG_REQ 0x4
+#define DSCR_ENTRY_VECT_CATCH 0x5
+#define DSCR_ENTRY_D_SIDE_ABORT 0x6 /* v6 only */
+#define DSCR_ENTRY_I_SIDE_ABORT 0x7 /* v6 only */
+#define DSCR_ENTRY_OS_UNLOCK 0x8
+#define DSCR_ENTRY_PRECISE_WATCHPT 0xA
/* DTR modes */
#define DSCR_EXT_DCC_NON_BLOCKING (0x0 << 20)
diff --git a/src/target/arm_semihosting.c b/src/target/arm_semihosting.c
index 21b7809..cb73848 100644
--- a/src/target/arm_semihosting.c
+++ b/src/target/arm_semihosting.c
@@ -41,6 +41,7 @@
#include "armv4_5.h"
#include "arm7_9_common.h"
#include "armv7m.h"
+#include "armv7a.h"
#include "cortex_m.h"
#include "register.h"
#include "arm_semihosting.h"
@@ -48,267 +49,477 @@
#include <helper/log.h>
#include <sys/stat.h>
-static const 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)
+/* We will need a temporary workspace for SYS_FLEN and SYS_TIME. */
+#define ARM_SEMIHOSTING_TEMP_BUFFER_SIZE 128
+static uint8_t arm_semihosting_temp_buffer[ARM_SEMIHOSTING_TEMP_BUFFER_SIZE];
+static uint32_t arm_semihosting_work_addr;
+
+/**
+ * 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)
+{
+ struct arm *arm = target_to_arm(target);
+ uint32_t pc, lr, spsr;
+ struct reg *r;
+ int retval;
+
+ if (!arm->is_semihosting)
+ return 0;
+
+ if (is_arm7_9(target_to_arm7_9(target))
+ || is_armv7a(target_to_armv7a(target))) {
+ uint32_t vector_base;
+
+ if (arm->core_mode != ARM_MODE_SVC)
+ return 0;
+
+ /* MRC p15,0,<Rt>,c12,c0,0 ; Read Vector Base Register */
+ retval = arm->mrc(target, 15,
+ 0, 0, /* op1, op2 */
+ 12, 0, /* CRn, CRm */
+ &vector_base);
+ if (retval != ERROR_OK)
+ return 1;
+
+ /* Check Supervisor Call vector. */
+ r = arm->pc;
+ pc = buf_get_u32(r->value, 0, 32);
+ /* TODO We should check DBGVCR.V */
+ if (pc != vector_base + 0x8 && 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!");
+ return 0;
+ }
+
+ 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 0;
+ 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 0;
+ 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 0;
+
+ /* bkpt 0xAB */
+ if (insn != 0xBEAB)
+ return 0;
+ } else {
+ LOG_ERROR("Unsupported semi-hosting Target");
+ return 0;
+ }
+
+ return 1;
+}
+
+void arm_semihosting_step_over_svc(struct target *target)
+{
+ struct arm *arm = target_to_arm(target);
+
+ if (is_arm7_9(target_to_arm7_9(target))
+ || is_armv7a(target_to_armv7a(target))) {
+ uint32_t spsr, lr;
+
+ /* LR --> PC */
+ lr = buf_get_u32(arm_reg_current(arm, 14)->value, 0, 32);
+ buf_set_u32(arm->core_cache->reg_list[15].value, 0, 32, lr);
+ 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;
+
+ }
+}
+
+void arm_semihosting_step_over_bkpt(struct target *target)
+{
+ struct arm *arm = target_to_arm(target);
+
+ if (is_armv7m(target_to_armv7m(target))) {
+ uint32_t pc;
+
+ /* resume execution, this will be pc+2 to skip over the
+ * bkpt instruction */
+ pc = buf_get_u32(arm->pc->value, 0, 32);
+ buf_set_u32(arm->core_cache->reg_list[15].value, 0, 32, pc + 2);
+ arm->core_cache->reg_list[15].dirty = 1;
+ }
+}
+
+#define GDB_FILEIO_O_RDONLY 0x0
+#define GDB_FILEIO_O_WRONLY 0x1
+#define GDB_FILEIO_O_RDWR 0x2
+#define GDB_FILEIO_O_APPEND 0x8
+#define GDB_FILEIO_O_CREAT 0x200
+#define GDB_FILEIO_O_TRUNC 0x400
+#define GDB_FILEIO_O_EXCL 0x800
+
+#define GDB_FILEIO_S_IFREG 0100000
+#define GDB_FILEIO_S_IFDIR 040000
+#define GDB_FILEIO_S_IRUSR 0400
+#define GDB_FILEIO_S_IWUSR 0200
+#define GDB_FILEIO_S_IXUSR 0100
+#define GDB_FILEIO_S_IRGRP 040
+#define GDB_FILEIO_S_IWGRP 020
+#define GDB_FILEIO_S_IXGRP 010
+#define GDB_FILEIO_S_IROTH 04
+#define GDB_FILEIO_S_IWOTH 02
+#define GDB_FILEIO_S_IXOTH 01
+
+int arm_get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *fileio_info)
{
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.
- */
+ int retval;
+
+ if (fileio_info == NULL) {
+ LOG_ERROR("Target has not initial file-I/O data structure");
+ return ERROR_FAIL;
+ }
+
+ if (!arm->hit_syscall)
+ return ERROR_FAIL;
+
+ arm->active_syscall_id = r0;
+
+ LOG_DEBUG("hit syscall ID: 0x%x", r0);
+
+ /* free previous identifier storage */
+ if (NULL != fileio_info->identifier) {
+ free(fileio_info->identifier);
+ fileio_info->identifier = NULL;
+ }
+
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;
+
+ /* pointer to path string */
+ fileio_info->param_1 = target_buffer_get_u32(target, params+0);
+ /* length of path string */
+ fileio_info->param_2 = target_buffer_get_u32(target, params+8) + 1;
+ /* flags */
+ fileio_info->param_3 = target_buffer_get_u32(target, params+4);
+ /* mode */
+ fileio_info->param_4 = 0;
+
+ if (fileio_info->param_2 == 4) {
+ uint8_t fn[4];
+ int fd = -1;
+
+ retval = target_read_memory(target, fileio_info->param_1, 1, 4, fn);
+ if (retval != ERROR_OK)
+ return retval;
+
+ if (fn[0] == ':' && fn[1] == 't' && fn[2] == 't' && fn[3] == '\0') {
+ if (fileio_info->param_3 == 0)
+ fd = 0;
+ else if (fileio_info->param_3 == 4)
+ fd = 1;
+ else if (fileio_info->param_3 == 8)
+ fd = 2;
+ }
+
+ if (fd >= 0) {
+ buf_set_u32(arm->core_cache->reg_list[0].value, 0, 32, fd);
+ arm->core_cache->reg_list[0].dirty = 1;
+
+ fileio_info->identifier = (char *)malloc(8);
+ sprintf(fileio_info->identifier, "open012");
+ break;
}
}
+
+ uint32_t flags = fileio_info->param_3;
+ fileio_info->param_3 = 0;
+ if (flags & 2)
+ fileio_info->param_3 |= GDB_FILEIO_O_RDWR;
+ if (flags & 4)
+ fileio_info->param_3 |= GDB_FILEIO_O_CREAT | GDB_FILEIO_O_TRUNC;
+ if ((flags & 4) && !(flags & 2))
+ fileio_info->param_3 |= GDB_FILEIO_O_WRONLY;
+ if (flags & 8)
+ fileio_info->param_3 |= GDB_FILEIO_O_APPEND;
+
+ /* if O_CREAT, hard code mode to S_IRUSR | S_IWUSR */
+ if (fileio_info->param_3 & GDB_FILEIO_O_CREAT)
+ fileio_info->param_4 = GDB_FILEIO_S_IRUSR | GDB_FILEIO_S_IWUSR;
+
+ fileio_info->identifier = malloc(5);
+ sprintf(fileio_info->identifier, "open");
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;
- }
+
+ /* fd */
+ fileio_info->param_1 = target_buffer_get_u32(target, params+0);
+
+ fileio_info->identifier = malloc(6);
+ sprintf(fileio_info->identifier, "close");
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;
- }
+ /* fd, use stdout */
+ fileio_info->param_1 = 1;
+ /* pointer to buffer */
+ fileio_info->param_2 = r1;
+ /* count */
+ fileio_info->param_3 = 1;
+
+ arm->semihosting_result = fileio_info->param_3;
+
+ fileio_info->identifier = malloc(6);
+ sprintf(fileio_info->identifier, "write");
break;
case 0x04: /* SYS_WRITE0 */
+ /* fd, use stdout */
+ fileio_info->param_1 = 1;
+ /* pointer to buffer */
+ fileio_info->param_2 = r1;
+ /* count */
do {
- unsigned char c;
- retval = target_read_memory(target, r1++, 1, 1, &c);
+ retval = target_read_memory(target, r1, 1, 1, params);
if (retval != ERROR_OK)
return retval;
- if (!c)
- break;
- putchar(c);
- } while (1);
- result = 0;
+ r1++;
+ } while (params[0]);
+ fileio_info->param_3 = r1 - fileio_info->param_2;
+
+ arm->semihosting_result = fileio_info->param_3;
+
+ fileio_info->identifier = malloc(6);
+ sprintf(fileio_info->identifier, "write");
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);
- }
- }
+
+ /* fd */
+ fileio_info->param_1 = target_buffer_get_u32(target, params+0);
+ /* pointer to buffer */
+ fileio_info->param_2 = target_buffer_get_u32(target, params+4);
+ /* count */
+ fileio_info->param_3 = target_buffer_get_u32(target, params+8);
+
+ arm->semihosting_result = fileio_info->param_3;
+
+ fileio_info->identifier = malloc(6);
+ sprintf(fileio_info->identifier, "write");
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;
+ /* fd */
+ fileio_info->param_1 = target_buffer_get_u32(target, params+0);
+ /* pointer to buffer */
+ fileio_info->param_2 = target_buffer_get_u32(target, params+4);
+ /* count */
+ fileio_info->param_3 = target_buffer_get_u32(target, params+8);
- 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);
+ arm->semihosting_result = fileio_info->param_3;
+
+ fileio_info->identifier = malloc(5);
+ sprintf(fileio_info->identifier, "read");
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));
+
+ /* fd */
+ fileio_info->param_1 = target_buffer_get_u32(target, params+0);
+
+ fileio_info->identifier = (char *)malloc(7);
+ sprintf(fileio_info->identifier, "isatty");
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;
- }
+
+ /* fd */
+ fileio_info->param_1 = target_buffer_get_u32(target, params+0);
+ /* offset */
+ fileio_info->param_2 = target_buffer_get_u32(target, params+4);
+ /* flag */
+ fileio_info->param_3 = SEEK_SET;
+
+ fileio_info->identifier = (char *)malloc(6);
+ sprintf(fileio_info->identifier, "lseek");
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;
- }
+
+ /* fd */
+ fileio_info->param_1 = target_buffer_get_u32(target, params+0);
+ /* buf */
+ /* We use the stack for a temporary buffer. */
+ arm_semihosting_work_addr = buf_get_u32(arm_reg_current(arm, ARM_SP)->value, 0, 32);
+ arm_semihosting_work_addr -= ARM_SEMIHOSTING_TEMP_BUFFER_SIZE;
+ retval = target_read_memory(target, arm_semihosting_work_addr, 1,
+ ARM_SEMIHOSTING_TEMP_BUFFER_SIZE, arm_semihosting_temp_buffer);
+ if (retval != ERROR_OK)
+ return retval;
+
+ fileio_info->param_2 = arm_semihosting_work_addr;
+ fileio_info->identifier = (char *)malloc(6);
+ sprintf(fileio_info->identifier, "fstat");
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;
- }
- }
+
+ /* pointer to path string */
+ fileio_info->param_1 = target_buffer_get_u32(target, params+0);
+ /* length of path string */
+ fileio_info->param_2 = target_buffer_get_u32(target, params+4) + 1;
+
+ fileio_info->identifier = (char *)malloc(7);
+ sprintf(fileio_info->identifier, "unlink");
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;
- }
- }
+
+ /* pointer to old path string */
+ fileio_info->param_1 = target_buffer_get_u32(target, params+0);
+ /* length of old path string */
+ fileio_info->param_2 = target_buffer_get_u32(target, params+4) + 1;
+ /* pointer to new path string */
+ fileio_info->param_3 = target_buffer_get_u32(target, params+8);
+ /* length of new path string */
+ fileio_info->param_4 = target_buffer_get_u32(target, params+12) + 1;
+
+ fileio_info->identifier = (char *)malloc(7);
+ sprintf(fileio_info->identifier, "rename");
break;
case 0x11: /* SYS_TIME */
- result = time(NULL);
+ /* tv */
+ /* We use the stack for a temporary buffer. */
+ arm_semihosting_work_addr = buf_get_u32(arm_reg_current(arm, ARM_SP)->value, 0, 32);
+ arm_semihosting_work_addr -= ARM_SEMIHOSTING_TEMP_BUFFER_SIZE;
+ retval = target_read_memory(target, arm_semihosting_work_addr, 1,
+ ARM_SEMIHOSTING_TEMP_BUFFER_SIZE, arm_semihosting_temp_buffer);
+ if (retval != ERROR_OK)
+ return retval;
+ fileio_info->param_1 = arm_semihosting_work_addr;
+
+ /* tz */
+ fileio_info->param_2 = 0;
+
+ fileio_info->identifier = (char *)malloc(13);
+ sprintf(fileio_info->identifier, "gettimeofday");
+ break;
+
+ case 0x12: /* SYS_SYSTEM */
+ retval = target_read_memory(target, r1, 4, 2, params);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* pointer to the command string */
+ fileio_info->param_1 = target_buffer_get_u32(target, params+0);
+ /* length of the command string */
+ fileio_info->param_2 = target_buffer_get_u32(target, params+4) + 1;
+
+ fileio_info->identifier = (char *)malloc(7);
+ sprintf(fileio_info->identifier, "system");
break;
case 0x13: /* SYS_ERRNO */
- result = arm->semihosting_errno;
+ buf_set_u32(arm->core_cache->reg_list[0].value, 0, 32, arm->semihosting_errno);
+ arm->core_cache->reg_list[0].dirty = 1;
+
+ fileio_info->identifier = (char *)malloc(6);
+ sprintf(fileio_info->identifier, "errno");
break;
case 0x15: /* SYS_GET_CMDLINE */
@@ -321,13 +532,17 @@ static int do_semihosting(struct target *target)
char *arg = "foobar";
uint32_t s = strlen(arg) + 1;
if (l < s)
- result = -1;
- else {
- retval = target_write_buffer(target, a, s, (uint8_t *)arg);
- if (retval != ERROR_OK)
- return retval;
- result = 0;
- }
+ return ERROR_FAIL;
+
+ retval = target_write_buffer(target, a, s, (void *)arg);
+ if (retval != ERROR_OK)
+ return retval;
+
+ buf_set_u32(arm->core_cache->reg_list[0].value, 0, 32, 0);
+ arm->core_cache->reg_list[0].dirty = 1;
+
+ fileio_info->identifier = (char *)malloc(16);
+ sprintf(fileio_info->identifier, "get_commandline");
}
break;
@@ -337,22 +552,38 @@ static int do_semihosting(struct target *target)
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);
+ target_buffer_set_u32(target, params, arm->heap_base);
+ target_buffer_set_u32(target, params + 4, arm->heap_limit);
+ target_buffer_set_u32(target, params + 8, arm->stack_base);
+ target_buffer_set_u32(target, params + 12, arm->stack_limit);
retval = target_write_memory(target, a, 4, 4, params);
if (retval != ERROR_OK)
return retval;
- result = 0;
+
+ buf_set_u32(arm->core_cache->reg_list[0].value, 0, 32, 0);
+ arm->core_cache->reg_list[0].dirty = 1;
+
+ fileio_info->identifier = (char *)malloc(9);
+ sprintf(fileio_info->identifier, "heapinfo");
}
break;
case 0x18: /* angel_SWIreason_ReportException */
+ fprintf(stderr, "semihosting: exception %#x\n", (unsigned) r1);
+
switch (r1) {
case 0x20026: /* ADP_Stopped_ApplicationExit */
- fprintf(stderr, "semihosting: *** application exited ***\n");
+ /* exit status is not passed down */
+ target->fileio_info->param_1 = 0;
+ fileio_info->identifier = (char *)malloc(5);
+ sprintf(fileio_info->identifier, "exit");
+ return ERROR_OK;
+
+ case 0x20001: /* ADP_Stopped_UndefinedInstr */
+ target->fileio_info->param_1 = 4 /* SIGILL */;
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 */
@@ -362,197 +593,101 @@ static int do_semihosting(struct target *target)
case 0x20020: /* ADP_Stopped_BreakPoint */
case 0x20021: /* ADP_Stopped_WatchPoint */
case 0x20022: /* ADP_Stopped_StepComplete */
- case 0x20023: /* ADP_Stopped_RunTimeErrorUnknown */
+ case 0x20023: /* ADP_Stopped_RunTimeError */
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);
+ /* TODO find better signal for each cause */
+ target->fileio_info->param_1 = 6 /* SIGABRT */;
+ break;
}
- return target_call_event_callbacks(target, TARGET_EVENT_HALTED);
- case 0x12: /* SYS_SYSTEM */
- /* Provide SYS_SYSTEM functionality. Uses the
- * libc system command, there may be a reason *NOT*
- * to use this, but as I can't think of one, I
- * implemented it this way.
- */
- retval = target_read_memory(target, r1, 4, 2, params);
- if (retval != ERROR_OK)
- return retval;
- else {
- uint32_t len = target_buffer_get_u32(target, params+4);
- uint32_t c_ptr = target_buffer_get_u32(target, params);
- uint8_t cmd[256];
- if (len > 255) {
- result = -1;
- arm->semihosting_errno = EINVAL;
- } else {
- memset(cmd, 0x0, 256);
- retval = target_read_memory(target, c_ptr, 1, len, cmd);
- if (retval != ERROR_OK)
- return retval;
- else
- result = system((const char *)cmd);
- }
- }
+ fileio_info->identifier = (char *)malloc(7);
+ sprintf(fileio_info->identifier, "signal");
break;
+
+ case 0x07: /* SYS_READC */
case 0x0d: /* SYS_TMPNAM */
case 0x10: /* SYS_CLOCK */
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;
+ fileio_info->identifier = (char *)malloc(8);
+ sprintf(fileio_info->identifier, "unknown");
+ break;
}
- return target_resume(target, 1, 0, 0, 0);
+ return ERROR_OK;
}
-/**
- * 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)
+int arm_gdb_fileio_end(struct target *target, int retcode, int fileio_errno, bool ctrl_c)
{
- struct arm *arm = target_to_arm(target);
- uint32_t pc, lr, spsr;
- struct reg *r;
+ uint32_t result;
+ int retval;
- if (!arm->is_semihosting)
- return 0;
+ LOG_DEBUG("syscall return code: 0x%x, errno: 0x%x, ctrl_c: %s",
+ retcode, fileio_errno, ctrl_c ? "true" : "false");
- 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);
+ struct arm *arm = target_to_arm(target);
- /* 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;
- }
+ switch (arm->active_syscall_id) {
+ case 0x05: /* SYS_WRITE */
+ case 0x06: /* SYS_READ */
+ if (retcode >= 0)
+ result = arm->semihosting_result - retcode;
+ else
+ result = arm->semihosting_result;
+ break;
+ case 0x0c: /* SYS_FLEN */
+ case 0x11: /* SYS_TIME */
+ result = arm->semihosting_result;
+ retval = target_write_memory(target, arm_semihosting_work_addr, 1,
+ ARM_SEMIHOSTING_TEMP_BUFFER_SIZE, arm_semihosting_temp_buffer);
+ if (retval != ERROR_OK)
+ return retval;
+ break;
+ default:
+ result = retcode;
+ }
- spsr = buf_get_u32(arm->spsr->value, 0, 32);
+ buf_set_u32(arm->core_cache->reg_list[0].value, 0, 32, result);
+ arm->core_cache->reg_list[0].dirty = 1;
- /* check instruction that triggered this trap */
- if (spsr & (1 << 5)) {
- /* was in Thumb (or ThumbEE) mode */
- uint8_t insn_buf[2];
- uint16_t insn;
+ arm->semihosting_errno = fileio_errno;
+ arm->semihosting_ctrl_c = ctrl_c;
+ arm->active_syscall_id = 0;
- *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);
+ return ERROR_OK;
+}
- /* 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);
+int arm_gdb_fileio_pre_write_buffer(struct target *target, uint32_t address,
+ uint32_t size, const uint8_t *buffer)
+{
+ struct arm *arm = target_to_arm(target);
- /* SVC 0x123456 */
- if (insn != 0xEF123456)
- return 0;
+ if (arm->hit_syscall) {
+ if (arm->active_syscall_id == 0x0c /* SYS_FLEN */) {
+ /* If doing GDB file-I/O, target should convert 'struct stat'
+ from gdb-format to target-format.
+ And we are only interested in st_size. */
+ /* st_size 4 */
+ arm->semihosting_result = buffer[35] | (buffer[34] << 8) | (buffer[33] << 16) | (buffer[32] << 24);
+
+ return ERROR_OK;
+ } else if (arm->active_syscall_id == 0x11 /* SYS_TIME */) {
+ /* If doing GDB file-I/O, target should convert 'struct timeval'
+ from gdb-format to target-format.
+ And we are only interested in tv_sec. */
+ arm->semihosting_result = buffer[3] | (buffer[2] << 8) | (buffer[1] << 16) | (buffer[0] << 24);
+
+ return ERROR_OK;
}
- } 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;
+ return ERROR_FAIL;
}
diff --git a/src/target/arm_semihosting.h b/src/target/arm_semihosting.h
index 58b3432..db7cb13 100644
--- a/src/target/arm_semihosting.h
+++ b/src/target/arm_semihosting.h
@@ -21,6 +21,11 @@
#ifndef ARM_SEMIHOSTING_H
#define ARM_SEMIHOSTING_H
-int arm_semihosting(struct target *target, int *retval);
+int arm_semihosting(struct target *target);
+void arm_semihosting_step_over_svc(struct target *target);
+void arm_semihosting_step_over_bkpt(struct target *target);
+int arm_get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *fileio_info);
+int arm_gdb_fileio_end(struct target *target, int retcode, int fileio_errno, bool ctrl_c);
+int arm_gdb_fileio_pre_write_buffer(struct target *target, uint32_t address, uint32_t size, const uint8_t *buffer);
#endif
diff --git a/src/target/armv4_5.c b/src/target/armv4_5.c
index e75fe99..05c8d30 100644
--- a/src/target/armv4_5.c
+++ b/src/target/armv4_5.c
@@ -616,7 +616,10 @@ struct reg_cache *arm_build_reg_cache(struct target *target, struct arm *arm)
reg_list[i].exist = true;
/* This really depends on the calling convention in use */
- reg_list[i].caller_save = false;
+ if (reg_list[i].number < 16)
+ reg_list[i].caller_save = true;
+ else
+ reg_list[i].caller_save = false;
/* Registers data type, as used by GDB target description */
reg_list[i].reg_data_type = malloc(sizeof(struct reg_data_type));
@@ -1026,6 +1029,7 @@ COMMAND_HANDLER(handle_arm_semihosting_command)
if (CMD_ARGC > 0) {
int semihosting;
+ unsigned int i;
COMMAND_PARSE_ENABLE(CMD_ARGV[0], semihosting);
@@ -1041,6 +1045,21 @@ COMMAND_HANDLER(handle_arm_semihosting_command)
/* FIXME never let that "catch" be dropped! */
arm->is_semihosting = semihosting;
+
+ arm->heap_base = arm->heap_limit = 0;
+ arm->stack_base = arm->stack_limit = 0;
+ for (i = 1; i < CMD_ARGC; i++) {
+ if (strncasecmp ("heap_base=", CMD_ARGV[i], 10) == 0)
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[i] + 10, arm->heap_base);
+ else if (strncasecmp ("heap_limit=", CMD_ARGV[i], 11) == 0)
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[i] + 11, arm->heap_limit);
+ else if (strncasecmp ("stack_base=", CMD_ARGV[i], 11) == 0)
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[i] + 11, arm->stack_base);
+ else if (strncasecmp ("stack_limit=", CMD_ARGV[i], 12) == 0)
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[i] + 12, arm->stack_limit);
+ else
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
}
command_print(CMD_CTX, "semihosting is %s",
diff --git a/src/target/armv7a.c b/src/target/armv7a.c
index 170cfcc..7816370 100644
--- a/src/target/armv7a.c
+++ b/src/target/armv7a.c
@@ -208,7 +208,7 @@ int armv7a_mmu_translate_va(struct target *target, uint32_t va, uint32_t *val)
}
retval = dpm->prepare(dpm);
if (retval != ERROR_OK)
- goto done;
+ return retval;
/* MRC p15,0,<Rt>,c2,c0,ttb */
retval = dpm->instr_read_data_r0(dpm,
@@ -226,19 +226,19 @@ int armv7a_mmu_translate_va(struct target *target, uint32_t va, uint32_t *val)
/* 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) {
+ if ((first_lvl_descriptor & 0x3) == 0
+ || (first_lvl_descriptor & 0x3) == 3) {
LOG_ERROR("Address translation failure");
return ERROR_TARGET_TRANSLATION_FAULT;
}
-
if ((first_lvl_descriptor & 0x40002) == 2) {
/* section descriptor */
*val = (first_lvl_descriptor & 0xfff00000) | (va & 0x000fffff);
return ERROR_OK;
} else if ((first_lvl_descriptor & 0x40002) == 0x40002) {
/* supersection descriptor */
- if (first_lvl_descriptor & 0x00f001e0) {
+ if ((first_lvl_descriptor & 0x00f001e0) != 0) {
LOG_ERROR("Physical address does not fit into 32 bits");
return ERROR_TARGET_TRANSLATION_FAULT;
}
@@ -272,9 +272,6 @@ int armv7a_mmu_translate_va(struct target *target, uint32_t va, uint32_t *val)
}
return ERROR_OK;
-
-done:
- return retval;
}
/* V7 method VA TO PA */
@@ -453,6 +450,168 @@ static int armv7a_flush_all_data(struct target *target)
return retval;
}
+int armv7a_invalidate_instruction_cache(struct target *target,
+ uint32_t address, uint32_t size, uint32_t count)
+{
+ struct armv7a_common *armv7a = target_to_armv7a(target);
+ struct arm_dpm *dpm = armv7a->arm.dpm;
+ uint32_t cacheline_size = armv7a->armv7a_mmu.armv7a_cache.i_size.linelen;
+ int retval;
+
+ if (target->state != TARGET_HALTED) {
+ LOG_ERROR("target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ /* check that cache data is on at target halt */
+ if (!armv7a->armv7a_mmu.armv7a_cache.i_cache_enabled) {
+ LOG_DEBUG("instruction cache invalidation not performed : cache not on at target halt");
+ return ERROR_OK;
+ }
+
+ retval = dpm->prepare(dpm);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* ICIMVAU - Invalidate instruction cache by VA to PoU
+ * MCR p15, 0, r0, c7, c5, 1
+ */
+ for (uint32_t cacheline = address & ~(cacheline_size - 1);
+ cacheline < address + size * count;
+ cacheline += cacheline_size) {
+ retval = dpm->instr_write_data_r0(dpm,
+ ARMV4_5_MCR(15, 0, 0, 7, 5, 1), cacheline);
+ if (retval != ERROR_OK)
+ return retval;
+ }
+
+ /* (void) */ dpm->finish(dpm);
+
+ return retval;
+}
+
+int armv7a_clean_data_cache(struct target *target,
+ uint32_t address, uint32_t size, uint32_t count)
+{
+ struct armv7a_common *armv7a = target_to_armv7a(target);
+ struct arm_dpm *dpm = armv7a->arm.dpm;
+ uint32_t cacheline_size = armv7a->armv7a_mmu.armv7a_cache.d_u_size.linelen;
+ int retval;
+
+ if (target->state != TARGET_HALTED) {
+ LOG_ERROR("target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ /* check that cache is on at target halt */
+ if (!armv7a->armv7a_mmu.armv7a_cache.d_u_cache_enabled) {
+ LOG_DEBUG("data/unified cache clean not performed : cache not on at target halt");
+ return ERROR_OK;
+ }
+
+ retval = dpm->prepare(dpm);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* DCCMVAC - Clean data cache line to PoC by VA
+ * MCR p15, 0, r0, c7, c10, 1
+ */
+ for (uint32_t cacheline = address & ~(cacheline_size - 1);
+ cacheline < address + size * count;
+ cacheline += cacheline_size) {
+ retval = dpm->instr_write_data_r0(dpm,
+ ARMV4_5_MCR(15, 0, 0, 7, 10, 1), cacheline);
+ if (retval != ERROR_OK)
+ return retval;
+ }
+
+ /* (void) */ dpm->finish(dpm);
+
+ return retval;
+}
+
+int armv7a_invalidate_data_cache(struct target *target,
+ uint32_t address, uint32_t size, uint32_t count)
+{
+ struct armv7a_common *armv7a = target_to_armv7a(target);
+ struct arm_dpm *dpm = armv7a->arm.dpm;
+ uint32_t cacheline_size = armv7a->armv7a_mmu.armv7a_cache.d_u_size.linelen;
+ int retval;
+
+ if (target->state != TARGET_HALTED) {
+ LOG_ERROR("target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ /* check that cache is on at target halt */
+ if (!armv7a->armv7a_mmu.armv7a_cache.d_u_cache_enabled) {
+ LOG_DEBUG("data/unified cache invalidation not performed : cache not on at target halt");
+ return ERROR_OK;
+ }
+
+ retval = dpm->prepare(dpm);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* DCIMVAC - Invalidate data cache line by VA to PoC
+ * MCR p15, 0, r0, c7, c6, 1
+ */
+ for (uint32_t cacheline = address & ~(cacheline_size - 1);
+ cacheline < address + size * count;
+ cacheline += cacheline_size) {
+ 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;
+}
+
+int armv7a_clean_and_invalidate_data_cache(struct target *target,
+ uint32_t address, uint32_t size, uint32_t count)
+{
+ struct armv7a_common *armv7a = target_to_armv7a(target);
+ struct arm_dpm *dpm = armv7a->arm.dpm;
+ uint32_t cacheline_size = armv7a->armv7a_mmu.armv7a_cache.d_u_size.linelen;
+ int retval;
+
+ if (target->state != TARGET_HALTED) {
+ LOG_ERROR("target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ /* check that cache is on at target halt */
+ if (!armv7a->armv7a_mmu.armv7a_cache.d_u_cache_enabled) {
+ LOG_DEBUG("data/unified cache clean and invalidation not performed : cache not on at target halt");
+ return ERROR_OK;
+ }
+
+ retval = dpm->prepare(dpm);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* DCCIMVAC - Clean and invalidate data cache line by VA to PoC
+ * MCR p15, 0, r0, c7, c14, 1
+ */
+ for (uint32_t cacheline = address & ~(cacheline_size - 1);
+ cacheline < address + size * count;
+ cacheline += cacheline_size) {
+ retval = dpm->instr_write_data_r0(dpm,
+ ARMV4_5_MCR(15, 0, 0, 7, 14, 1),
+ cacheline);
+ if (retval != ERROR_OK)
+ return retval;
+ }
+
+ /* (void) */ dpm->finish(dpm);
+
+ return retval;
+
+}
+
/* L2 is not specific to armv7a a specific file is needed */
static int armv7a_l2x_flush_all_data(struct target *target)
{
@@ -465,14 +624,65 @@ static int armv7a_l2x_flush_all_data(struct target *target)
uint32_t base = l2x_cache->base;
uint32_t l2_way = l2x_cache->way;
uint32_t l2_way_val = (1 << l2_way) - 1;
+ uint8_t buf[4];
+
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);
+
+ target_buffer_set_u32(target, buf, l2_way_val);
+ retval = target->type->write_phys_memory(target, base + L2X0_CLEAN_INV_WAY, 4, 1, buf);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* poll cache maintenance register until operation is complete. */
+ while (l2_way_val & ((1 << l2_way) - 1)) {
+ retval = target->type->read_phys_memory(target, base + L2X0_CLEAN_INV_WAY, 4, 1, buf);
+ if (retval != ERROR_OK)
+ return retval;
+ l2_way_val = target_buffer_get_u32(target, buf);
+ }
+
+ return retval;
+}
+
+int armv7a_l2x_invalidate_all_data(struct target *target)
+{
+
+#define L2X0_CONTROL 0x100
+#define L2X0_INV_WAY 0x77C
+ 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;
+ uint32_t l2_control;
+ uint8_t buf[4];
+
+ retval = target->type->read_phys_memory(target, base + L2X0_CONTROL, 4, 1, buf);
+ if (retval != ERROR_OK)
+ return retval;
+ l2_control = target_buffer_get_u32(target, buf);
+
+ /* if L2 cache is disabled, do nothing */
+ if ((l2_control & 0x1) == 0)
+ return ERROR_OK;
+
+ target_buffer_set_u32(target, buf, l2_way_val);
+ retval = target->type->write_phys_memory(target, base + L2X0_INV_WAY, 4, 1, buf);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* poll cache maintenance register until operation is complete. */
+ while (l2_way_val & ((1 << l2_way) - 1)) {
+ retval = target->type->read_phys_memory(target, base + L2X0_INV_WAY, 4, 1, buf);
+ if (retval != ERROR_OK)
+ return retval;
+ l2_way_val = target_buffer_get_u32(target, buf);
+ }
+
return retval;
}
@@ -833,7 +1043,7 @@ static const struct command_registration l2_cache_commands[] = {
{
.name = "l2x",
.handler = handle_cache_l2x,
- .mode = COMMAND_EXEC,
+ .mode = COMMAND_ANY,
.help = "configure l2x cache "
"",
.usage = "[base_addr] [number_of_way]",
@@ -845,7 +1055,7 @@ static const struct command_registration l2_cache_commands[] = {
const struct command_registration l2x_cache_command_handlers[] = {
{
.name = "cache_config",
- .mode = COMMAND_EXEC,
+ .mode = COMMAND_ANY,
.help = "cache configuration for a target",
.usage = "",
.chain = l2_cache_commands,
diff --git a/src/target/armv7a.h b/src/target/armv7a.h
index 4341aca..3fb1fc2 100644
--- a/src/target/armv7a.h
+++ b/src/target/armv7a.h
@@ -26,11 +26,6 @@
#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*/
@@ -127,6 +122,10 @@ target_to_armv7a(struct target *target)
return container_of(target->arch_info, struct armv7a_common, arm);
}
+static inline bool is_armv7a(struct armv7a_common *armv7a)
+{
+ return armv7a->common_magic == ARMV7_COMMON_MAGIC;
+}
/* register offsets from armv7a.debug_base */
/* See ARMv7a arch spec section C10.2 */
@@ -150,7 +149,8 @@ target_to_armv7a(struct target *target)
#define CPUDBG_BCR_BASE 0x140
#define CPUDBG_WVR_BASE 0x180
#define CPUDBG_WCR_BASE 0x1C0
-#define CPUDBG_VCR 0x01C
+#define CPUDBG_VCR 0x01C
+#define VCR_SVC 0x4
/* See ARMv7a arch spec section C10.6 */
#define CPUDBG_OSLAR 0x300
@@ -171,6 +171,17 @@ 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_invalidate_instruction_cache(struct target *target,
+ uint32_t address, uint32_t size, uint32_t count);
+int armv7a_clean_data_cache(struct target *target,
+ uint32_t address, uint32_t size, uint32_t count);
+int armv7a_invalidate_data_cache(struct target *target,
+ uint32_t address, uint32_t size, uint32_t count);
+int armv7a_clean_and_invalidate_data_cache(struct target *target,
+ uint32_t address, uint32_t size, uint32_t count);
+
+int armv7a_l2x_invalidate_all_data(struct target *target);
+
int armv7a_handle_cache_info_command(struct command_context *cmd_ctx,
struct armv7a_cache_common *armv7a_cache);
diff --git a/src/target/blackfin.c b/src/target/blackfin.c
new file mode 100644
index 0000000..33e1de5
--- /dev/null
+++ b/src/target/blackfin.c
@@ -0,0 +1,1445 @@
+/***************************************************************************
+ * Copyright (C) 2011 by Analog Devices, Inc. *
+ * Written by Jie Zhang <***@analog.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 "helper/log.h"
+#include "helper/types.h"
+#include "helper/binarybuffer.h"
+
+#include "breakpoints.h"
+#include "register.h"
+#include "target.h"
+#include "target_type.h"
+#include "blackfin.h"
+#include "blackfin_jtag.h"
+#include "blackfin_mem.h"
+#include "blackfin_memory_map.h"
+#include "blackfin_config.h"
+
+#include "jtag/jtag.h"
+#include "jtag/drivers/ft2232.h"
+
+#undef UPSTREAM_GDB_SUPPORT
+
+/* Core Registers
+ BFIN_R0_REGNUM = 0,
+ BFIN_R1_REGNUM,
+ BFIN_R2_REGNUM,
+ BFIN_R3_REGNUM,
+ BFIN_R4_REGNUM,
+ BFIN_R5_REGNUM,
+ BFIN_R6_REGNUM,
+ BFIN_R7_REGNUM,
+ BFIN_P0_REGNUM,
+ BFIN_P1_REGNUM,
+ BFIN_P2_REGNUM,
+ BFIN_P3_REGNUM,
+ BFIN_P4_REGNUM,
+ BFIN_P5_REGNUM,
+ BFIN_SP_REGNUM,
+ BFIN_FP_REGNUM,
+ BFIN_I0_REGNUM,
+ BFIN_I1_REGNUM,
+ BFIN_I2_REGNUM,
+ BFIN_I3_REGNUM,
+ BFIN_M0_REGNUM,
+ BFIN_M1_REGNUM,
+ BFIN_M2_REGNUM,
+ BFIN_M3_REGNUM,
+ BFIN_B0_REGNUM,
+ BFIN_B1_REGNUM,
+ BFIN_B2_REGNUM,
+ BFIN_B3_REGNUM,
+ BFIN_L0_REGNUM,
+ BFIN_L1_REGNUM,
+ BFIN_L2_REGNUM,
+ BFIN_L3_REGNUM,
+ BFIN_A0_DOT_X_REGNUM,
+ BFIN_AO_DOT_W_REGNUM,
+ BFIN_A1_DOT_X_REGNUM,
+ BFIN_A1_DOT_W_REGNUM,
+ BFIN_ASTAT_REGNUM,
+ BFIN_RETS_REGNUM,
+ BFIN_LC0_REGNUM,
+ BFIN_LT0_REGNUM,
+ BFIN_LB0_REGNUM,
+ BFIN_LC1_REGNUM,
+ BFIN_LT1_REGNUM,
+ BFIN_LB1_REGNUM,
+ BFIN_CYCLES_REGNUM,
+ BFIN_CYCLES2_REGNUM,
+ BFIN_USP_REGNUM,
+ BFIN_SEQSTAT_REGNUM,
+ BFIN_SYSCFG_REGNUM,
+ BFIN_RETI_REGNUM,
+ BFIN_RETX_REGNUM,
+ BFIN_RETN_REGNUM,
+ BFIN_RETE_REGNUM,
+*/
+
+struct blackfin_core_reg
+{
+ uint32_t num;
+ struct target *target;
+ /* can we remove the following line. */
+ struct blackfin_common *blackfin_common;
+};
+
+/* This enum was copied from GDB. */
+enum gdb_regnum
+{
+ /* Core Registers */
+ BFIN_R0_REGNUM = 0,
+ BFIN_R1_REGNUM,
+ BFIN_R2_REGNUM,
+ BFIN_R3_REGNUM,
+ BFIN_R4_REGNUM,
+ BFIN_R5_REGNUM,
+ BFIN_R6_REGNUM,
+ BFIN_R7_REGNUM,
+ BFIN_P0_REGNUM,
+ BFIN_P1_REGNUM,
+ BFIN_P2_REGNUM,
+ BFIN_P3_REGNUM,
+ BFIN_P4_REGNUM,
+ BFIN_P5_REGNUM,
+ BFIN_SP_REGNUM,
+ BFIN_FP_REGNUM,
+ BFIN_I0_REGNUM,
+ BFIN_I1_REGNUM,
+ BFIN_I2_REGNUM,
+ BFIN_I3_REGNUM,
+ BFIN_M0_REGNUM,
+ BFIN_M1_REGNUM,
+ BFIN_M2_REGNUM,
+ BFIN_M3_REGNUM,
+ BFIN_B0_REGNUM,
+ BFIN_B1_REGNUM,
+ BFIN_B2_REGNUM,
+ BFIN_B3_REGNUM,
+ BFIN_L0_REGNUM,
+ BFIN_L1_REGNUM,
+ BFIN_L2_REGNUM,
+ BFIN_L3_REGNUM,
+ BFIN_A0_DOT_X_REGNUM,
+ BFIN_AO_DOT_W_REGNUM,
+ BFIN_A1_DOT_X_REGNUM,
+ BFIN_A1_DOT_W_REGNUM,
+ BFIN_ASTAT_REGNUM,
+ BFIN_RETS_REGNUM,
+ BFIN_LC0_REGNUM,
+ BFIN_LT0_REGNUM,
+ BFIN_LB0_REGNUM,
+ BFIN_LC1_REGNUM,
+ BFIN_LT1_REGNUM,
+ BFIN_LB1_REGNUM,
+ BFIN_CYCLES_REGNUM,
+ BFIN_CYCLES2_REGNUM,
+ BFIN_USP_REGNUM,
+ BFIN_SEQSTAT_REGNUM,
+ BFIN_SYSCFG_REGNUM,
+ BFIN_RETI_REGNUM,
+ BFIN_RETX_REGNUM,
+ BFIN_RETN_REGNUM,
+ BFIN_RETE_REGNUM,
+
+ /* Pseudo Registers */
+ BFIN_PC_REGNUM,
+#ifndef UPSTREAM_GDB_SUPPORT
+ BFIN_CC_REGNUM,
+ BFIN_TEXT_ADDR, /* Address of .text section. */
+ BFIN_TEXT_END_ADDR, /* Address of the end of .text section. */
+ BFIN_DATA_ADDR, /* Address of .data section. */
+
+ BFIN_FDPIC_EXEC_REGNUM,
+ BFIN_FDPIC_INTERP_REGNUM,
+
+ /* MMRs */
+ BFIN_IPEND_REGNUM,
+#endif
+
+ /* LAST ENTRY SHOULD NOT BE CHANGED. */
+ BFIN_NUM_REGS /* The number of all registers. */
+};
+
+/* Map gdb register number to core register number. */
+static enum core_regnum map_gdb_core[] = {
+ /* Core Registers */
+ REG_R0, REG_R1, REG_R2, REG_R3, REG_R4, REG_R5, REG_R6, REG_R7,
+ REG_P0, REG_P1, REG_P2, REG_P3, REG_P4, REG_P5, REG_SP, REG_FP,
+ REG_I0, REG_I1, REG_I2, REG_I3, REG_M0, REG_M1, REG_M2, REG_M3,
+ REG_B0, REG_B1, REG_B2, REG_B3, REG_L0, REG_L1, REG_L2, REG_L3,
+ REG_A0x, REG_A0w, REG_A1x, REG_A1w, REG_ASTAT, REG_RETS,
+ REG_LC0, REG_LT0, REG_LB0, REG_LC1, REG_LT1, REG_LB1,
+ REG_CYCLES, REG_CYCLES2,
+ REG_USP, REG_SEQSTAT, REG_SYSCFG, REG_RETI, REG_RETX, REG_RETN, REG_RETE,
+
+ /* Pseudo Registers */
+ REG_RETE,
+#ifndef UPSTREAM_GDB_SUPPORT
+ -1 /* REG_CC */,
+ -1 /* REG_TEXT_ADDR */,
+ -1 /* REG_TEXT_END_ADDR */,
+ -1 /* REG_DATA_ADDR */,
+ -1 /* REG_FDPIC_EXEC_REGNUM */,
+ -1 /* REG_FDPIC_INTERP_REGNUM */,
+
+ /* MMRs */
+ -1 /* REG_IPEND */
+#endif
+};
+
+static char* blackfin_core_reg_list[] =
+{
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+ "p0", "p1", "p2", "p3", "p4", "p5", "sp", "fp",
+ "i0", "i1", "i2", "i3", "m0", "m1", "m2", "m3",
+ "b0", "b1", "b2", "b3", "l0", "l1", "l2", "l3",
+ "a0.x", "a0.w", "a1.x", "a1.w", "astat", "rets",
+ "lc0", "lt0", "lb0", "lc1", "lt1", "lb1",
+ "cycles", "cycles2", "usp", "seqstat", "syscfg",
+ "reti", "retx", "retn", "rete"
+};
+
+static struct blackfin_core_reg blackfin_core_reg_list_arch_info[BLACKFINNUMCOREREGS] =
+{
+ {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},
+ {38, NULL, NULL},
+ {39, NULL, NULL},
+ {40, NULL, NULL},
+ {41, NULL, NULL},
+ {42, NULL, NULL},
+ {43, NULL, NULL},
+ {44, NULL, NULL},
+ {45, NULL, NULL},
+ {46, NULL, NULL},
+ {47, NULL, NULL},
+ {48, NULL, NULL},
+ {49, NULL, NULL},
+ {50, NULL, NULL},
+ {51, NULL, NULL},
+ {52, NULL, NULL},
+};
+
+static uint8_t blackfin_gdb_dummy_value[] = {0, 0, 0, 0};
+
+static struct reg blackfin_gdb_dummy_reg =
+{
+ .name = "GDB dummy register",
+ .value = blackfin_gdb_dummy_value,
+ .dirty = 0,
+ .valid = 1,
+ .size = 32,
+ .arch_info = NULL,
+};
+
+#define EMUCAUSE_EMUEXCPT 0x0
+#define EMUCAUSE_EMUIN 0x1
+#define EMUCAUSE_WATCHPOINT 0x2
+#define EMUCAUSE_PM0_OVERFLOW 0x4
+#define EMUCAUSE_PM1_OVERFLOW 0x5
+#define EMUCAUSE_SINGLE_STEP 0x8
+
+#define WPDA_DISABLE 0
+#define WPDA_WRITE 1
+#define WPDA_READ 2
+#define WPDA_ALL 3
+
+static const uint8_t blackfin_breakpoint_16[] = { 0x25, 0x0 };
+static const uint8_t blackfin_breakpoint_32[] = { 0x25, 0x0, 0x0, 0x0 };
+
+int blackfin_wait_clocks = -1;
+
+/* This function reads hardware register and update the value in cache. */
+static int blackfin_get_core_reg(struct reg *reg)
+{
+ struct blackfin_core_reg *blackfin_reg = reg->arch_info;
+ struct target *target = blackfin_reg->target;
+ struct blackfin_common *blackfin = target_to_blackfin(target);
+ struct blackfin_jtag *jtag_info = &blackfin->jtag_info;
+ uint32_t value;
+
+ if (target->state != TARGET_HALTED)
+ {
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ value = blackfin_register_get(jtag_info, map_gdb_core[blackfin_reg->num]);
+ buf_set_u32(reg->value, 0, 32, value);
+ reg->valid = 1;
+ reg->dirty = 0;
+
+ return ERROR_OK;
+}
+
+/* This function does not set hardware register. It just sets the register in
+ the cache and set it's dirty flag. When restoring context, all dirty
+ registers will be written back to the hardware. */
+static int blackfin_set_core_reg(struct reg *reg, uint8_t *buf)
+{
+ struct blackfin_core_reg *blackfin_reg = reg->arch_info;
+ struct target *target = blackfin_reg->target;
+ uint32_t value;
+
+ if (target->state != TARGET_HALTED)
+ {
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ value = buf_get_u32(buf, 0, 32);
+ buf_set_u32(reg->value, 0, 32, value);
+ reg->dirty = 1;
+ reg->valid = 1;
+
+ return ERROR_OK;
+}
+
+static const struct reg_arch_type blackfin_reg_type =
+{
+ .get = blackfin_get_core_reg,
+ .set = blackfin_set_core_reg,
+};
+
+
+/* We does not actually save all registers here. We just invalidate
+ all registers in the cache. When an invalid register in the cache
+ is read, its value will then be fetched from hardware. */
+static void blackfin_save_context(struct target *target)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(target);
+ int i;
+
+ for (i = 0; i < BLACKFINNUMCOREREGS; i++)
+ {
+ blackfin->core_cache->reg_list[i].valid = 0;
+ blackfin->core_cache->reg_list[i].dirty = 0;
+ }
+}
+
+/* Write dirty registers to hardware. */
+static void blackfin_restore_context(struct target *target)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(target);
+ struct blackfin_jtag *jtag_info = &blackfin->jtag_info;
+ int i;
+
+ for (i = 0; i < BLACKFINNUMCOREREGS; i++)
+ {
+ struct reg *reg = &blackfin->core_cache->reg_list[i];
+ struct blackfin_core_reg *blackfin_reg = reg->arch_info;
+
+ if (reg->dirty)
+ {
+ uint32_t value = buf_get_u32(reg->value, 0, 32);
+ blackfin_register_set(jtag_info, map_gdb_core[blackfin_reg->num], value);
+ }
+ }
+}
+
+static void blackfin_debug_entry(struct target *target)
+{
+ blackfin_save_context(target);
+}
+
+static int blackfin_poll(struct target *target)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(target);
+ struct blackfin_jtag *jtag_info = &blackfin->jtag_info;
+ enum target_state prev_target_state = target->state;
+
+ blackfin_emupc_get(jtag_info);
+ /* If the core is already in fault, don't reset EMUPC. */
+ if (!blackfin_dbgstat_is_core_fault(jtag_info))
+ blackfin_emupc_reset(jtag_info);
+ blackfin_read_dbgstat(jtag_info);
+
+ if (blackfin_dbgstat_is_in_reset(jtag_info))
+ target->state = TARGET_RESET;
+ else if (blackfin_dbgstat_is_core_fault(jtag_info))
+ {
+ if (prev_target_state != TARGET_HALTED)
+ {
+ LOG_WARNING("%s: a double fault has occurred at EMUPC [0x%08X]",
+ target_name(target), jtag_info->emupc);
+ target->state = TARGET_HALTED;
+ target->debug_reason = DBG_REASON_UNDEFINED;
+ blackfin->is_corefault = 1;
+ }
+
+ if (prev_target_state == TARGET_RUNNING
+ || prev_target_state == TARGET_RESET)
+ {
+ target_call_event_callbacks(target, TARGET_EVENT_HALTED);
+ }
+ else if (prev_target_state == TARGET_DEBUG_RUNNING)
+ {
+ target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED);
+ }
+ }
+ else if (blackfin_dbgstat_is_emuready(jtag_info))
+
+ {
+ if (prev_target_state != TARGET_HALTED)
+ {
+ uint16_t cause;
+
+ LOG_DEBUG("Target halted");
+ target->state = TARGET_HALTED;
+
+ cause = blackfin_dbgstat_emucause(jtag_info);
+
+ blackfin_wpstat_get(jtag_info);
+
+ if ((jtag_info->wpstat & 0x3f) && !(jtag_info->wpstat & 0xc0))
+ {
+ target->debug_reason = DBG_REASON_BREAKPOINT;
+ }
+ else if (!(jtag_info->wpstat & 0x3f) && (jtag_info->wpstat & 0xc0))
+ {
+ target->debug_reason = DBG_REASON_WATCHPOINT;
+ }
+ else if ((jtag_info->wpstat & 0x3f) && (jtag_info->wpstat & 0xc0))
+ {
+ target->debug_reason = DBG_REASON_WPTANDBKPT;
+ }
+ else
+ switch (cause)
+ {
+ case EMUCAUSE_EMUEXCPT:
+ target->debug_reason = DBG_REASON_BREAKPOINT;
+ break;
+
+ case EMUCAUSE_SINGLE_STEP:
+ target->debug_reason = DBG_REASON_SINGLESTEP;
+ break;
+
+ case EMUCAUSE_WATCHPOINT:
+ abort();
+ break;
+
+ case EMUCAUSE_EMUIN:
+ target->debug_reason = DBG_REASON_DBGRQ;
+ break;
+
+ case EMUCAUSE_PM0_OVERFLOW:
+ case EMUCAUSE_PM1_OVERFLOW:
+ default:
+ target->debug_reason = DBG_REASON_UNDEFINED;
+ break;
+ }
+
+ if (jtag_info->wpstat & 0xff)
+ {
+ if (jtag_info->wpstat & 0xc0)
+ blackfin_single_step(jtag_info, blackfin->is_stepping);
+ blackfin_wpstat_clear(jtag_info);
+ }
+
+ blackfin_debug_entry(target);
+
+ if (prev_target_state == TARGET_RUNNING
+ || prev_target_state == TARGET_RESET)
+ {
+ target_call_event_callbacks(target, TARGET_EVENT_HALTED);
+ }
+ else if (prev_target_state == TARGET_DEBUG_RUNNING)
+ {
+ target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED);
+ }
+ }
+ }
+ else
+ {
+ target->state = TARGET_RUNNING;
+ target->debug_reason = DBG_REASON_NOTHALTED;
+ }
+
+ if (prev_target_state != target->state)
+ LOG_DEBUG("target->state: ==> %s", target_state_name(target));
+
+ return ERROR_OK;
+}
+
+static int blackfin_arch_state(struct target *target)
+{
+ return ERROR_FAIL;
+}
+
+static int blackfin_target_request_data(struct target *target,
+ uint32_t size, uint8_t *buffer)
+{
+ return ERROR_FAIL;
+}
+
+static int blackfin_halt(struct target *target)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(target);
+ struct blackfin_jtag *jtag_info = &blackfin->jtag_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)
+ {
+ /* FIXME it might be possible to halt while in reset,
+ see other targets for a example. */
+ LOG_ERROR("can't request a halt while in reset");
+ return ERROR_TARGET_FAILURE;
+ }
+
+ blackfin_emulation_enable(jtag_info);
+ blackfin_emulation_trigger(jtag_info);
+
+ target->debug_reason = DBG_REASON_DBGRQ;
+
+ return ERROR_OK;
+}
+
+static int blackfin_resume_1(struct target *target, int current,
+ uint32_t address, int handle_breakpoints, int debug_execution, bool step)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(target);
+ struct blackfin_jtag *jtag_info = &blackfin->jtag_info;
+
+ /* We don't handle this for now. */
+ assert(debug_execution == 0);
+
+ /* FIXME handle handle_breakpoints !!!*/
+
+ if (target->state != TARGET_HALTED)
+ {
+ LOG_WARNING("target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ if (!debug_execution)
+ {
+ target_free_all_working_areas(target);
+ }
+
+ blackfin_emupc_reset(jtag_info);
+
+ blackfin_restore_context(target);
+
+ if (!current)
+ {
+ blackfin_register_set(jtag_info, REG_RETE, address);
+ }
+
+ if (blackfin->status_pending_p && blackfin->pending_is_breakpoint)
+ {
+ int retval;
+ uint8_t buf[2];
+
+ retval = blackfin_read_mem(jtag_info, blackfin->pending_stop_pc, 2, buf);
+ assert(retval == ERROR_OK);
+
+ if (buf[0] != blackfin_breakpoint_16[0]
+ || buf[1] != blackfin_breakpoint_16[1])
+ {
+ /* The breakpoint is gone. Consume the pending status. */
+ blackfin->pending_is_breakpoint = 0;
+ blackfin->status_pending_p = 0;
+ }
+
+ if (blackfin->status_pending_p)
+ return ERROR_OK;
+ }
+
+ if (step && !blackfin->is_stepping)
+ {
+ blackfin_dbgctl_bit_set_esstep(jtag_info);
+ blackfin->is_stepping = 1;
+ }
+ else if (!step && blackfin->is_stepping)
+ {
+ blackfin_dbgctl_bit_clear_esstep(jtag_info);
+ blackfin->is_stepping = 0;
+ }
+
+ 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);
+ }
+
+ blackfin->is_running = 1;
+ blackfin->is_interrupted = 0;
+ blackfin->dmem_control_valid_p = 0;
+ blackfin->imem_control_valid_p = 0;
+ blackfin_emulation_return(jtag_info);
+
+ return ERROR_OK;
+}
+
+static int blackfin_resume(struct target *target, int current,
+ uint32_t address, int handle_breakpoints, int debug_execution)
+{
+ int retval;
+
+ retval = blackfin_resume_1(target, current, address, handle_breakpoints, debug_execution, false);
+
+ return retval;
+}
+
+static int blackfin_step(struct target *target, int current,
+ uint32_t address, int handle_breakpoints)
+{
+ int retval;
+
+ retval = blackfin_resume_1(target, current, address, handle_breakpoints, 0, true);
+
+ return retval;
+}
+
+static int blackfin_assert_reset(struct target *target)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(target);
+ struct blackfin_jtag *jtag_info = &blackfin->jtag_info;
+
+ LOG_DEBUG("target->state: %s", target_state_name(target));
+
+ blackfin_system_reset(jtag_info);
+ blackfin_core_reset(jtag_info);
+
+ target->state = TARGET_HALTED;
+
+ /* Reset should bring the core out of core fault. */
+ blackfin->is_corefault = 0;
+
+ /* Reset should invalidate register cache. */
+ register_cache_invalidate(blackfin->core_cache);
+
+ if (!target->reset_halt)
+ {
+ blackfin_resume(target, 1, 0, 0, 0);
+ target->state = TARGET_RUNNING;
+ }
+
+ return ERROR_OK;
+}
+
+static int blackfin_deassert_reset(struct target *target)
+{
+ return ERROR_OK;
+}
+
+static int blackfin_get_gdb_reg_list(struct target *target, struct reg **reg_list[],
+ int *reg_list_size, enum target_register_class reg_class)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(target);
+ int i;
+
+ *reg_list_size = BFIN_NUM_REGS;
+ *reg_list = malloc(sizeof(struct reg*) * (*reg_list_size));
+
+ for (i = 0; i < BLACKFINNUMCOREREGS; i++)
+ (*reg_list)[i] = &blackfin->core_cache->reg_list[i];
+
+ for (i = BLACKFINNUMCOREREGS; i < BFIN_NUM_REGS; i++)
+ {
+ if (i == BFIN_PC_REGNUM)
+ (*reg_list)[i] = &blackfin->core_cache->reg_list[BFIN_RETE_REGNUM];
+ /* TODO handle CC */
+ else
+ (*reg_list)[i] = &blackfin_gdb_dummy_reg;
+ }
+
+ return ERROR_OK;
+}
+
+static int blackfin_read_memory(struct target *target, uint32_t address,
+ uint32_t size, uint32_t count, uint8_t *buffer)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(target);
+ struct blackfin_jtag *jtag_info = &blackfin->jtag_info;
+ 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;
+ }
+
+ retval = blackfin_read_mem(jtag_info, address, size * count, buffer);
+
+ return retval;
+}
+
+static int blackfin_write_memory(struct target *target, uint32_t address,
+ uint32_t size, uint32_t count, const uint8_t *buffer)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(target);
+ struct blackfin_jtag *jtag_info = &blackfin->jtag_info;
+ 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;
+ }
+
+ retval = blackfin_write_mem(jtag_info, address, size * count, buffer);
+
+ return retval;
+}
+
+static int blackfin_checksum_memory(struct target *target,
+ uint32_t address, uint32_t count, uint32_t* checksum)
+{
+ return ERROR_FAIL;
+}
+
+static int blackfin_blank_check_memory(struct target *target,
+ uint32_t address, uint32_t count, uint32_t* blank)
+{
+ return ERROR_FAIL;
+}
+
+static int blackfin_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 ERROR_FAIL;
+}
+
+static int blackfin_add_breakpoint(struct target *target, struct breakpoint *breakpoint)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(target);
+ struct blackfin_jtag *jtag_info = &blackfin->jtag_info;
+ int retval;
+
+ assert(breakpoint->set == 0);
+
+ blackfin_emupc_reset(jtag_info);
+
+ if (breakpoint->type == BKPT_SOFT)
+ {
+ const uint8_t *bp;
+
+ if (breakpoint->length == 2)
+ bp = blackfin_breakpoint_16;
+ else
+ bp = blackfin_breakpoint_32;
+
+ retval = blackfin_read_memory(target, breakpoint->address,
+ breakpoint->length, 1, breakpoint->orig_instr);
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = blackfin_write_memory(target, breakpoint->address,
+ breakpoint->length, 1, bp);
+ if (retval != ERROR_OK)
+ return retval;
+ }
+ else /* BKPT_HARD */
+ {
+ int i;
+ for (i = 0; i < BLACKFIN_MAX_HWBREAKPOINTS; i++)
+ if (jtag_info->hwbps[i] == (uint32_t) -1)
+ break;
+ if (i == BLACKFIN_MAX_HWBREAKPOINTS)
+ {
+ LOG_ERROR("%s: no more hardware breakpoint available for 0x%08x",
+ target_name(target), breakpoint->address);
+ return ERROR_FAIL;
+ }
+
+ jtag_info->hwbps[i] = breakpoint->address;
+ if (blackfin->is_locked)
+ {
+ LOG_WARNING("%s: target is locked, hardware breakpoint [0x%08x] will be set when it's unlocked", target_name(target), breakpoint->address);
+ }
+ else
+ {
+ blackfin_wpu_set_wpia(jtag_info, i, breakpoint->address, 1);
+ }
+ }
+
+ breakpoint->set = 1;
+
+ return ERROR_OK;
+}
+
+static int blackfin_remove_breakpoint(struct target *target, struct breakpoint *breakpoint)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(target);
+ struct blackfin_jtag *jtag_info = &blackfin->jtag_info;
+ int retval;
+
+ assert(breakpoint->set != 0);
+
+ blackfin_emupc_reset(jtag_info);
+
+ if (breakpoint->type == BKPT_SOFT)
+ {
+ retval = blackfin_write_memory(target, breakpoint->address,
+ breakpoint->length, 1, breakpoint->orig_instr);
+ if (retval != ERROR_OK)
+ return retval;
+ }
+ else /* BKPT_HARD */
+ {
+ int i;
+ for (i = 0; i < BLACKFIN_MAX_HWBREAKPOINTS; i++)
+ if (jtag_info->hwbps[i] == breakpoint->address)
+ break;
+
+ if (i == BLACKFIN_MAX_HWBREAKPOINTS)
+ {
+ LOG_ERROR("%s: no hardware breakpoint at 0x%08x",
+ target_name(target), breakpoint->address);
+ return ERROR_FAIL;
+ }
+
+ jtag_info->hwbps[i] = -1;
+ if (blackfin->is_locked)
+ {
+ /* The hardware breakpoint will only be set when target is
+ unlocked. Target cannot be locked again after it's unlocked.
+ So if we are removing a hardware breakpoint when target is
+ locked, that hardware breakpoint has never been set.
+ So we can just quietly remove it. */
+ }
+ else
+ {
+ blackfin_wpu_set_wpia(jtag_info, i, breakpoint->address, 0);
+ }
+ }
+
+ breakpoint->set = 0;
+
+ return ERROR_OK;
+}
+
+static int blackfin_add_watchpoint(struct target *target, struct watchpoint *watchpoint)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(target);
+ struct blackfin_jtag *jtag_info = &blackfin->jtag_info;
+ int i;
+ bool range;
+
+ /* TODO provide a method to always use range watchpoint. */
+
+ if (target->state != TARGET_HALTED)
+ return ERROR_TARGET_NOT_HALTED;
+
+ blackfin_emupc_reset(jtag_info);
+
+ if (watchpoint->length <= 4
+ && jtag_info->hwwps[0].used
+ && (jtag_info->hwwps[1].used
+ || jtag_info->hwwps[0].range))
+ {
+ LOG_ERROR("all hardware watchpoints are in use.");
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+ }
+
+ if (watchpoint->length > 4
+ && (jtag_info->hwwps[0].used
+ || jtag_info->hwwps[1].used))
+ {
+ LOG_ERROR("no enough hardware watchpoints.");
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+ }
+
+ if (watchpoint->length <= 4)
+ {
+ i = jtag_info->hwwps[0].used ? 1 : 0;
+ range = false;
+ }
+ else
+ {
+ i = 0;
+ range = true;
+ }
+
+ jtag_info->hwwps[i].addr = watchpoint->address;
+ jtag_info->hwwps[i].len = watchpoint->length;
+ jtag_info->hwwps[i].range = range;
+ jtag_info->hwwps[i].used = true;
+ switch (watchpoint->rw)
+ {
+ case WPT_READ:
+ jtag_info->hwwps[i].mode = WPDA_READ;
+ break;
+ case WPT_WRITE:
+ jtag_info->hwwps[i].mode = WPDA_WRITE;
+ break;
+ case WPT_ACCESS:
+ jtag_info->hwwps[i].mode = WPDA_ALL;
+ break;
+ }
+
+ if (blackfin->is_locked)
+ {
+ LOG_WARNING("%s: target is locked, hardware watchpoint [0x%08x] will be set when it's unlocked", target_name(target), watchpoint->address);
+ }
+ else
+ {
+ blackfin_wpu_set_wpda(jtag_info, i);
+ }
+
+ return ERROR_OK;
+}
+
+static int blackfin_remove_watchpoint(struct target *target, struct watchpoint *watchpoint)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(target);
+ struct blackfin_jtag *jtag_info = &blackfin->jtag_info;
+ int mode;
+ int i;
+
+ /* TODO provide a method to always use range watchpoint. */
+
+ if (target->state != TARGET_HALTED)
+ return ERROR_TARGET_NOT_HALTED;
+
+ blackfin_emupc_reset(jtag_info);
+
+ switch (watchpoint->rw)
+ {
+ case WPT_READ:
+ mode = WPDA_READ;
+ break;
+ case WPT_WRITE:
+ mode = WPDA_WRITE;
+ break;
+ case WPT_ACCESS:
+ mode = WPDA_ALL;
+ break;
+ default:
+ return ERROR_FAIL;
+ }
+
+ for (i = 0; i < BLACKFIN_MAX_HWWATCHPOINTS; i++)
+ if (jtag_info->hwwps[i].addr == watchpoint->address
+ && jtag_info->hwwps[i].len == watchpoint->length
+ && jtag_info->hwwps[i].mode == mode)
+ break;
+
+ if (i == BLACKFIN_MAX_HWWATCHPOINTS)
+ {
+ LOG_ERROR("no hardware watchpoint at 0x%08X length %d.",
+ watchpoint->address, watchpoint->length);
+ return ERROR_FAIL;
+ }
+
+ if (watchpoint->length > 4)
+ {
+ assert (i == 0 && jtag_info->hwwps[i].range);
+ }
+
+ jtag_info->hwwps[i].mode = WPDA_DISABLE;
+
+ if (blackfin->is_locked)
+ {
+ /* See the comment in blackfin_remove_breakpoint. */
+ }
+ else
+ {
+ blackfin_wpu_set_wpda(jtag_info, i);
+ }
+
+ jtag_info->hwwps[i].addr = 0;
+ jtag_info->hwwps[i].len = 0;
+ jtag_info->hwwps[i].range = false;
+ jtag_info->hwwps[i].used = false;
+
+ return ERROR_OK;
+}
+
+static int blackfin_target_create(struct target *target, Jim_Interp *interp)
+{
+ struct blackfin_common *blackfin = calloc(1, sizeof(struct blackfin_common));
+ struct Jim_Obj *objPtr;
+ const char *map, *config;
+ char *end;
+
+ target->arch_info = blackfin;
+
+ blackfin->common_magic = BLACKFIN_COMMON_MAGIC;
+ strcpy(blackfin->part, target_name(target));
+ end = strchr(blackfin->part, '.');
+ if (end)
+ *end = '\0';
+
+ objPtr = Jim_GetGlobalVariableStr(interp, "MEMORY_MAP", JIM_NONE);
+ map = Jim_GetString(objPtr, NULL);
+ parse_memory_map(target, map);
+
+ objPtr = Jim_GetGlobalVariableStr(interp, "BLACKFIN_CONFIG", JIM_NONE);
+ config = Jim_GetString(objPtr, NULL);
+ blackfin_parse_config(target, config);
+
+ objPtr = Jim_GetGlobalVariableStr(interp, "SDRRC", JIM_NONE);
+ if (objPtr)
+ {
+ struct blackfin_sdram_config *sdram_config;
+ long value;
+ int retval;
+ sdram_config = malloc(sizeof (blackfin->sdram_config));
+ if (!sdram_config)
+ {
+ LOG_ERROR("%s: malloc(%"PRIzu") failed",
+ target_name(target), sizeof (blackfin->sdram_config));
+ return ERROR_FAIL;
+ }
+ retval = Jim_GetLong(interp, objPtr, &value);
+ if (retval == JIM_OK)
+ sdram_config->sdrrc = value;
+ else
+ return ERROR_FAIL;
+
+ objPtr = Jim_GetGlobalVariableStr(interp, "SDBCTL", JIM_NONE);
+ if (!objPtr)
+ {
+ LOG_ERROR("%s: SDBCTL is not defined", target_name(target));
+ return ERROR_FAIL;
+ }
+ retval = Jim_GetLong(interp, objPtr, &value);
+ if (retval == JIM_OK)
+ sdram_config->sdbctl = value;
+ else
+ return ERROR_FAIL;
+
+ objPtr = Jim_GetGlobalVariableStr(interp, "SDGCTL", JIM_NONE);
+ if (!objPtr)
+ {
+ LOG_ERROR("%s: SDGCTL is not defined", target_name(target));
+ return ERROR_FAIL;
+ }
+ retval = Jim_GetLong(interp, objPtr, &value);
+ if (retval == JIM_OK)
+ sdram_config->sdgctl = value;
+ else
+ return ERROR_FAIL;
+
+ blackfin->sdram_config = sdram_config;
+ }
+ else
+ blackfin->sdram_config = NULL;
+
+ objPtr = Jim_GetGlobalVariableStr(interp, "DDRCTL0", JIM_NONE);
+ if (objPtr)
+ {
+ struct blackfin_ddr_config *ddr_config;
+ long value;
+ int retval;
+ ddr_config = malloc(sizeof (blackfin->ddr_config));
+ if (!ddr_config)
+ {
+ LOG_ERROR("%s: malloc(%"PRIzu") failed",
+ target_name(target), sizeof (blackfin->ddr_config));
+ return ERROR_FAIL;
+ }
+ retval = Jim_GetLong(interp, objPtr, &value);
+ if (retval == JIM_OK)
+ ddr_config->ddrctl0 = value;
+ else
+ return ERROR_FAIL;
+
+ objPtr = Jim_GetGlobalVariableStr(interp, "DDRCTL1", JIM_NONE);
+ if (!objPtr)
+ {
+ LOG_ERROR("%s: DDRCTL1 is not defined", target_name(target));
+ return ERROR_FAIL;
+ }
+ retval = Jim_GetLong(interp, objPtr, &value);
+ if (retval == JIM_OK)
+ ddr_config->ddrctl1 = value;
+ else
+ return ERROR_FAIL;
+
+ objPtr = Jim_GetGlobalVariableStr(interp, "DDRCTL2", JIM_NONE);
+ if (!objPtr)
+ {
+ LOG_ERROR("%s: DDRCTL2 is not defined", target_name(target));
+ return ERROR_FAIL;
+ }
+ retval = Jim_GetLong(interp, objPtr, &value);
+ if (retval == JIM_OK)
+ ddr_config->ddrctl2 = value;
+ else
+ return ERROR_FAIL;
+
+ blackfin->ddr_config = ddr_config;
+ }
+ else
+ blackfin->ddr_config = NULL;
+
+ blackfin->dmem_control_valid_p = 0;
+ blackfin->imem_control_valid_p = 0;
+ blackfin->dmem_control = 0;
+ blackfin->imem_control = 0;
+
+ return ERROR_OK;
+}
+
+static struct reg_cache *blackfin_build_reg_cache(struct target *target)
+{
+ /* get pointers to arch-specific information */
+ struct blackfin_common *blackfin = target_to_blackfin(target);
+
+ int num_regs = BLACKFINNUMCOREREGS;
+ 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 blackfin_core_reg *arch_info = malloc(sizeof(struct blackfin_core_reg) * num_regs);
+ int i;
+
+ register_init_dummy(&blackfin_gdb_dummy_reg);
+
+ /* Build the process context cache */
+ cache->name = "blackfin registers";
+ cache->next = NULL;
+ cache->reg_list = reg_list;
+ cache->num_regs = num_regs;
+ (*cache_p) = cache;
+ blackfin->core_cache = cache;
+
+ for (i = 0; i < num_regs; i++)
+ {
+ arch_info[i] = blackfin_core_reg_list_arch_info[i];
+ arch_info[i].target = target;
+ arch_info[i].blackfin_common = blackfin;
+ reg_list[i].name = blackfin_core_reg_list[i];
+ reg_list[i].feature = NULL;
+ 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 = &blackfin_reg_type;
+ reg_list[i].arch_info = &arch_info[i];
+ }
+
+ return cache;
+}
+
+static int blackfin_init_target(struct command_context *cmd_ctx,
+ struct target *target)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(target);
+
+ blackfin->jtag_info.target = target;
+ blackfin_build_reg_cache(target);
+ return ERROR_OK;
+}
+
+static int blackfin_calculate_wait_clocks(void)
+{
+ int clocks;
+ int frequency;
+
+ /* The following default numbers of wait clock for various cables are
+ tested on a BF537 stamp board, on which U-Boot is running.
+ CCLK is set to 62MHz and SCLK is set to 31MHz, which is the lowest
+ frequency I can set in BF537 stamp Linux kernel.
+
+ The test is done by dumping memory from 0x20000000 to 0x20000010 using
+ GDB and gdbproxy:
+
+ (gdb) dump memory u-boot.bin 0x20000000 0x20000010
+ (gdb) shell hexdump -C u-boot.bin
+
+ With an incorrect number of wait clocks, the first 4 bytes will be
+ duplicated by the second 4 bytes. */
+
+ clocks = -1;
+ frequency = jtag_get_speed_khz();
+
+ if (strcmp(jtag_get_name(), "ftdi") == 0)
+ {
+ /* For full speed ftdi device, we only need 3 wait clocks. For
+ high speed ftdi device, we need 5 wait clocks when its frequency
+ is less than or equal to 6000. We need a function like
+
+ bool ftdi_is_high_speed(void)
+
+ to distinguish them. But currently ftdi driver does not provide
+ such a function. So we just set wait clocks to 5 for both cases. */
+
+ if (frequency <= 6000)
+ clocks = 5;
+ else if (frequency <= 15000)
+ clocks = 12;
+ else
+ clocks = 21;
+ }
+ else if (strcmp(jtag_get_name(), "ice1000") == 0
+ || strcmp(jtag_get_name(), "ice2000") == 0)
+ {
+ if (frequency <= 5000)
+ clocks = 5;
+ else if (frequency <= 10000)
+ clocks = 11;
+ else if (frequency <= 17000)
+ clocks = 19;
+ else /* <= 25MHz */
+ clocks = 30;
+ }
+ else
+ {
+ /* intended empty */
+ }
+
+ if (clocks == -1)
+ {
+ clocks = 30;
+ LOG_WARNING("%s: untested cable running at %d KHz, set wait_clocks to %d",
+ jtag_get_name(), frequency, clocks);
+ }
+
+ return clocks;
+}
+
+static int blackfin_examine(struct target *target)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(target);
+ struct blackfin_jtag *jtag_info = &blackfin->jtag_info;
+ int i;
+
+ if (!target_was_examined(target))
+ {
+ target_set_examined(target);
+
+ jtag_info->dbgctl = 0;
+ jtag_info->dbgstat = 0;
+ jtag_info->emuir_a = BLACKFIN_INSN_ILLEGAL;
+ jtag_info->emuir_b = BLACKFIN_INSN_ILLEGAL;
+ jtag_info->emudat_out = 0;
+ jtag_info->emudat_in = 0;
+
+ jtag_info->wpiactl = 0;
+ jtag_info->wpdactl = 0;
+ jtag_info->wpstat = 0;
+ for (i = 0; i < BLACKFIN_MAX_HWBREAKPOINTS; i++)
+ jtag_info->hwbps[i] = -1;
+ for (i = 0; i < BLACKFIN_MAX_HWWATCHPOINTS; i++)
+ {
+ jtag_info->hwwps[i].addr = 0;
+ jtag_info->hwwps[i].len = 0;
+ jtag_info->hwwps[i].mode = WPDA_DISABLE;
+ jtag_info->hwwps[i].range = false;
+ jtag_info->hwwps[i].used = false;
+ }
+
+ jtag_info->emupc = -1;
+
+ blackfin_emulation_enable(jtag_info);
+ }
+
+ blackfin_wait_clocks = blackfin_calculate_wait_clocks();
+
+ return ERROR_OK;
+}
+
+COMMAND_HANDLER(blackfin_handle_wpu_init_command)
+{
+ struct target *target = get_current_target(CMD_CTX);
+ struct blackfin_common *blackfin = target_to_blackfin(target);
+ struct blackfin_jtag *jtag_info = &blackfin->jtag_info;
+
+ if (!target_was_examined(target))
+ {
+ LOG_ERROR("target not examined yet");
+ return ERROR_FAIL;
+ }
+
+ blackfin_wpu_init(jtag_info);
+ return ERROR_OK;
+}
+
+COMMAND_HANDLER(blackfin_handle_sdram_init_command)
+{
+ struct target *target = get_current_target(CMD_CTX);
+ struct blackfin_common *blackfin = target_to_blackfin(target);
+ struct blackfin_jtag *jtag_info = &blackfin->jtag_info;
+ int retval;
+
+ if (!target_was_examined(target))
+ {
+ LOG_ERROR("target not examined yet");
+ return ERROR_FAIL;
+ }
+ if (!blackfin->sdram_config)
+ {
+ LOG_ERROR("no SDRAM config");
+ return ERROR_FAIL;
+ }
+
+ retval = blackfin_sdram_init(jtag_info);
+ return retval;
+}
+
+COMMAND_HANDLER(blackfin_handle_ddr_init_command)
+{
+ struct target *target = get_current_target(CMD_CTX);
+ struct blackfin_common *blackfin = target_to_blackfin(target);
+ struct blackfin_jtag *jtag_info = &blackfin->jtag_info;
+ int retval;
+
+ if (!target_was_examined(target))
+ {
+ LOG_ERROR("target not examined yet");
+ return ERROR_FAIL;
+ }
+ if (!blackfin->ddr_config)
+ {
+ LOG_ERROR("no DDR config");
+ return ERROR_FAIL;
+ }
+
+ retval = blackfin_ddr_init(jtag_info);
+ return retval;
+}
+
+static const struct command_registration blackfin_exec_command_handlers[] = {
+ {
+ .name = "wpu_init",
+ .handler = blackfin_handle_wpu_init_command,
+ .mode = COMMAND_EXEC,
+ .help = "Initialize Watchpoint Unit",
+ },
+ {
+ .name = "sdram_init",
+ .handler = blackfin_handle_sdram_init_command,
+ .mode = COMMAND_EXEC,
+ .help = "Initialize SDRAM",
+ },
+ {
+ .name = "ddr_init",
+ .handler = blackfin_handle_ddr_init_command,
+ .mode = COMMAND_EXEC,
+ .help = "Initialize DDR",
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
+static const struct command_registration blackfin_command_handlers[] = {
+ {
+ .name = "blackfin",
+ .mode = COMMAND_ANY,
+ .help = "Blackfin command group",
+ .chain = blackfin_exec_command_handlers,
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
+struct target_type blackfin_target =
+{
+ .name = "blackfin",
+
+ .poll = blackfin_poll,
+ .arch_state = blackfin_arch_state,
+
+ .target_request_data = blackfin_target_request_data,
+
+ .halt = blackfin_halt,
+ .resume = blackfin_resume,
+ .step = blackfin_step,
+
+ .assert_reset = blackfin_assert_reset,
+ .deassert_reset = blackfin_deassert_reset,
+ .soft_reset_halt = NULL,
+
+ .get_gdb_reg_list = blackfin_get_gdb_reg_list,
+
+ .read_memory = blackfin_read_memory,
+ .write_memory = blackfin_write_memory,
+ .checksum_memory = blackfin_checksum_memory,
+ .blank_check_memory = blackfin_blank_check_memory,
+
+ .run_algorithm = blackfin_run_algorithm,
+
+ .add_breakpoint = blackfin_add_breakpoint,
+ .remove_breakpoint = blackfin_remove_breakpoint,
+ .add_watchpoint = blackfin_add_watchpoint,
+ .remove_watchpoint = blackfin_remove_watchpoint,
+
+ .commands = blackfin_command_handlers,
+ .target_create = blackfin_target_create,
+ .init_target = blackfin_init_target,
+ .examine = blackfin_examine,
+};
diff --git a/src/target/blackfin.h b/src/target/blackfin.h
new file mode 100644
index 0000000..18c9218
--- /dev/null
+++ b/src/target/blackfin.h
@@ -0,0 +1,78 @@
+/***************************************************************************
+ * Copyright (C) 2011 by Analog Devices, Inc. *
+ * Written by Jie Zhang <***@analog.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 BLACKFIN_H
+#define BLACKFIN_H
+
+#include "target.h"
+#include "blackfin_jtag.h"
+#include "blackfin_mem.h"
+
+#define BLACKFINNUMCOREREGS 53
+#define BLACKFIN_COMMON_MAGIC 0x05330533
+#define BLACKFIN_PART_MAXLEN 20
+
+struct blackfin_common
+{
+ uint32_t common_magic;
+ char part[BLACKFIN_PART_MAXLEN];
+ struct blackfin_jtag jtag_info;
+ const struct blackfin_mem_map *mem_map;
+ const struct blackfin_l1_map *l1_map;
+ const struct blackfin_sdram_config *sdram_config;
+ const struct blackfin_ddr_config *ddr_config;
+ uint32_t mdma_s0;
+ uint32_t mdma_d0;
+ struct reg_cache *core_cache;
+ // uint32_t core_regs[BLACKFINNUMCOREREGS];
+
+ unsigned int is_locked:1;
+ unsigned int is_running:1;
+ unsigned int is_interrupted:1;
+ unsigned int is_stepping:1;
+ unsigned int is_corefault:1;
+
+ unsigned int leave_stopped:1;
+ unsigned int status_pending_p:1;
+ unsigned int pending_is_breakpoint:1;
+
+ unsigned int l1_data_a_cache_enabled:1;
+ unsigned int l1_data_b_cache_enabled:1;
+ unsigned int l1_code_cache_enabled:1;
+
+ unsigned int dmem_control_valid_p:1;
+ unsigned int imem_control_valid_p:1;
+
+ int pending_signal;
+ uint32_t pending_stop_pc;
+
+ uint32_t dmem_control;
+ uint32_t imem_control;
+};
+
+static inline struct blackfin_common *
+target_to_blackfin(struct target *target)
+{
+ return (struct blackfin_common *)target->arch_info;
+}
+
+extern int blackfin_wait_clocks;
+
+#endif /* BLACKFIN_H */
diff --git a/src/target/blackfin_config.c b/src/target/blackfin_config.c
new file mode 100644
index 0000000..4830b89
--- /dev/null
+++ b/src/target/blackfin_config.c
@@ -0,0 +1,91 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "helper/log.h"
+
+#include "target.h"
+#include "blackfin.h"
+#include "blackfin_config.h"
+
+
+#if !defined(HAVE_LIBEXPAT)
+
+int blackfin_parse_config(struct target *target, const char *configs)
+{
+ LOG_WARNING("%s: cannot parse Blackfin XML config file; XML support was disabled at compile time", target_name(target));
+ return ERROR_FAIL;
+}
+
+#else /* HAVE_LIBEXPAT */
+
+#include "xml_support.h"
+
+/* Callback called by Expat on start of element.
+ This function handles the following elements:
+ * processor: unused now
+ * core: contains the memory map for the core
+ * memory: a memory region
+ * property: unused now
+ The target name is in format PROCESSOR or PROCESSOR.CORE */
+static void blackfin_config_start_element(void *data_, const XML_Char *name,
+ const XML_Char **attrs)
+{
+ struct blackfin_common *blackfin = data_;
+
+ if (strcmp(name, "processor") == 0)
+ {
+ /* not used for now */
+ }
+ else if (strcmp(name, "config") == 0)
+ {
+ const XML_Char *config_name;
+ uint32_t value;
+
+ config_name = xml_find_attribute(attrs, "name");
+ if (xml_parse_uint32(xml_find_attribute(attrs, "value"), &value) < 0)
+ return;
+ if (strcmp(config_name, "mdma_d0") == 0)
+ blackfin->mdma_d0 = value;
+ else if (strcmp(config_name, "mdma_s0") == 0)
+ blackfin->mdma_s0 = value;
+ }
+}
+
+static void blackfin_config_end_element(void *data_, const XML_Char *name)
+{
+ return;
+}
+
+static void blackfin_config_character_data(void *data_, const XML_Char *s, int len)
+{
+ return;
+}
+
+int blackfin_parse_config(struct target *target, const char *configs)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(target);
+ int retval;
+
+ XML_Parser parser = XML_ParserCreateNS(NULL, '!');
+ if (parser == NULL)
+ return ERROR_FAIL;
+
+ XML_SetElementHandler(parser, blackfin_config_start_element, blackfin_config_end_element);
+ XML_SetCharacterDataHandler(parser, blackfin_config_character_data);
+ XML_SetUserData(parser, blackfin);
+
+ retval = XML_Parse(parser, configs, strlen(configs), 1);
+ if (retval != XML_STATUS_OK)
+ {
+ enum XML_Error err = XML_GetErrorCode(parser);
+ LOG_ERROR("%s: cannot parse Blackfin XML config file [%s]",
+ target_name(target), XML_ErrorString(err));
+ return ERROR_FAIL;
+ }
+
+ return ERROR_OK;
+}
+
+#endif
+
diff --git a/src/target/blackfin_config.h b/src/target/blackfin_config.h
new file mode 100644
index 0000000..9803d85
--- /dev/null
+++ b/src/target/blackfin_config.h
@@ -0,0 +1,6 @@
+#ifndef BLACKFIN_CONFIG_H
+#define BLACKFIN_CONFIG_H
+
+extern int blackfin_parse_config(struct target *target, const char *configs);
+
+#endif /* BLACKFIN_CONFIG_H */
diff --git a/src/target/blackfin_insn.c b/src/target/blackfin_insn.c
new file mode 100644
index 0000000..73572f1
--- /dev/null
+++ b/src/target/blackfin_insn.c
@@ -0,0 +1,295 @@
+/***************************************************************************
+ * Copyright (C) 2011 by Analog Devices, Inc. *
+ * Written by Jie Zhang <***@analog.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 "blackfin_insn.h"
+
+uint32_t
+blackfin_gen_move (enum core_regnum dest, enum core_regnum src)
+{
+ uint32_t insn;
+
+ insn = 0x3000;
+ insn |= src & 0xf;
+ insn |= (dest & 0xf) << 3;
+ insn |= GROUP (src) << 6;
+ insn |= GROUP (dest) << 9;
+
+ return insn;
+}
+
+static uint32_t
+gen_ldstidxi (enum core_regnum reg,
+ enum core_regnum ptr, int32_t offset, int w, int sz)
+{
+ uint32_t insn;
+
+ insn = 0xe4000000;
+ insn |= (reg & 0xf) << 16;
+ insn |= (ptr & 0xf) << 19;
+
+ switch (sz)
+ {
+ case 0:
+ offset >>= 2;
+ break;
+ case 1:
+ offset >>= 1;
+ break;
+ case 2:
+ break;
+ default:
+ abort ();
+ }
+ if (offset > 32767 || offset < -32768)
+ abort ();
+ insn |= offset & 0xffff;
+
+ insn |= w << 25;
+ insn |= sz << 22;
+
+ return insn;
+}
+
+uint32_t
+blackfin_gen_load32_offset (enum core_regnum dest, enum core_regnum base, int32_t offset)
+{
+ return gen_ldstidxi (dest, base, offset, 0, 0);
+}
+
+uint32_t
+blackfin_gen_store32_offset (enum core_regnum base, int32_t offset, enum core_regnum src)
+{
+ return gen_ldstidxi (src, base, offset, 1, 0);
+}
+
+uint32_t
+blackfin_gen_load16z_offset (enum core_regnum dest, enum core_regnum base, int32_t offset)
+{
+ return gen_ldstidxi (dest, base, offset, 0, 1);
+}
+
+uint32_t
+blackfin_gen_store16_offset (enum core_regnum base, int32_t offset, enum core_regnum src)
+{
+ return gen_ldstidxi (src, base, offset, 1, 1);
+}
+
+uint32_t
+blackfin_gen_load8z_offset (enum core_regnum dest, enum core_regnum base, int32_t offset)
+{
+ return gen_ldstidxi (dest, base, offset, 0, 2);
+}
+
+uint32_t
+blackfin_gen_store8_offset (enum core_regnum base, int32_t offset, enum core_regnum src)
+{
+ return gen_ldstidxi (src, base, offset, 1, 2);
+}
+
+static uint32_t
+gen_ldst (enum core_regnum reg,
+ enum core_regnum ptr, int post_dec, int w, int sz)
+{
+ uint32_t insn;
+
+ insn = 0x9000;
+ insn |= reg & 0xf;
+ insn |= (ptr & 0xf) << 3;
+ insn |= post_dec << 7;
+ insn |= w << 9;
+ insn |= sz << 10;
+
+ return insn;
+}
+
+uint32_t
+blackfin_gen_load32pi (enum core_regnum dest, enum core_regnum base)
+{
+ return gen_ldst (dest, base, 0, 0, 0);
+}
+
+uint32_t
+blackfin_gen_store32pi (enum core_regnum base, enum core_regnum src)
+{
+ return gen_ldst (src, base, 0, 1, 0);
+}
+
+uint32_t
+blackfin_gen_load16zpi (enum core_regnum dest, enum core_regnum base)
+{
+ return gen_ldst (dest, base, 0, 0, 1);
+}
+
+uint32_t
+blackfin_gen_store16pi (enum core_regnum base, enum core_regnum src)
+{
+ return gen_ldst (src, base, 0, 1, 1);
+}
+
+uint32_t
+blackfin_gen_load8zpi (enum core_regnum dest, enum core_regnum base)
+{
+ return gen_ldst (dest, base, 0, 0, 2);
+}
+
+uint32_t
+blackfin_gen_store8pi (enum core_regnum base, enum core_regnum src)
+{
+ return gen_ldst (src, base, 0, 1, 2);
+}
+
+uint32_t
+blackfin_gen_load32 (enum core_regnum dest, enum core_regnum base)
+{
+ return gen_ldst (dest, base, 2, 0, 0);
+}
+
+uint32_t
+blackfin_gen_store32 (enum core_regnum base, enum core_regnum src)
+{
+ return gen_ldst (src, base, 2, 1, 0);
+}
+
+uint32_t
+blackfin_gen_load16z (enum core_regnum dest, enum core_regnum base)
+{
+ return gen_ldst (dest, base, 2, 0, 1);
+}
+
+uint32_t
+blackfin_gen_store16 (enum core_regnum base, enum core_regnum src)
+{
+ return gen_ldst (src, base, 2, 1, 1);
+}
+
+uint32_t
+blackfin_gen_load8z (enum core_regnum dest, enum core_regnum base)
+{
+ return gen_ldst (dest, base, 2, 0, 2);
+}
+
+uint32_t
+blackfin_gen_store8 (enum core_regnum base, enum core_regnum src)
+{
+ return gen_ldst (src, base, 2, 1, 2);
+}
+
+/* op
+ 0 prefetch
+ 1 flushinv
+ 2 flush
+ 3 iflush */
+static uint32_t
+gen_flush_insn (enum core_regnum addr, int op, int post_modify)
+{
+ uint32_t insn;
+
+ insn = 0x0240;
+ insn |= addr & 0xf;
+ insn |= op << 3;
+ insn |= post_modify << 5;
+
+ return insn;
+}
+
+uint32_t
+blackfin_gen_iflush (enum core_regnum addr)
+{
+ return gen_flush_insn (addr, 3, 0);
+}
+
+uint32_t
+blackfin_gen_iflush_pm (enum core_regnum addr)
+{
+ return gen_flush_insn (addr, 3, 1);
+}
+
+uint32_t
+blackfin_gen_flush (enum core_regnum addr)
+{
+ return gen_flush_insn (addr, 2, 0);
+}
+
+uint32_t
+blackfin_gen_flush_pm (enum core_regnum addr)
+{
+ return gen_flush_insn (addr, 2, 1);
+}
+
+uint32_t
+blackfin_gen_flushinv (enum core_regnum addr)
+{
+ return gen_flush_insn (addr, 1, 0);
+}
+
+uint32_t
+blackfin_gen_flushinv_pm (enum core_regnum addr)
+{
+ return gen_flush_insn (addr, 1, 1);
+}
+
+uint32_t
+blackfin_gen_prefetch (enum core_regnum addr)
+{
+ return gen_flush_insn (addr, 0, 0);
+}
+
+uint32_t
+blackfin_gen_prefetch_pm (enum core_regnum addr)
+{
+ return gen_flush_insn (addr, 0, 1);
+}
+
+uint32_t
+blackfin_gen_jump_reg (enum core_regnum addr)
+{
+ uint32_t insn;
+
+ insn = 0x0050;
+ insn |= addr & 0x7;
+
+ return insn;
+}
+
+uint32_t blackfin_gen_add_dreg_imm7 (enum core_regnum reg, int32_t imm7)
+{
+ uint32_t insn;
+
+ insn = 0x6400;
+ insn |= reg & 0x7;
+ insn |= (imm7 & 0x7f) << 3;
+
+ return insn;
+}
+
+uint32_t blackfin_gen_add_preg_imm7 (enum core_regnum reg, int32_t imm7)
+{
+ uint32_t insn;
+
+ insn = 0x6c00;
+ insn |= reg & 0x7;
+ insn |= (imm7 & 0x7f) << 3;
+
+ return insn;
+}
diff --git a/src/target/blackfin_insn.h b/src/target/blackfin_insn.h
new file mode 100644
index 0000000..8b3a88d
--- /dev/null
+++ b/src/target/blackfin_insn.h
@@ -0,0 +1,94 @@
+/***************************************************************************
+ * Copyright (C) 2011 by Analog Devices, Inc. *
+ * Written by Jie Zhang <***@analog.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 BLACKFIN_INSN_H
+#define BLACKFIN_INSN_H
+
+/* High-Nibble: group code, low nibble: register code. */
+#define T_REG_R 0x00
+#define T_REG_P 0x10
+#define T_REG_I 0x20
+#define T_REG_B 0x30
+#define T_REG_L 0x34
+#define T_REG_M 0x24
+#define T_REG_A 0x40
+
+enum core_regnum
+{
+ REG_R0 = T_REG_R, REG_R1, REG_R2, REG_R3, REG_R4, REG_R5, REG_R6, REG_R7,
+ REG_P0 = T_REG_P, REG_P1, REG_P2, REG_P3, REG_P4, REG_P5, REG_SP, REG_FP,
+ REG_I0 = T_REG_I, REG_I1, REG_I2, REG_I3,
+ REG_M0 = T_REG_M, REG_M1, REG_M2, REG_M3,
+ REG_B0 = T_REG_B, REG_B1, REG_B2, REG_B3,
+ REG_L0 = T_REG_L, REG_L1, REG_L2, REG_L3,
+ REG_A0x = T_REG_A, REG_A0w, REG_A1x, REG_A1w,
+ REG_ASTAT = 0x46,
+ REG_RETS = 0x47,
+ REG_LC0 = 0x60, REG_LT0, REG_LB0, REG_LC1, REG_LT1, REG_LB1,
+ REG_CYCLES, REG_CYCLES2,
+ REG_USP = 0x70, REG_SEQSTAT, REG_SYSCFG,
+ REG_RETI, REG_RETX, REG_RETN, REG_RETE, REG_EMUDAT,
+};
+
+#define CLASS_MASK 0xf0
+#define GROUP(x) (((x) & CLASS_MASK) >> 4)
+#define DREG_P(x) (((x) & CLASS_MASK) == T_REG_R)
+#define PREG_P(x) (((x) & CLASS_MASK) == T_REG_P)
+
+#define BLACKFIN_INSN_NOP 0x0000
+#define BLACKFIN_INSN_RTE 0x0014
+#define BLACKFIN_INSN_CSYNC 0x0023
+#define BLACKFIN_INSN_SSYNC 0x0024
+#define BLACKFIN_INSN_ILLEGAL 0xffffffff
+
+uint32_t blackfin_gen_move (enum core_regnum dest, enum core_regnum src);
+uint32_t blackfin_gen_load32_offset (enum core_regnum dest, enum core_regnum base, int32_t offset);
+uint32_t blackfin_gen_store32_offset (enum core_regnum base, int32_t offset, enum core_regnum src);
+uint32_t blackfin_gen_load16z_offset (enum core_regnum dest, enum core_regnum base, int32_t offset);
+uint32_t blackfin_gen_store16_offset (enum core_regnum base, int32_t offset, enum core_regnum src);
+uint32_t blackfin_gen_load8z_offset (enum core_regnum dest, enum core_regnum base, int32_t offset);
+uint32_t blackfin_gen_store8_offset (enum core_regnum base, int32_t offset, enum core_regnum src);
+uint32_t blackfin_gen_load32pi (enum core_regnum dest, enum core_regnum base);
+uint32_t blackfin_gen_store32pi (enum core_regnum base, enum core_regnum src);
+uint32_t blackfin_gen_load16zpi (enum core_regnum dest, enum core_regnum base);
+uint32_t blackfin_gen_store16pi (enum core_regnum base, enum core_regnum src);
+uint32_t blackfin_gen_load8zpi (enum core_regnum dest, enum core_regnum base);
+uint32_t blackfin_gen_store8pi (enum core_regnum base, enum core_regnum src);
+uint32_t blackfin_gen_load32 (enum core_regnum dest, enum core_regnum base);
+uint32_t blackfin_gen_store32 (enum core_regnum base, enum core_regnum src);
+uint32_t blackfin_gen_load16z (enum core_regnum dest, enum core_regnum base);
+uint32_t blackfin_gen_store16 (enum core_regnum base, enum core_regnum src);
+uint32_t blackfin_gen_load8z (enum core_regnum dest, enum core_regnum base);
+uint32_t blackfin_gen_store8 (enum core_regnum base, enum core_regnum src);
+uint32_t blackfin_gen_iflush (enum core_regnum addr);
+uint32_t blackfin_gen_iflush_pm (enum core_regnum addr);
+uint32_t blackfin_gen_flush (enum core_regnum addr);
+uint32_t blackfin_gen_flush_pm (enum core_regnum addr);
+uint32_t blackfin_gen_flushinv (enum core_regnum addr);
+uint32_t blackfin_gen_flushinv_pm (enum core_regnum addr);
+uint32_t blackfin_gen_prefetch (enum core_regnum addr);
+uint32_t blackfin_gen_prefetch_pm (enum core_regnum addr);
+uint32_t blackfin_gen_jump_reg (enum core_regnum addr);
+
+uint32_t blackfin_gen_add_dreg_imm7 (enum core_regnum reg, int32_t imm7);
+uint32_t blackfin_gen_add_preg_imm7 (enum core_regnum reg, int32_t imm7);
+
+#endif /* BLACKFIN_INSN_H */
diff --git a/src/target/blackfin_jtag.c b/src/target/blackfin_jtag.c
new file mode 100644
index 0000000..3b62034
--- /dev/null
+++ b/src/target/blackfin_jtag.c
@@ -0,0 +1,1011 @@
+/***************************************************************************
+ * Copyright (C) 2011 by Analog Devices, Inc. *
+ * Written by Jie Zhang <***@analog.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 <assert.h>
+#include <time.h>
+
+#include "helper/binarybuffer.h"
+#include "jtag/jtag.h"
+
+#include "blackfin.h"
+#include "blackfin_jtag.h"
+#include "blackfin_mem.h"
+
+/* tap instructions */
+#define BLACKFIN_IDCODE 0x02
+#define BLACKFIN_DBGCTL 0x04
+#define BLACKFIN_EMUIR 0x08
+#define BLACKFIN_DBGSTAT 0x0c
+#define BLACKFIN_EMUDAT 0x14
+#define BLACKFIN_EMUPC 0x1e
+#define BLACKFIN_BYPASS 0x1f
+
+static struct {
+ uint16_t dbgctl_sram_init;
+ uint16_t dbgctl_wakeup;
+ uint16_t dbgctl_sysrst;
+ uint16_t dbgctl_esstep;
+ uint16_t dbgctl_emudatsz_32;
+ uint16_t dbgctl_emudatsz_40;
+ uint16_t dbgctl_emudatsz_48;
+ uint16_t dbgctl_emudatsz_mask;
+ uint16_t dbgctl_emuirlpsz_2;
+ uint16_t dbgctl_emuirsz_64;
+ uint16_t dbgctl_emuirsz_48;
+ uint16_t dbgctl_emuirsz_32;
+ uint16_t dbgctl_emuirsz_mask;
+ uint16_t dbgctl_empen;
+ uint16_t dbgctl_emeen;
+ uint16_t dbgctl_emfen;
+ uint16_t dbgctl_empwr;
+
+ uint16_t dbgstat_lpdec1;
+ uint16_t dbgstat_core_fault;
+ uint16_t dbgstat_idle;
+ uint16_t dbgstat_in_reset;
+ uint16_t dbgstat_lpdec0;
+ uint16_t dbgstat_bist_done;
+ uint16_t dbgstat_emucause_mask;
+ uint16_t dbgstat_emuack;
+ uint16_t dbgstat_emuready;
+ uint16_t dbgstat_emudiovf;
+ uint16_t dbgstat_emudoovf;
+ uint16_t dbgstat_emudif;
+ uint16_t dbgstat_emudof;
+} bits = {
+ 0x1000, /* DBGCTL_SRAM_INIT */
+ 0x0800, /* DBGCTL_WAKEUP */
+ 0x0400, /* DBGCTL_SYSRST */
+ 0x0200, /* DBGCTL_ESSTEP */
+ 0x0000, /* DBGCTL_EMUDATSZ_32 */
+ 0x0080, /* DBGCTL_EMUDATSZ_40 */
+ 0x0100, /* DBGCTL_EMUDATSZ_48 */
+ 0x0180, /* DBGCTL_EMUDATSZ_MASK */
+ 0x0040, /* DBGCTL_EMUIRLPSZ_2 */
+ 0x0000, /* DBGCTL_EMUIRSZ_64 */
+ 0x0010, /* DBGCTL_EMUIRSZ_48 */
+ 0x0020, /* DBGCTL_EMUIRSZ_32 */
+ 0x0030, /* DBGCTL_EMUIRSZ_MASK */
+ 0x0008, /* DBGCTL_EMPEN */
+ 0x0004, /* DBGCTL_EMEEN */
+ 0x0002, /* DBGCTL_EMFEN */
+ 0x0001, /* DBGCTL_EMPWR */
+
+ 0x8000, /* DBGSTAT_LPDEC1 */
+ 0x4000, /* DBGSTAT_CORE_FAULT */
+ 0x2000, /* DBGSTAT_IDLE */
+ 0x1000, /* DBGSTAT_IN_RESET */
+ 0x0800, /* DBGSTAT_LPDEC0 */
+ 0x0400, /* DBGSTAT_BIST_DONE */
+ 0x03c0, /* DBGSTAT_EMUCAUSE_MASK */
+ 0x0020, /* DBGSTAT_EMUACK */
+ 0x0010, /* DBGSTAT_EMUREADY */
+ 0x0008, /* DBGSTAT_EMUDIOVF */
+ 0x0004, /* DBGSTAT_EMUDOOVF */
+ 0x0002, /* DBGSTAT_EMUDIF */
+ 0x0001, /* DBGSTAT_EMUDOF */
+};
+
+#define SWRST 0xffc00100
+
+#define WPIACTL 0xffe07000
+#define WPIACTL_WPAND 0x02000000
+#define WPIACTL_EMUSW5 0x01000000
+#define WPIACTL_EMUSW4 0x00800000
+#define WPIACTL_WPICNTEN5 0x00400000
+#define WPIACTL_WPICNTEN4 0x00200000
+#define WPIACTL_WPIAEN5 0x00100000
+#define WPIACTL_WPIAEN4 0x00080000
+#define WPIACTL_WPIRINV45 0x00040000
+#define WPIACTL_WPIREN45 0x00020000
+#define WPIACTL_EMUSW3 0x00010000
+#define WPIACTL_EMUSW2 0x00008000
+#define WPIACTL_WPICNTEN3 0x00004000
+#define WPIACTL_WPICNTEN2 0x00002000
+#define WPIACTL_WPIAEN3 0x00001000
+#define WPIACTL_WPIAEN2 0x00000800
+#define WPIACTL_WPIRINV23 0x00000400
+#define WPIACTL_WPIREN23 0x00000200
+#define WPIACTL_EMUSW1 0x00000100
+#define WPIACTL_EMUSW0 0x00000080
+#define WPIACTL_WPICNTEN1 0x00000040
+#define WPIACTL_WPICNTEN0 0x00000020
+#define WPIACTL_WPIAEN1 0x00000010
+#define WPIACTL_WPIAEN0 0x00000008
+#define WPIACTL_WPIRINV01 0x00000004
+#define WPIACTL_WPIREN01 0x00000002
+#define WPIACTL_WPPWR 0x00000001
+#define WPIA0 0xffe07040
+
+#define WPDACTL 0xffe07100
+#define WPDACTL_WPDACC1_R 0x00002000
+#define WPDACTL_WPDACC1_W 0x00001000
+#define WPDACTL_WPDACC1_A 0x00003000
+#define WPDACTL_WPDSRC1_1 0x00000800
+#define WPDACTL_WPDSRC1_0 0x00000400
+#define WPDACTL_WPDSRC1_A 0x00000c00
+#define WPDACTL_WPDACC0_R 0x00000200
+#define WPDACTL_WPDACC0_W 0x00000100
+#define WPDACTL_WPDACC0_A 0x00000300
+#define WPDACTL_WPDSRC0_1 0x00000080
+#define WPDACTL_WPDSRC0_0 0x00000040
+#define WPDACTL_WPDSRC0_A 0x000000c0
+#define WPDACTL_WPDCNTEN1 0x00000020
+#define WPDACTL_WPDCNTEN0 0x00000010
+#define WPDACTL_WPDAEN1 0x00000008
+#define WPDACTL_WPDAEN0 0x00000004
+#define WPDACTL_WPDRINV01 0x00000002
+#define WPDACTL_WPDREN01 0x00000001
+#define WPDA0 0xffe07140
+
+#define WPSTAT 0xffe07200
+
+static void buf_set(void *_buffer, unsigned first, unsigned num, uint32_t value)
+{
+ buf_set_u32(_buffer, first, num, flip_u32(value, num));
+}
+
+static uint32_t buf_get(const void *_buffer, unsigned first, unsigned num)
+{
+ return flip_u32(buf_get_u32(_buffer, first, num), num);
+}
+
+/* Force moving from Pause-DR to Shift-DR to go through Capture-DR.
+ Otherwise, it will go Exit2-DR, Shift-DR. Similar for IR scan.
+
+ The code is copied from arm11_dbgtap.c. We should move it to generic
+ code. */
+
+static const tap_state_t blackfin_move_pi_to_si_via_ci[] =
+{
+ TAP_IREXIT2, TAP_IRUPDATE, TAP_DRSELECT, TAP_IRSELECT, TAP_IRCAPTURE, TAP_IRSHIFT
+};
+
+static void blackfin_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(blackfin_move_pi_to_si_via_ci), blackfin_move_pi_to_si_via_ci);
+
+ jtag_add_ir_scan(tap, fields, state);
+}
+
+static const tap_state_t blackfin_move_pd_to_sd_via_cd[] =
+{
+ TAP_DREXIT2, TAP_DRUPDATE, TAP_DRSELECT, TAP_DRCAPTURE, TAP_DRSHIFT
+};
+
+void blackfin_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(blackfin_move_pd_to_sd_via_cd), blackfin_move_pd_to_sd_via_cd);
+
+ jtag_add_dr_scan(tap, num_fields, fields, state);
+}
+
+static void blackfin_add_wait_clocks(void)
+{
+ jtag_add_clocks(blackfin_wait_clocks);
+}
+
+void blackfin_set_instr(struct blackfin_jtag *jtag_info, uint8_t new_instr)
+{
+ struct jtag_tap *tap;
+
+ tap = jtag_info->target->tap;
+ assert(tap != NULL);
+
+ if (buf_get_u32(tap->cur_instr, 0, tap->ir_length) != 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;
+
+ blackfin_add_ir_scan_vc(tap, &field, TAP_IRPAUSE);
+ }
+}
+
+#define BLACKFIN_DBGCTL_BIT_SET(name) \
+ void blackfin_dbgctl_bit_set_##name(struct blackfin_jtag *jtag_info) \
+ { \
+ jtag_info->dbgctl |= bits.dbgctl_##name; \
+ }
+
+#define BLACKFIN_DBGCTL_BIT_CLEAR(name) \
+ void blackfin_dbgctl_bit_clear_##name(struct blackfin_jtag *jtag_info) \
+ { \
+ jtag_info->dbgctl &= ~bits.dbgctl_##name; \
+ }
+
+#define BLACKFIN_DBGCTL_IS(name) \
+ bool blackfin_dbgctl_is_##name(struct blackfin_jtag *jtag_info) \
+ { \
+ if (jtag_info->dbgctl & bits.dbgctl_##name) \
+ return true; \
+ else \
+ return false; \
+ }
+
+#define BLACKFIN_DBGCTL_BIT_OP(name) \
+ BLACKFIN_DBGCTL_BIT_SET(name) \
+ BLACKFIN_DBGCTL_BIT_CLEAR(name) \
+ BLACKFIN_DBGCTL_IS(name)
+
+BLACKFIN_DBGCTL_BIT_OP(sram_init)
+BLACKFIN_DBGCTL_BIT_OP(wakeup)
+BLACKFIN_DBGCTL_BIT_OP(sysrst)
+BLACKFIN_DBGCTL_BIT_OP(esstep)
+BLACKFIN_DBGCTL_BIT_OP(emudatsz_32)
+BLACKFIN_DBGCTL_BIT_OP(emudatsz_40)
+BLACKFIN_DBGCTL_BIT_OP(emudatsz_48)
+BLACKFIN_DBGCTL_BIT_OP(emuirlpsz_2)
+BLACKFIN_DBGCTL_BIT_OP(emuirsz_64)
+BLACKFIN_DBGCTL_BIT_OP(emuirsz_48)
+BLACKFIN_DBGCTL_BIT_OP(emuirsz_32)
+BLACKFIN_DBGCTL_BIT_OP(empen)
+BLACKFIN_DBGCTL_BIT_OP(emeen)
+BLACKFIN_DBGCTL_BIT_OP(emfen)
+BLACKFIN_DBGCTL_BIT_OP(empwr)
+
+#define BLACKFIN_DBGSTAT_BIT_IS(name) \
+ bool blackfin_dbgstat_is_##name(struct blackfin_jtag *jtag_info) \
+ { \
+ if (jtag_info->dbgstat & bits.dbgstat_##name) \
+ return true; \
+ else \
+ return false; \
+ }
+
+BLACKFIN_DBGSTAT_BIT_IS(lpdec1)
+BLACKFIN_DBGSTAT_BIT_IS(core_fault)
+BLACKFIN_DBGSTAT_BIT_IS(idle)
+BLACKFIN_DBGSTAT_BIT_IS(in_reset)
+BLACKFIN_DBGSTAT_BIT_IS(lpdec0)
+BLACKFIN_DBGSTAT_BIT_IS(bist_done)
+BLACKFIN_DBGSTAT_BIT_IS(emuack)
+BLACKFIN_DBGSTAT_BIT_IS(emuready)
+BLACKFIN_DBGSTAT_BIT_IS(emudiovf)
+BLACKFIN_DBGSTAT_BIT_IS(emudoovf)
+BLACKFIN_DBGSTAT_BIT_IS(emudif)
+BLACKFIN_DBGSTAT_BIT_IS(emudof)
+
+static void blackfin_shift_dbgctl(struct blackfin_jtag *jtag_info, int state)
+{
+ struct scan_field field;
+ uint8_t t[4];
+
+ LOG_DEBUG("shift DBGCTL = %04x end state is %s", (unsigned) jtag_info->dbgctl, tap_state_name(state));
+
+ field.num_bits = 16;
+ field.out_value = t;
+ buf_set(t, 0, field.num_bits, jtag_info->dbgctl);
+ field.in_value = NULL;
+ blackfin_add_dr_scan_vc(jtag_info->target->tap, 1, &field, state);
+
+ if (state == TAP_IDLE)
+ blackfin_add_wait_clocks();
+}
+
+static void blackfin_emuir_setup_field(struct scan_field *field, uint8_t *t, uint32_t insn)
+{
+ if ((insn & 0xffff0000) == 0)
+ insn <<= 16;
+
+ field->num_bits = 32;
+ field->out_value = t;
+ buf_set(t, 0, field->num_bits, insn);
+ field->in_value = NULL;
+}
+
+void blackfin_emuir_set(struct blackfin_jtag *jtag_info, uint32_t insn, int state)
+{
+ struct scan_field field;
+ uint8_t t[4];
+
+ /* If the EMUIRLPSZ_2 is set in DBGCTL, clear it. */
+ if (blackfin_dbgctl_is_emuirlpsz_2(jtag_info))
+ {
+ blackfin_set_instr(jtag_info, BLACKFIN_DBGCTL);
+ blackfin_dbgctl_bit_clear_emuirlpsz_2(jtag_info);
+ blackfin_shift_dbgctl(jtag_info, TAP_DRPAUSE);
+ }
+
+ blackfin_set_instr(jtag_info, BLACKFIN_EMUIR);
+
+ blackfin_emuir_setup_field(&field, t, insn);
+ blackfin_add_dr_scan_vc(jtag_info->target->tap, 1, &field, state);
+ jtag_info->emuir_a = insn;
+
+ if (state == TAP_IDLE)
+ blackfin_add_wait_clocks();
+}
+
+void blackfin_emuir_set_2(struct blackfin_jtag *jtag_info, uint32_t insn1, uint32_t insn2, int state)
+{
+ struct scan_field field1, field2;
+ uint8_t t[4];
+
+ /* If the EMUIRLPSZ_2 is clear in DBGCTL, set it. */
+ if (!blackfin_dbgctl_is_emuirlpsz_2(jtag_info))
+ {
+ blackfin_set_instr(jtag_info, BLACKFIN_DBGCTL);
+ blackfin_dbgctl_bit_set_emuirlpsz_2(jtag_info);
+ blackfin_shift_dbgctl(jtag_info, TAP_DRPAUSE);
+ }
+
+ blackfin_set_instr(jtag_info, BLACKFIN_EMUIR);
+
+ blackfin_emuir_setup_field(&field2, t, insn2);
+ blackfin_add_dr_scan_vc(jtag_info->target->tap, 1, &field2, TAP_DRPAUSE);
+ jtag_info->emuir_b = insn2;
+
+ blackfin_emuir_setup_field(&field1, t, insn1);
+ blackfin_add_dr_scan_vc(jtag_info->target->tap, 1, &field1, state);
+ jtag_info->emuir_a = insn1;
+
+ if (state == TAP_IDLE)
+ blackfin_add_wait_clocks();
+}
+
+/*
+static void blackfin_emuir_set_nop(struct blackfin_jtag *jtag_info)
+{
+ if (blackfin_dbgctl_is_emuirlpsz_2(jtag_info))
+ blackfin_emuir_set_2(jtag_info, BLACKFIN_INSN_NOP, BLACKFIN_INSN_NOP, TAP_DRPAUSE);
+ else
+ blackfin_emuir_set(jtag_info, BLACKFIN_INSN_NOP, TAP_DRPAUSE);
+}
+*/
+
+void blackfin_read_dbgstat(struct blackfin_jtag *jtag_info)
+{
+ struct scan_field field;
+ uint16_t dbgstat;
+ uint8_t t[4];
+ int retval;
+
+ blackfin_set_instr(jtag_info, BLACKFIN_DBGSTAT);
+
+ field.num_bits = 16;
+ field.out_value = NULL;
+ field.in_value = t;
+
+ blackfin_add_dr_scan_vc(jtag_info->target->tap, 1, &field, TAP_DRPAUSE);
+
+ retval = jtag_execute_queue();
+ assert(retval == ERROR_OK);
+
+ dbgstat = buf_get(t, 0, 16);
+
+ if (jtag_info->dbgstat != dbgstat)
+ LOG_DEBUG("DBGSTAT = %04x (OLD %04x)",
+ (unsigned) dbgstat,
+ (unsigned) jtag_info->dbgstat);
+
+ jtag_info->dbgstat = dbgstat;
+}
+
+uint16_t blackfin_dbgstat_emucause(struct blackfin_jtag *jtag_info)
+{
+ uint16_t mask, emucause;
+
+ mask = bits.dbgstat_emucause_mask;
+ emucause = jtag_info->dbgstat & mask;
+
+ while (!(mask & 0x1))
+ {
+ mask >>= 1;
+ emucause >>= 1;
+ }
+
+ return emucause;
+}
+
+void blackfin_wpstat_get(struct blackfin_jtag *jtag_info)
+{
+ uint32_t p0, r0;
+
+ p0 = blackfin_get_p0(jtag_info);
+ r0 = blackfin_get_r0(jtag_info);
+
+ blackfin_set_p0(jtag_info, WPSTAT);
+ blackfin_emuir_set(jtag_info, blackfin_gen_load32_offset(REG_R0, REG_P0, 0), TAP_IDLE);
+ jtag_info->wpstat = blackfin_register_get(jtag_info, REG_R0);
+
+ blackfin_set_p0(jtag_info, p0);
+ blackfin_set_r0(jtag_info, r0);
+}
+
+void blackfin_wpstat_clear(struct blackfin_jtag *jtag_info)
+{
+ uint32_t p0, r0;
+
+ p0 = blackfin_get_p0(jtag_info);
+ r0 = blackfin_get_r0(jtag_info);
+
+ blackfin_set_p0(jtag_info, WPSTAT);
+ blackfin_set_r0(jtag_info, jtag_info->wpstat);
+ blackfin_emuir_set(jtag_info, blackfin_gen_store32_offset(REG_P0, 0, REG_R0), TAP_IDLE);
+ jtag_info->wpstat = 0;
+
+ blackfin_set_p0(jtag_info, p0);
+ blackfin_set_r0(jtag_info, r0);
+}
+
+void blackfin_emulation_enable(struct blackfin_jtag *jtag_info)
+{
+ /* TODO check if emulation has already been enabled. */
+
+ blackfin_set_instr(jtag_info, BLACKFIN_DBGCTL);
+
+ blackfin_dbgctl_bit_set_empwr(jtag_info);
+ blackfin_shift_dbgctl(jtag_info, TAP_IDLE);
+
+ blackfin_dbgctl_bit_set_emfen(jtag_info);
+ blackfin_shift_dbgctl(jtag_info, TAP_IDLE);
+
+ blackfin_dbgctl_bit_set_emuirsz_32(jtag_info);
+ blackfin_shift_dbgctl(jtag_info, TAP_IDLE);
+}
+
+void blackfin_emulation_disable(struct blackfin_jtag *jtag_info)
+{
+ blackfin_set_instr(jtag_info, BLACKFIN_DBGCTL);
+ blackfin_dbgctl_bit_clear_empwr(jtag_info);
+ blackfin_shift_dbgctl(jtag_info, TAP_IDLE);
+}
+
+void blackfin_emulation_trigger(struct blackfin_jtag *jtag_info)
+{
+ /* TODO check if we have already been in emulation mode. */
+
+ blackfin_emuir_set(jtag_info, BLACKFIN_INSN_NOP, TAP_DRPAUSE);
+
+ blackfin_set_instr(jtag_info, BLACKFIN_DBGCTL);
+ blackfin_dbgctl_bit_set_wakeup(jtag_info);
+ blackfin_dbgctl_bit_set_emeen(jtag_info);
+ blackfin_shift_dbgctl(jtag_info, TAP_IDLE);
+}
+
+void blackfin_emulation_return(struct blackfin_jtag *jtag_info)
+{
+ blackfin_emuir_set(jtag_info, BLACKFIN_INSN_RTE, TAP_DRPAUSE);
+
+ blackfin_set_instr(jtag_info, BLACKFIN_DBGCTL);
+ blackfin_dbgctl_bit_clear_emeen(jtag_info);
+ blackfin_dbgctl_bit_clear_wakeup(jtag_info);
+ blackfin_shift_dbgctl(jtag_info, TAP_IDLE);
+}
+
+uint32_t blackfin_register_get(struct blackfin_jtag *jtag_info, enum core_regnum reg)
+{
+ struct scan_field field;
+ uint8_t t[4];
+ uint32_t r0 = 0;
+ int retval;
+
+ if (DREG_P(reg) || PREG_P(reg))
+ {
+ blackfin_emuir_set(jtag_info, blackfin_gen_move(REG_EMUDAT, reg), TAP_IDLE);
+ }
+ else
+ {
+ r0 = blackfin_get_r0(jtag_info);
+ blackfin_emuir_set_2(jtag_info, blackfin_gen_move(REG_R0, reg), blackfin_gen_move(REG_EMUDAT, REG_R0), TAP_IDLE);
+ }
+
+ blackfin_set_instr(jtag_info, BLACKFIN_EMUDAT);
+
+ field.num_bits = 32;
+ field.out_value = NULL;
+ field.in_value = t;
+ blackfin_add_dr_scan_vc(jtag_info->target->tap, 1, &field, TAP_DRPAUSE);
+
+ retval = jtag_execute_queue();
+ assert(retval == ERROR_OK);
+
+ if (!DREG_P(reg) && !PREG_P(reg))
+ blackfin_set_r0(jtag_info, r0);
+
+ return buf_get(t, 0, 32);
+}
+
+void blackfin_register_set(struct blackfin_jtag *jtag_info, enum core_regnum reg, uint32_t value)
+{
+ struct scan_field field;
+ uint8_t t[4];
+ uint32_t r0 = 0;
+
+ if (!DREG_P(reg) && !PREG_P(reg))
+ r0 = blackfin_get_r0(jtag_info);
+
+ blackfin_set_instr(jtag_info, BLACKFIN_EMUDAT);
+
+ field.num_bits = 32;
+ field.out_value = t;
+ buf_set(t, 0, field.num_bits, value);
+ field.in_value = NULL;
+ blackfin_add_dr_scan_vc(jtag_info->target->tap, 1, &field, TAP_DRPAUSE);
+
+ if (DREG_P(reg) || PREG_P(reg))
+ {
+ blackfin_emuir_set(jtag_info, blackfin_gen_move(reg, REG_EMUDAT), TAP_IDLE);
+ }
+ else
+ {
+ blackfin_emuir_set_2(jtag_info, blackfin_gen_move(REG_R0, REG_EMUDAT), blackfin_gen_move(reg, REG_R0), TAP_IDLE);
+ blackfin_set_r0(jtag_info, r0);
+ }
+}
+
+uint32_t blackfin_get_p0(struct blackfin_jtag *jtag_info)
+{
+ return blackfin_register_get(jtag_info, REG_P0);
+}
+
+uint32_t blackfin_get_r0(struct blackfin_jtag *jtag_info)
+{
+ return blackfin_register_get(jtag_info, REG_R0);
+}
+
+void blackfin_set_p0(struct blackfin_jtag *jtag_info, uint32_t value)
+{
+ blackfin_register_set(jtag_info, REG_P0, value);
+}
+
+void blackfin_set_r0(struct blackfin_jtag *jtag_info, uint32_t value)
+{
+ blackfin_register_set(jtag_info, REG_R0, value);
+}
+
+void blackfin_check_emuready(struct blackfin_jtag *jtag_info)
+{
+ int emuready;
+
+ blackfin_read_dbgstat(jtag_info);
+ if (blackfin_dbgstat_is_emuready(jtag_info))
+ emuready = 1;
+ else
+ emuready = 0;
+
+ assert(emuready);
+}
+
+/* system reset by writing to SWRST MMR */
+void blackfin_system_reset(struct blackfin_jtag *jtag_info)
+{
+ uint32_t p0, r0;
+
+ p0 = blackfin_get_p0(jtag_info);
+ r0 = blackfin_get_r0(jtag_info);
+
+ /*
+ * Flush all system events like cache line fills. Otherwise,
+ * when we reset the system side, any events that the core was
+ * waiting on no longer exist, and the core hangs.
+ */
+ blackfin_emuir_set(jtag_info, BLACKFIN_INSN_SSYNC, TAP_IDLE);
+
+ /* Write 0x7 to SWRST to start system reset. */
+ blackfin_set_p0(jtag_info, SWRST);
+ blackfin_set_r0(jtag_info, 0x7);
+ blackfin_emuir_set(jtag_info, blackfin_gen_store16_offset(REG_P0, 0, REG_R0), TAP_IDLE);
+
+ /*
+ * Delay at least 10 SCLKs instead of doing an SSYNC insn.
+ * Since the system is being reset, the sync signal might
+ * not be asserted, and so the core hangs waiting for it.
+ * The magic "10" number was given to us by ADI designers
+ * who looked at the schematic and ran some simulations.
+ */
+ usleep(100);
+
+ /* Write 0x0 to SWRST to stop system reset. */
+ blackfin_set_r0(jtag_info, 0);
+ blackfin_emuir_set(jtag_info, blackfin_gen_store16_offset(REG_P0, 0, REG_R0), TAP_IDLE);
+
+ /* Delay at least 1 SCLK; see comment above for more info. */
+ usleep(100);
+
+ blackfin_set_p0(jtag_info, p0);
+ blackfin_set_r0(jtag_info, r0);
+}
+
+static void blackfin_wait_in_reset(struct blackfin_jtag *jtag_info)
+{
+ int in_reset;
+ int waited = 0;
+ const struct timespec reset_wait = {0, 5000000};
+
+ try_again:
+
+ blackfin_read_dbgstat(jtag_info);
+ if (blackfin_dbgstat_is_in_reset(jtag_info))
+ in_reset = 1;
+ else
+ in_reset = 0;
+
+ if (waited)
+ assert(in_reset);
+
+ if (!in_reset)
+ {
+ nanosleep (&reset_wait, NULL);
+ waited = 1;
+ goto try_again;
+ }
+}
+
+static void blackfin_wait_reset(struct blackfin_jtag *jtag_info)
+{
+ int in_reset;
+ int waited = 0;
+ const struct timespec reset_wait = {0, 5000000};
+
+ try_again:
+
+ blackfin_read_dbgstat(jtag_info);
+ if (blackfin_dbgstat_is_in_reset(jtag_info))
+ in_reset = 1;
+ else
+ in_reset = 0;
+
+ if (waited)
+ assert(!in_reset);
+
+ if (in_reset)
+ {
+ nanosleep (&reset_wait, NULL);
+ waited = 1;
+ goto try_again;
+ }
+}
+
+/* core reset by setting SYSRST bit in DBGCTL */
+void blackfin_core_reset(struct blackfin_jtag *jtag_info)
+{
+ blackfin_emulation_disable(jtag_info);
+
+ blackfin_emuir_set(jtag_info, BLACKFIN_INSN_NOP, TAP_DRPAUSE);
+
+ blackfin_set_instr(jtag_info, BLACKFIN_DBGCTL);
+ blackfin_dbgctl_bit_set_sram_init(jtag_info);
+ blackfin_dbgctl_bit_set_sysrst(jtag_info);
+ blackfin_shift_dbgctl(jtag_info, TAP_IDLE);
+
+ blackfin_wait_in_reset(jtag_info);
+
+ blackfin_set_instr(jtag_info, BLACKFIN_DBGCTL);
+ blackfin_dbgctl_bit_clear_sysrst(jtag_info);
+ blackfin_shift_dbgctl(jtag_info, TAP_IDLE);
+
+ blackfin_wait_reset(jtag_info);
+
+ blackfin_emulation_enable(jtag_info);
+ blackfin_emulation_trigger(jtag_info);
+
+ blackfin_set_instr(jtag_info, BLACKFIN_DBGCTL);
+ blackfin_dbgctl_bit_clear_sram_init(jtag_info);
+ blackfin_shift_dbgctl(jtag_info, TAP_IDLE);
+}
+
+void blackfin_emupc_get(struct blackfin_jtag *jtag_info)
+{
+ struct scan_field field;
+ uint8_t t[4];
+ uint32_t value;
+ int retval;
+
+ blackfin_set_instr(jtag_info, BLACKFIN_EMUPC);
+
+ field.num_bits = 32;
+ field.out_value = NULL;
+ field.in_value = t;
+
+ blackfin_add_dr_scan_vc(jtag_info->target->tap, 1, &field, TAP_DRPAUSE);
+
+ retval = jtag_execute_queue();
+ assert(retval == ERROR_OK);
+
+ value = buf_get(t, 0, field.num_bits);
+ jtag_info->emupc = value;
+}
+
+void blackfin_emupc_reset(struct blackfin_jtag *jtag_info)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(jtag_info->target);
+ uint32_t p0;
+
+ p0 = blackfin_get_p0(jtag_info);
+ blackfin_set_p0(jtag_info, blackfin->l1_map->l1_code);
+ blackfin_emuir_set(jtag_info, blackfin_gen_jump_reg(REG_P0), TAP_IDLE);
+ blackfin_set_p0(jtag_info, p0);
+}
+
+void blackfin_emudat_set(struct blackfin_jtag *jtag_info, uint32_t value, tap_state_t state)
+{
+ struct scan_field field;
+ uint8_t t[4];
+
+ blackfin_set_instr(jtag_info, BLACKFIN_EMUDAT);
+
+ field.num_bits = 32;
+ field.out_value = t;
+ buf_set(t, 0, field.num_bits, value);
+ field.in_value = NULL;
+
+ blackfin_add_dr_scan_vc(jtag_info->target->tap, 1, &field, state);
+ jtag_info->emudat_in = value;
+
+ if (state == TAP_IDLE)
+ blackfin_add_wait_clocks();
+}
+
+uint32_t blackfin_emudat_get(struct blackfin_jtag *jtag_info, tap_state_t state)
+{
+ struct scan_field field;
+ uint8_t t[4];
+ uint32_t value;
+ const uint8_t seq = 0;
+ int retval;
+
+ if (state == TAP_IDLE)
+ {
+ if (cmd_queue_cur_state != TAP_RESET && cmd_queue_cur_state != TAP_IDLE)
+ jtag_add_statemove(TAP_IDLE);
+ else
+ jtag_add_tms_seq(1, &seq, TAP_IDLE);
+
+ blackfin_add_wait_clocks();
+ }
+
+ blackfin_set_instr(jtag_info, BLACKFIN_EMUDAT);
+
+ field.num_bits = 32;
+ field.out_value = NULL;
+ field.in_value = t;
+
+ blackfin_add_dr_scan_vc(jtag_info->target->tap, 1, &field, TAP_DRPAUSE);
+
+ retval = jtag_execute_queue();
+ assert(retval == ERROR_OK);
+
+ value = buf_get(t, 0, field.num_bits);
+ jtag_info->emudat_out = value;
+
+ return value;
+}
+
+void blackfin_wpu_init(struct blackfin_jtag *jtag_info)
+{
+ uint32_t p0, r0;
+ uint32_t wpiactl, wpdactl;
+
+ LOG_DEBUG("-");
+
+ p0 = blackfin_get_p0(jtag_info);
+ r0 = blackfin_get_r0(jtag_info);
+
+ blackfin_set_p0(jtag_info, WPIACTL);
+
+ wpiactl = WPIACTL_WPPWR;
+
+ blackfin_set_r0(jtag_info, wpiactl);
+
+ blackfin_emuir_set(jtag_info, blackfin_gen_store32_offset(REG_P0, 0, REG_R0), TAP_IDLE);
+
+ wpiactl |= WPIACTL_EMUSW5 | WPIACTL_EMUSW4 | WPIACTL_EMUSW3;
+ wpiactl |= WPIACTL_EMUSW2 | WPIACTL_EMUSW1 | WPIACTL_EMUSW0;
+
+ blackfin_set_r0(jtag_info, wpiactl);
+ blackfin_emuir_set(jtag_info, blackfin_gen_store32_offset(REG_P0, 0, REG_R0), TAP_IDLE);
+
+ wpdactl = WPDACTL_WPDSRC1_A | WPDACTL_WPDSRC0_A;
+
+ blackfin_set_r0(jtag_info, wpdactl);
+ blackfin_emuir_set(jtag_info, blackfin_gen_store32_offset(REG_P0, WPDACTL - WPIACTL, REG_R0),
+ TAP_IDLE);
+
+ blackfin_set_r0(jtag_info, 0);
+ blackfin_emuir_set(jtag_info, blackfin_gen_store32_offset(REG_P0, WPSTAT - WPIACTL, REG_R0),
+ TAP_IDLE);
+
+ jtag_info->wpiactl = wpiactl;
+ jtag_info->wpdactl = wpdactl;
+
+ blackfin_set_p0(jtag_info, p0);
+ blackfin_set_r0(jtag_info, r0);
+}
+
+static uint32_t wpiaen[] = {
+ WPIACTL_WPIAEN0,
+ WPIACTL_WPIAEN1,
+ WPIACTL_WPIAEN2,
+ WPIACTL_WPIAEN3,
+ WPIACTL_WPIAEN4,
+ WPIACTL_WPIAEN5,
+};
+
+void blackfin_wpu_set_wpia(struct blackfin_jtag *jtag_info, int n, uint32_t addr, int enable)
+{
+ uint32_t p0, r0;
+
+ p0 = blackfin_get_p0(jtag_info);
+ r0 = blackfin_get_r0(jtag_info);
+
+ blackfin_register_set(jtag_info, REG_P0, WPIACTL);
+ if (enable)
+ {
+ jtag_info->wpiactl += wpiaen[n];
+ blackfin_register_set(jtag_info, REG_R0, addr);
+ blackfin_emuir_set(jtag_info,
+ blackfin_gen_store32_offset(REG_P0, WPIA0 + 4 * n - WPIACTL, REG_R0),
+ TAP_IDLE);
+ }
+ else
+ {
+ jtag_info->wpiactl &= ~wpiaen[n];
+ }
+
+ blackfin_register_set(jtag_info, REG_R0, jtag_info->wpiactl);
+ blackfin_emuir_set(jtag_info,
+ blackfin_gen_store32_offset(REG_P0, 0, REG_R0),
+ TAP_IDLE);
+
+ blackfin_set_p0(jtag_info, p0);
+ blackfin_set_r0(jtag_info, r0);
+}
+
+void blackfin_wpu_set_wpda(struct blackfin_jtag *jtag_info, int n)
+{
+ uint32_t p0, r0;
+ uint32_t addr = jtag_info->hwwps[n].addr;
+ uint32_t len = jtag_info->hwwps[n].len;
+ int mode = jtag_info->hwwps[n].mode;
+ bool range = jtag_info->hwwps[n].range;
+
+ p0 = blackfin_get_p0(jtag_info);
+ r0 = blackfin_get_r0(jtag_info);
+
+ blackfin_register_set(jtag_info, REG_P0, WPDACTL);
+
+ /* Currently LEN > 4 iff RANGE. But in future, it can change. */
+ if (len > 4 || range)
+ {
+ assert (n == 0);
+
+ switch (mode)
+ {
+ case WPDA_DISABLE:
+ jtag_info->wpdactl &= ~WPDACTL_WPDREN01;
+ break;
+ case WPDA_WRITE:
+ jtag_info->wpdactl &= ~WPDACTL_WPDACC0_R;
+ jtag_info->wpdactl |= WPDACTL_WPDREN01 | WPDACTL_WPDACC0_W;
+ break;
+ case WPDA_READ:
+ jtag_info->wpdactl &= ~WPDACTL_WPDACC0_W;
+ jtag_info->wpdactl |= WPDACTL_WPDREN01 | WPDACTL_WPDACC0_R;
+ break;
+ case WPDA_ALL:
+ jtag_info->wpdactl |= WPDACTL_WPDREN01 | WPDACTL_WPDACC0_A;
+ break;
+ default:
+ abort ();
+ }
+
+ if (mode != WPDA_DISABLE)
+ {
+ blackfin_register_set(jtag_info, REG_R0, addr - 1);
+ blackfin_emuir_set(jtag_info,
+ blackfin_gen_store32_offset(REG_P0, WPDA0 - WPDACTL, REG_R0),
+ TAP_IDLE);
+ blackfin_register_set(jtag_info, REG_R0, addr + len - 1);
+ blackfin_emuir_set(jtag_info,
+ blackfin_gen_store32_offset(REG_P0, WPDA0 + 4 - WPDACTL, REG_R0),
+ TAP_IDLE);
+ }
+ }
+ else
+ {
+ if (n == 0)
+ switch (mode)
+ {
+ case WPDA_DISABLE:
+ jtag_info->wpdactl &= ~WPDACTL_WPDAEN0;
+ break;
+ case WPDA_WRITE:
+ jtag_info->wpdactl &= ~WPDACTL_WPDACC0_R;
+ jtag_info->wpdactl |= WPDACTL_WPDAEN0 | WPDACTL_WPDACC0_W;
+ break;
+ case WPDA_READ:
+ jtag_info->wpdactl &= ~WPDACTL_WPDACC0_W;
+ jtag_info->wpdactl |= WPDACTL_WPDAEN0 | WPDACTL_WPDACC0_R;
+ break;
+ case WPDA_ALL:
+ jtag_info->wpdactl |= WPDACTL_WPDAEN0 | WPDACTL_WPDACC0_A;
+ break;
+ default:
+ abort ();
+ }
+ else
+ switch (mode)
+ {
+ case WPDA_DISABLE:
+ jtag_info->wpdactl &= ~WPDACTL_WPDAEN1;
+ break;
+ case WPDA_WRITE:
+ jtag_info->wpdactl &= ~WPDACTL_WPDACC1_R;
+ jtag_info->wpdactl |= WPDACTL_WPDAEN1 | WPDACTL_WPDACC1_W;
+ break;
+ case WPDA_READ:
+ jtag_info->wpdactl &= ~WPDACTL_WPDACC1_W;
+ jtag_info->wpdactl |= WPDACTL_WPDAEN1 | WPDACTL_WPDACC1_R;
+ break;
+ case WPDA_ALL:
+ jtag_info->wpdactl |= WPDACTL_WPDAEN1 | WPDACTL_WPDACC1_A;
+ break;
+ default:
+ abort ();
+ }
+ if (mode != WPDA_DISABLE)
+ {
+ blackfin_register_set(jtag_info, REG_R0, addr);
+ blackfin_emuir_set(jtag_info,
+ blackfin_gen_store32_offset(REG_P0, WPDA0 + 4 * n - WPDACTL, REG_R0),
+ TAP_IDLE);
+ }
+ }
+
+ blackfin_register_set(jtag_info, REG_R0, jtag_info->wpdactl);
+ blackfin_emuir_set(jtag_info,
+ blackfin_gen_store32_offset(REG_P0, 0, REG_R0),
+ TAP_IDLE);
+
+ blackfin_set_p0(jtag_info, p0);
+ blackfin_set_r0(jtag_info, r0);
+}
+
+void blackfin_single_step(struct blackfin_jtag *jtag_info, bool in_stepping)
+{
+ if (!in_stepping)
+ {
+ blackfin_set_instr(jtag_info, BLACKFIN_DBGCTL);
+ blackfin_dbgctl_bit_set_esstep(jtag_info);
+ blackfin_shift_dbgctl(jtag_info, TAP_DRPAUSE);
+ }
+ blackfin_emuir_set(jtag_info, BLACKFIN_INSN_RTE, TAP_IDLE);
+ blackfin_check_emuready(jtag_info);
+ if (!in_stepping)
+ {
+ blackfin_set_instr(jtag_info, BLACKFIN_DBGCTL);
+ blackfin_dbgctl_bit_clear_esstep(jtag_info);
+ blackfin_shift_dbgctl(jtag_info, TAP_DRPAUSE);
+ }
+}
diff --git a/src/target/blackfin_jtag.h b/src/target/blackfin_jtag.h
new file mode 100644
index 0000000..818b997
--- /dev/null
+++ b/src/target/blackfin_jtag.h
@@ -0,0 +1,146 @@
+/***************************************************************************
+ * Copyright (C) 2011 by Analog Devices, Inc. *
+ * Written by Jie Zhang <***@analog.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 BLACKFIN_JTAG_H
+#define BLACKFIN_JTAG_H
+
+#include "jtag/jtag.h"
+#include "target.h"
+#include "blackfin_insn.h"
+
+#define WPDA_DISABLE 0
+#define WPDA_WRITE 1
+#define WPDA_READ 2
+#define WPDA_ALL 3
+
+struct blackfin_hwwpt
+{
+ uint32_t addr;
+ uint32_t len;
+ int mode;
+ /* If range is true, this hardware watchpoint is combined with the
+ next watchpoint to form a range watchpoint. */
+ bool range;
+ /* True if this hardware watchpoint has been used, otherwise false. */
+ bool used;
+};
+
+#define BLACKFIN_MAX_HWBREAKPOINTS 6
+#define BLACKFIN_MAX_HWWATCHPOINTS 2
+
+struct blackfin_jtag
+{
+ struct target *target;
+
+ uint16_t dbgctl;
+ uint16_t dbgstat;
+ uint64_t emuir_a;
+ uint64_t emuir_b;
+ uint64_t emudat_out;
+ uint64_t emudat_in;
+
+ uint32_t wpiactl;
+ uint32_t wpdactl;
+ uint32_t wpstat;
+
+ uint32_t hwbps[BLACKFIN_MAX_HWBREAKPOINTS];
+ struct blackfin_hwwpt hwwps[BLACKFIN_MAX_HWWATCHPOINTS];
+
+ uint32_t emupc;
+};
+
+extern void blackfin_set_instr(struct blackfin_jtag *, uint8_t);
+
+#define DECLARE_BLACKFIN_DBGCTL_BIT_SET(name) \
+ extern void blackfin_dbgctl_bit_set_##name(struct blackfin_jtag *);
+
+#define DECLARE_BLACKFIN_DBGCTL_BIT_CLEAR(name) \
+ extern void blackfin_dbgctl_bit_clear_##name(struct blackfin_jtag *);
+
+#define DECLARE_BLACKFIN_DBGCTL_BIT_IS(name) \
+ extern bool blackfin_dbgctl_bit_IS_##name(struct blackfin_jtag *);
+
+#define DECLARE_BLACKFIN_DBGCTL_BIT_OP(name) \
+ DECLARE_BLACKFIN_DBGCTL_BIT_SET(name) \
+ DECLARE_BLACKFIN_DBGCTL_BIT_CLEAR(name) \
+ DECLARE_BLACKFIN_DBGCTL_BIT_IS(name)
+
+DECLARE_BLACKFIN_DBGCTL_BIT_OP(sram_init)
+DECLARE_BLACKFIN_DBGCTL_BIT_OP(wakeup)
+DECLARE_BLACKFIN_DBGCTL_BIT_OP(sysrst)
+DECLARE_BLACKFIN_DBGCTL_BIT_OP(esstep)
+DECLARE_BLACKFIN_DBGCTL_BIT_OP(emudatsz_32)
+DECLARE_BLACKFIN_DBGCTL_BIT_OP(emudatsz_40)
+DECLARE_BLACKFIN_DBGCTL_BIT_OP(emudatsz_48)
+DECLARE_BLACKFIN_DBGCTL_BIT_OP(emuirlpsz_2)
+DECLARE_BLACKFIN_DBGCTL_BIT_OP(emuirsz_64)
+DECLARE_BLACKFIN_DBGCTL_BIT_OP(emuirsz_48)
+DECLARE_BLACKFIN_DBGCTL_BIT_OP(emuirsz_32)
+DECLARE_BLACKFIN_DBGCTL_BIT_OP(empen)
+DECLARE_BLACKFIN_DBGCTL_BIT_OP(emeen)
+DECLARE_BLACKFIN_DBGCTL_BIT_OP(emfen)
+DECLARE_BLACKFIN_DBGCTL_BIT_OP(empwr)
+
+#define DECLARE_BLACKFIN_DBGSTAT_BIT_IS(name) \
+ extern bool blackfin_dbgstat_is_##name(struct blackfin_jtag *);
+
+DECLARE_BLACKFIN_DBGSTAT_BIT_IS(lpdec1)
+DECLARE_BLACKFIN_DBGSTAT_BIT_IS(core_fault)
+DECLARE_BLACKFIN_DBGSTAT_BIT_IS(idle)
+DECLARE_BLACKFIN_DBGSTAT_BIT_IS(in_reset)
+DECLARE_BLACKFIN_DBGSTAT_BIT_IS(lpdec0)
+DECLARE_BLACKFIN_DBGSTAT_BIT_IS(bist_done)
+DECLARE_BLACKFIN_DBGSTAT_BIT_IS(emuack)
+DECLARE_BLACKFIN_DBGSTAT_BIT_IS(emuready)
+DECLARE_BLACKFIN_DBGSTAT_BIT_IS(emudiovf)
+DECLARE_BLACKFIN_DBGSTAT_BIT_IS(emudoovf)
+DECLARE_BLACKFIN_DBGSTAT_BIT_IS(emudif)
+DECLARE_BLACKFIN_DBGSTAT_BIT_IS(emudof)
+
+extern void blackfin_read_dbgstat(struct blackfin_jtag *);
+extern void blackfin_wpstat_get(struct blackfin_jtag *);
+extern void blackfin_wpstat_clear(struct blackfin_jtag *);
+extern uint16_t blackfin_dbgstat_emucause(struct blackfin_jtag *);
+extern void blackfin_emuir_set(struct blackfin_jtag *, uint32_t, tap_state_t);
+extern void blackfin_emuir_set_2(struct blackfin_jtag *, uint32_t, uint32_t, tap_state_t);
+extern void blackfin_emulation_enable(struct blackfin_jtag *);
+extern void blackfin_emulation_disable(struct blackfin_jtag *);
+extern void blackfin_emulation_trigger(struct blackfin_jtag *);
+extern void blackfin_emulation_return(struct blackfin_jtag *);
+
+extern void blackfin_register_set(struct blackfin_jtag *, enum core_regnum, uint32_t);
+extern uint32_t blackfin_register_get(struct blackfin_jtag *, enum core_regnum);
+extern uint32_t blackfin_get_p0(struct blackfin_jtag *);
+extern uint32_t blackfin_get_r0(struct blackfin_jtag *);
+extern void blackfin_set_p0(struct blackfin_jtag *, uint32_t);
+extern void blackfin_set_r0(struct blackfin_jtag *, uint32_t);
+extern void blackfin_check_emuready(struct blackfin_jtag *);
+extern void blackfin_system_reset(struct blackfin_jtag *);
+extern void blackfin_core_reset(struct blackfin_jtag *);
+extern void blackfin_emupc_get(struct blackfin_jtag *);
+extern void blackfin_emupc_reset(struct blackfin_jtag *);
+extern uint32_t blackfin_emudat_get(struct blackfin_jtag *, tap_state_t);
+extern void blackfin_emudat_set(struct blackfin_jtag *, uint32_t, tap_state_t);
+extern void blackfin_wpu_init(struct blackfin_jtag *);
+extern void blackfin_wpu_set_wpia(struct blackfin_jtag *, int, uint32_t, int);
+extern void blackfin_wpu_set_wpda(struct blackfin_jtag *, int);
+extern void blackfin_single_step(struct blackfin_jtag *, bool);
+#endif /* BLACKFIN_JTAG_H */
diff --git a/src/target/blackfin_mem.c b/src/target/blackfin_mem.c
new file mode 100644
index 0000000..6464d70
--- /dev/null
+++ b/src/target/blackfin_mem.c
@@ -0,0 +1,1628 @@
+/***************************************************************************
+ * Copyright (C) 2011 by Analog Devices, Inc. *
+ * Written by Jie Zhang <***@analog.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 <assert.h>
+
+#include "helper/log.h"
+#include "helper/types.h"
+#include "jtag/jtag.h"
+#include "blackfin.h"
+#include "blackfin_jtag.h"
+#include "blackfin_mem.h"
+
+#define DMA_CONFIG_FLOW_STOP 0x0000
+#define DMA_CONFIG_NDSIZE_0 0x0000
+#define DMA_CONFIG_DI_EN 0x0080
+#define DMA_CONFIG_DI_SEL 0x0040
+#define DMA_CONFIG_SYNC 0x0020
+#define DMA_CONFIG_DMA2D 0x0010
+#define DMA_CONFIG_WDSIZE_8 0x0000
+#define DMA_CONFIG_WDSIZE_16 0x0004
+#define DMA_CONFIG_WDSIZE_32 0x0008
+#define DMA_CONFIG_WDSIZE_MASK 0x000c
+#define DMA_CONFIG_WNR 0x0002
+#define DMA_CONFIG_DMAEN 0x0001
+
+#define DMA_IRQ_STATUS_DMA_RUN 0x0008
+#define DMA_IRQ_STATUS_DFETCH 0x0004
+#define DMA_IRQ_STATUS_DMA_ERR 0x0002
+#define DMA_IRQ_STATUS_DMA_DONE 0x0001
+
+#define EBIU_SDGCTL 0xffc00a10
+#define EBIU_SDBCTL 0xffc00a14
+#define EBIU_SDRRC 0xffc00a18
+#define EBIU_SDSTAT 0xffc00a1c
+
+#define EBIU_DDRCTL0 0xffc00a20
+#define EBIU_DDRCTL1 0xffc00a24
+#define EBIU_DDRCTL2 0xffc00a28
+#define EBIU_DDRCTL3 0xffc00a2c
+#define EBIU_RSTCTL 0xffc00a3c
+
+#define SICA_SYSCR 0xffc00104
+#define SICA_SYSCR_COREB_SRAM_INIT 0x0020
+
+#define DMEM_CONTROL 0xffe00004
+#define DCPLB_ADDR0 0xffe00100
+#define DCPLB_DATA0 0xffe00200
+#define IMEM_CONTROL 0xffe01004
+#define ICPLB_ADDR0 0xffe01100
+#define ICPLB_DATA0 0xffe01200
+
+#define ENICPLB 0x00000002
+#define IMC 0x00000004
+
+#define ENDCPLB 0x00000002
+#define DMC 0x0000000c
+#define ACACHE_BSRAM 0x00000008
+#define ACACHE_BCACHE 0x0000000c
+
+#define PAGE_SIZE_MASK 0x00030000
+#define PAGE_SIZE_4MB 0x00030000
+#define PAGE_SIZE_1MB 0x00020000
+#define PAGE_SIZE_4KB 0x00010000
+#define PAGE_SIZE_1KB 0x00000000
+#define CPLB_L1_AOW 0x00008000
+#define CPLB_WT 0x00004000
+#define CPLB_L1_CHBL 0x00001000
+#define CPLB_MEM_LEV 0x00000200
+#define CPLB_LRUPRIO 0x00000100
+#define CPLB_DIRTY 0x00000080
+#define CPLB_SUPV_WR 0x00000010
+#define CPLB_USER_WR 0x00000008
+#define CPLB_USER_RD 0x00000004
+#define CPLB_LOCK 0x00000002
+#define CPLB_VALID 0x00000001
+
+#define L1_DMEMORY (PAGE_SIZE_1MB | CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID)
+#define SDRAM_DNON_CHBL (PAGE_SIZE_4MB | CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID)
+#define SDRAM_DGEN_WB (PAGE_SIZE_4MB | CPLB_L1_CHBL | CPLB_DIRTY | CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID)
+#define SDRAM_DGEN_WT (PAGE_SIZE_4MB | CPLB_L1_CHBL | CPLB_WT | CPLB_L1_AOW | CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID)
+#define L1_IMEMORY (PAGE_SIZE_1MB | CPLB_USER_RD | CPLB_VALID)
+#define SDRAM_INON_CHBL (PAGE_SIZE_4MB | CPLB_USER_RD | CPLB_VALID)
+#define SDRAM_IGENERIC (PAGE_SIZE_4MB | CPLB_L1_CHBL | CPLB_MEM_LEV | CPLB_USER_RD | CPLB_VALID)
+/* The following DCPLB DATA are used by gdbproxy to prevent DCPLB missing exception. */
+#define DNON_CHBL_4MB (PAGE_SIZE_4MB | CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID)
+#define DNON_CHBL_1MB (PAGE_SIZE_1MB | CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID)
+#define DNON_CHBL_4KB (PAGE_SIZE_4KB | CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID)
+#define DNON_CHBL_1KB (PAGE_SIZE_1KB | CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID)
+
+#define CACHE_LINE_BYTES 32
+
+#define BFIN_DCPLB_NUM 16
+#define BFIN_ICPLB_NUM 16
+
+#define DTEST_COMMAND 0xffe00300
+#define DTEST_DATA0 0xffe00400
+#define DTEST_DATA1 0xffe00404
+
+#define ITEST_COMMAND 0xffe01300
+#define ITEST_DATA0 0xffe01400
+#define ITEST_DATA1 0xffe01404
+
+#define IN_RANGE(addr, lo, hi) ((addr) >= (lo) && (addr) < (hi))
+#define IN_MAP(addr, map) IN_RANGE (addr, map, map##_end)
+#define MAP_LEN(map) ((map##_end) - (map))
+
+struct blackfin_dma
+{
+ uint32_t next_desc_ptr;
+ uint32_t start_addr;
+ uint16_t config;
+ uint16_t x_count;
+ uint16_t x_modify;
+ uint16_t y_count;
+ uint16_t y_modify;
+ uint32_t curr_desc_ptr;
+ uint32_t curr_addr;
+ uint16_t irq_status;
+ uint16_t peripheral_map;
+ uint16_t curr_x_count;
+ uint16_t curr_y_count;
+};
+
+struct blackfin_test_data
+{
+ uint32_t command_addr, data0_addr, data1_addr;
+ uint32_t data0_off, data1_off;
+ uint32_t data0;
+ uint32_t data1;
+};
+
+#define RTI_LIMIT(blackfin) ((blackfin->l1_map->l1_code_end - blackfin->l1_map->l1_code) / 8)
+
+
+static uint32_t mmr_read_clobber_r0(struct blackfin_jtag *jtag_info, int32_t offset, uint32_t size)
+{
+ uint32_t value;
+
+ assert(size == 2 || size == 4);
+
+ if (offset == 0)
+ {
+ if (size == 2)
+ blackfin_emuir_set_2(jtag_info,
+ blackfin_gen_load16z(REG_R0, REG_P0),
+ blackfin_gen_move(REG_EMUDAT, REG_R0), TAP_DRPAUSE);
+ else
+ blackfin_emuir_set_2(jtag_info,
+ blackfin_gen_load32(REG_R0, REG_P0),
+ blackfin_gen_move(REG_EMUDAT, REG_R0), TAP_DRPAUSE);
+ }
+ else
+ {
+ if (size == 2)
+ blackfin_emuir_set(jtag_info,
+ blackfin_gen_load16z_offset(REG_R0, REG_P0, offset), TAP_IDLE);
+ else
+ blackfin_emuir_set(jtag_info,
+ blackfin_gen_load32_offset(REG_R0, REG_P0, offset), TAP_IDLE);
+ blackfin_emuir_set(jtag_info, blackfin_gen_move(REG_EMUDAT, REG_R0), TAP_DRPAUSE);
+ }
+ value = blackfin_emudat_get(jtag_info, TAP_IDLE);
+
+ return value;
+}
+
+static uint32_t mmr_read(struct blackfin_jtag *jtag_info, uint32_t addr, uint32_t size)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(jtag_info->target);
+ uint32_t p0, r0;
+ uint32_t value;
+
+ if (addr == DMEM_CONTROL)
+ {
+ if (size != 4)
+ {
+ LOG_ERROR("DMEM_CONTROL can only be accessed as 32-bit word");
+ /* Return a weird value to notice people. */
+ return 0xfffffff;
+ }
+
+ if (blackfin->dmem_control_valid_p)
+ return blackfin->dmem_control;
+ }
+ else if (addr == IMEM_CONTROL)
+ {
+ if (size != 4)
+ {
+ LOG_ERROR("IMEM_CONTROL can only be accessed as 32-bit word");
+ /* Return a weird value to notice people. */
+ return 0xfffffff;
+ }
+
+ if (blackfin->imem_control_valid_p)
+ return blackfin->imem_control;
+ }
+
+
+ p0 = blackfin_get_p0(jtag_info);
+ r0 = blackfin_get_r0(jtag_info);
+
+ blackfin_set_p0(jtag_info, addr);
+ value = mmr_read_clobber_r0(jtag_info, 0, size);
+
+ blackfin_set_p0(jtag_info, p0);
+ blackfin_set_r0(jtag_info, r0);
+
+ if (addr == DMEM_CONTROL)
+ {
+ blackfin->dmem_control = value;
+ blackfin->dmem_control_valid_p = 1;
+ }
+ else if (addr == IMEM_CONTROL)
+ {
+ blackfin->imem_control = value;
+ blackfin->imem_control_valid_p = 1;
+ }
+
+ return value;
+}
+
+static void mmr_write_clobber_r0(struct blackfin_jtag *jtag_info, int32_t offset, uint32_t data, uint32_t size)
+{
+ assert (size == 2 || size == 4);
+
+ blackfin_emudat_set(jtag_info, data, TAP_DRPAUSE);
+
+ if (offset == 0)
+ {
+ if (size == 2)
+ blackfin_emuir_set_2(jtag_info,
+ blackfin_gen_move(REG_R0, REG_EMUDAT),
+ blackfin_gen_store16(REG_P0, REG_R0), TAP_IDLE);
+ else
+ blackfin_emuir_set_2(jtag_info,
+ blackfin_gen_move(REG_R0, REG_EMUDAT),
+ blackfin_gen_store32(REG_P0, REG_R0), TAP_IDLE);
+ }
+ else
+ {
+ blackfin_emuir_set(jtag_info, blackfin_gen_move(REG_R0, REG_EMUDAT), TAP_IDLE);
+ if (size == 2)
+ blackfin_emuir_set(jtag_info, blackfin_gen_store16_offset(REG_P0, offset, REG_R0), TAP_IDLE);
+ else
+ blackfin_emuir_set(jtag_info, blackfin_gen_store32_offset(REG_P0, offset, REG_R0), TAP_IDLE);
+ }
+}
+
+static void mmr_write(struct blackfin_jtag *jtag_info, uint32_t addr, uint32_t data, int size)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(jtag_info->target);
+ uint32_t p0, r0;
+
+ if (addr == DMEM_CONTROL)
+ {
+ if (size != 4)
+ {
+ LOG_ERROR("DMEM_CONTROL can only be accessed as 32-bit word");
+ return;
+ }
+
+ if (blackfin->dmem_control_valid_p
+ && blackfin->dmem_control == data)
+ return;
+ else
+ {
+ blackfin->dmem_control = data;
+ blackfin->dmem_control_valid_p = 1;
+ }
+ }
+ else if (addr == IMEM_CONTROL)
+ {
+ if (size != 4)
+ {
+ LOG_ERROR("IMEM_CONTROL can only be accessed as 32-bit word");
+ return;
+ }
+
+ if (blackfin->imem_control_valid_p
+ && blackfin->imem_control == data)
+ return;
+ else
+ {
+ blackfin->imem_control = data;
+ blackfin->imem_control_valid_p = 1;
+ }
+ }
+
+ p0 = blackfin_get_p0(jtag_info);
+ r0 = blackfin_get_r0(jtag_info);
+
+ blackfin_set_p0(jtag_info, addr);
+ mmr_write_clobber_r0(jtag_info, 0, data, size);
+
+ blackfin_set_p0(jtag_info, p0);
+ blackfin_set_r0(jtag_info, r0);
+}
+
+static void cache_status_get(struct blackfin_jtag *jtag_info)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(jtag_info->target);
+ uint32_t p0, r0;
+
+ /* Instead of calling mmr_read twice, we save one of context save
+ and restore. */
+ if (!blackfin->dmem_control_valid_p
+ && !blackfin->imem_control_valid_p)
+ {
+ p0 = blackfin_get_p0(jtag_info);
+ r0 = blackfin_get_r0(jtag_info);
+
+ blackfin_set_p0(jtag_info, DMEM_CONTROL);
+
+ blackfin->dmem_control = mmr_read_clobber_r0(jtag_info, 0, 4);
+ blackfin->dmem_control_valid_p = 1;
+ blackfin->imem_control = mmr_read_clobber_r0(jtag_info, IMEM_CONTROL - DMEM_CONTROL, 4);
+ blackfin->imem_control_valid_p = 1;
+
+ blackfin_set_p0(jtag_info, p0);
+ blackfin_set_r0(jtag_info, r0);
+ }
+ else if (!blackfin->dmem_control_valid_p)
+ /* No need to set dmem_control and dmem_control_valid_p here.
+ mmr_read will handle them. */
+ mmr_read(jtag_info, DMEM_CONTROL, 4);
+ else if (!blackfin->imem_control_valid_p)
+ /* No need to set imem_control and imem_control_valid_p here.
+ mmr_read will handle them. */
+ mmr_read(jtag_info, IMEM_CONTROL, 4);
+
+ if (blackfin->imem_control & IMC)
+ blackfin->l1_code_cache_enabled = 1;
+ else
+ blackfin->l1_code_cache_enabled = 0;
+
+ if ((blackfin->dmem_control & DMC) == ACACHE_BCACHE)
+ {
+ blackfin->l1_data_a_cache_enabled = 1;
+ blackfin->l1_data_b_cache_enabled = 1;
+ }
+ else if ((blackfin->dmem_control & DMC) == ACACHE_BSRAM)
+ {
+ blackfin->l1_data_a_cache_enabled = 1;
+ blackfin->l1_data_b_cache_enabled = 0;
+ }
+ else
+ {
+ blackfin->l1_data_a_cache_enabled = 0;
+ blackfin->l1_data_b_cache_enabled = 0;
+ }
+}
+
+int blackfin_sdram_init(struct blackfin_jtag *jtag_info)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(jtag_info->target);
+ uint32_t p0, r0, value;
+
+ p0 = blackfin_get_p0(jtag_info);
+ r0 = blackfin_get_r0(jtag_info);
+
+ blackfin_set_p0(jtag_info, EBIU_SDGCTL);
+
+ /* Check if SDRAM has been enabled already.
+ If so, don't enable it again. */
+ value = mmr_read_clobber_r0(jtag_info, EBIU_SDSTAT - EBIU_SDGCTL, 2);
+ if ((value & 0x8) == 0)
+ {
+ LOG_DEBUG("%s: SDRAM has already been enabled", target_name(jtag_info->target));
+ return ERROR_OK;
+ }
+
+ mmr_write_clobber_r0(jtag_info, EBIU_SDRRC - EBIU_SDGCTL,
+ blackfin->sdram_config->sdrrc, 2);
+ mmr_write_clobber_r0(jtag_info, EBIU_SDBCTL - EBIU_SDGCTL,
+ blackfin->sdram_config->sdbctl, 2);
+ mmr_write_clobber_r0(jtag_info, 0, blackfin->sdram_config->sdgctl, 4);
+ blackfin_emuir_set(jtag_info, BLACKFIN_INSN_SSYNC, TAP_IDLE);
+
+ blackfin_set_p0(jtag_info, p0);
+ blackfin_set_r0(jtag_info, r0);
+
+ return ERROR_OK;
+}
+
+int blackfin_ddr_init(struct blackfin_jtag *jtag_info)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(jtag_info->target);
+ uint32_t p0, r0, value;
+
+ p0 = blackfin_get_p0(jtag_info);
+ r0 = blackfin_get_r0(jtag_info);
+
+ blackfin_set_p0(jtag_info, EBIU_DDRCTL0);
+
+ value = mmr_read_clobber_r0(jtag_info, EBIU_RSTCTL - EBIU_DDRCTL0, 2);
+ mmr_write_clobber_r0(jtag_info, EBIU_RSTCTL - EBIU_DDRCTL0, value | 0x1, 2);
+ blackfin_emuir_set(jtag_info, BLACKFIN_INSN_SSYNC, TAP_IDLE);
+
+ mmr_write_clobber_r0(jtag_info, 0, blackfin->ddr_config->ddrctl0, 4);
+ mmr_write_clobber_r0(jtag_info, EBIU_DDRCTL1 - EBIU_DDRCTL0,
+ blackfin->ddr_config->ddrctl1, 4);
+ mmr_write_clobber_r0(jtag_info, EBIU_DDRCTL2 - EBIU_DDRCTL0,
+ blackfin->ddr_config->ddrctl2, 4);
+ blackfin_emuir_set(jtag_info, BLACKFIN_INSN_SSYNC, TAP_IDLE);
+
+ blackfin_set_p0(jtag_info, p0);
+ blackfin_set_r0(jtag_info, r0);
+
+ return ERROR_OK;
+}
+
+static void dcplb_enable_clobber_p0r0(struct blackfin_jtag *jtag_info)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(jtag_info->target);
+
+ blackfin_set_p0(jtag_info, DMEM_CONTROL);
+
+ if (!blackfin->dmem_control_valid_p)
+ {
+ blackfin_emuir_set(jtag_info, BLACKFIN_INSN_CSYNC, TAP_IDLE);
+ blackfin->dmem_control = mmr_read_clobber_r0(jtag_info, 0, 4);
+ blackfin->dmem_control_valid_p = 1;
+ }
+
+ if (blackfin->dmem_control & ENDCPLB)
+ return;
+
+ blackfin->dmem_control |= ENDCPLB;
+ mmr_write_clobber_r0(jtag_info, 0, blackfin->dmem_control, 4);
+ blackfin_emuir_set(jtag_info, BLACKFIN_INSN_SSYNC, TAP_IDLE);
+}
+
+static int dcplb_disable_clobber_p0r0(struct blackfin_jtag *jtag_info)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(jtag_info->target);
+ int orig;
+
+ blackfin_set_p0(jtag_info, DMEM_CONTROL);
+
+ if (!blackfin->dmem_control_valid_p)
+ {
+ blackfin_emuir_set(jtag_info, BLACKFIN_INSN_CSYNC, TAP_IDLE);
+ blackfin->dmem_control = mmr_read_clobber_r0(jtag_info, 0, 4);
+ blackfin->dmem_control_valid_p = 1;
+ }
+
+ orig = blackfin->dmem_control & ENDCPLB;
+
+ if (orig)
+ {
+ blackfin->dmem_control &= ~ENDCPLB;
+ mmr_write_clobber_r0(jtag_info, 0, blackfin->dmem_control, 4);
+ blackfin_emuir_set(jtag_info, BLACKFIN_INSN_SSYNC, TAP_IDLE);
+ }
+
+ return orig;
+}
+
+static void dma_context_save_clobber_p0r0(struct blackfin_jtag *jtag_info, uint32_t base, struct blackfin_dma *dma)
+{
+ blackfin_set_p0(jtag_info, base);
+
+ dma->start_addr = mmr_read_clobber_r0(jtag_info, 0x04, 4);
+ dma->config = mmr_read_clobber_r0(jtag_info, 0x08, 2);
+ dma->x_count = mmr_read_clobber_r0(jtag_info, 0x10, 2);
+ dma->x_modify = mmr_read_clobber_r0(jtag_info, 0x14, 2);
+ dma->irq_status = mmr_read_clobber_r0(jtag_info, 0x28, 2);
+}
+
+static void dma_context_restore_clobber_p0r0(struct blackfin_jtag *jtag_info, uint32_t base, struct blackfin_dma *dma)
+{
+ blackfin_set_p0(jtag_info, base);
+
+ mmr_write_clobber_r0(jtag_info, 0x04, dma->start_addr, 4);
+ mmr_write_clobber_r0(jtag_info, 0x10, dma->x_count, 2);
+ mmr_write_clobber_r0(jtag_info, 0x14, dma->x_modify, 2);
+ mmr_write_clobber_r0(jtag_info, 0x08, dma->config, 2);
+}
+
+static void log_dma(uint32_t base, struct blackfin_dma *dma)
+{
+ LOG_DEBUG("DMA base [0x%08X]", base);
+ LOG_DEBUG("START_ADDR [0x%08X]", dma->start_addr);
+ LOG_DEBUG("CONFIG [0x%04X]", dma->config);
+ LOG_DEBUG("X_COUNT [0x%04X]", dma->x_count);
+ LOG_DEBUG("X_MODIFY [0x%04X]", dma->x_modify);
+ LOG_DEBUG("IRQ_STATUS [0x%04X]", dma->irq_status);
+}
+
+static int dma_copy(struct blackfin_jtag *jtag_info, uint32_t dest, uint32_t src, uint32_t size)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(jtag_info->target);
+ struct blackfin_dma mdma_s0_save, mdma_d0_save;
+ struct blackfin_dma mdma_s0, mdma_d0;
+ uint32_t p0, r0;
+ uint16_t s0_irq_status, d0_irq_status;
+ int retval;
+ const struct timespec dma_wait = {0, 50000000};
+
+ blackfin_emupc_reset(jtag_info);
+
+ p0 = blackfin_get_p0(jtag_info);
+ r0 = blackfin_get_r0(jtag_info);
+
+ dma_context_save_clobber_p0r0(jtag_info, blackfin->mdma_s0, &mdma_s0_save);
+ dma_context_save_clobber_p0r0(jtag_info, blackfin->mdma_d0, &mdma_d0_save);
+
+ log_dma(blackfin->mdma_s0, &mdma_s0_save);
+ log_dma(blackfin->mdma_d0, &mdma_d0_save);
+
+ s0_irq_status = mdma_s0_save.irq_status;
+ d0_irq_status = mdma_d0_save.irq_status;
+
+ while ((s0_irq_status & DMA_IRQ_STATUS_DMA_RUN) ||
+ (d0_irq_status & DMA_IRQ_STATUS_DMA_RUN))
+ {
+ if ((s0_irq_status & DMA_IRQ_STATUS_DMA_ERR) ||
+ (d0_irq_status & DMA_IRQ_STATUS_DMA_ERR))
+ break;
+
+ LOG_DEBUG("wait DMA done: S0:0x%08X [0x%04X] D0:0x%08X [0x%04X]",
+ src, s0_irq_status, dest, d0_irq_status);
+
+ nanosleep(&dma_wait, NULL);
+
+ blackfin_set_p0(jtag_info, blackfin->mdma_s0);
+ s0_irq_status = mmr_read_clobber_r0(jtag_info, 0x28, 2);
+ blackfin_set_p0(jtag_info, blackfin->mdma_d0);
+ d0_irq_status = mmr_read_clobber_r0(jtag_info, 0x28, 2);
+ }
+
+ if (s0_irq_status & DMA_IRQ_STATUS_DMA_ERR)
+ LOG_DEBUG("clear MDMA0_S0 DMA ERR: IRQ_STATUS [0x%04X]",
+ s0_irq_status);
+ if (s0_irq_status & DMA_IRQ_STATUS_DMA_DONE)
+ LOG_DEBUG("clear MDMA_S0 DMA DONE: IRQ_STATUS [0x%04X]",
+ s0_irq_status);
+ if (d0_irq_status & DMA_IRQ_STATUS_DMA_ERR)
+ LOG_DEBUG("clear MDMA0_D0 DMA ERR: IRQ_STATUS [0x%04X]",
+ d0_irq_status);
+ if (d0_irq_status & DMA_IRQ_STATUS_DMA_DONE)
+ LOG_DEBUG("clear MDMA_D0 DMA DONE: IRQ_STATUS [0x%04X]",
+ d0_irq_status);
+
+ if (s0_irq_status & (DMA_IRQ_STATUS_DMA_ERR | DMA_IRQ_STATUS_DMA_DONE))
+ {
+ blackfin_set_p0(jtag_info, blackfin->mdma_s0);
+ mmr_write_clobber_r0(jtag_info,
+ 0x28, DMA_IRQ_STATUS_DMA_ERR | DMA_IRQ_STATUS_DMA_DONE, 2);
+ }
+
+ if (d0_irq_status & (DMA_IRQ_STATUS_DMA_ERR | DMA_IRQ_STATUS_DMA_DONE))
+ {
+ blackfin_set_p0(jtag_info, blackfin->mdma_d0);
+ mmr_write_clobber_r0(jtag_info,
+ 0x28, DMA_IRQ_STATUS_DMA_ERR | DMA_IRQ_STATUS_DMA_DONE, 2);
+ }
+
+ blackfin_set_p0(jtag_info, blackfin->mdma_s0);
+ s0_irq_status = mmr_read_clobber_r0(jtag_info, 0x28, 2);
+ blackfin_set_p0(jtag_info, blackfin->mdma_d0);
+ d0_irq_status = mmr_read_clobber_r0(jtag_info, 0x28, 2);
+
+ LOG_DEBUG("before dma copy MDMA0_S0 IRQ_STATUS [0x%04X]", s0_irq_status);
+ LOG_DEBUG("before dma copy MDMA0_D0 IRQ_STATUS [0x%04X]", d0_irq_status);
+
+ mdma_s0.start_addr = src;
+ mdma_s0.x_count = size;
+ mdma_s0.x_modify = 1;
+ mdma_s0.config = DMA_CONFIG_FLOW_STOP | DMA_CONFIG_NDSIZE_0;
+ mdma_s0.config |= DMA_CONFIG_WDSIZE_8 | DMA_CONFIG_DMAEN | DMA_CONFIG_DI_EN;
+
+ mdma_d0.start_addr = dest;
+ mdma_d0.x_count = size;
+ mdma_d0.x_modify = 1;
+ mdma_d0.config =
+ DMA_CONFIG_FLOW_STOP | DMA_CONFIG_NDSIZE_0 | DMA_CONFIG_WNR;
+ mdma_d0.config |= DMA_CONFIG_WDSIZE_8 | DMA_CONFIG_DMAEN | DMA_CONFIG_DI_EN;
+
+ dma_context_restore_clobber_p0r0(jtag_info, blackfin->mdma_s0, &mdma_s0);
+ dma_context_restore_clobber_p0r0(jtag_info, blackfin->mdma_d0, &mdma_d0);
+
+ wait_dma:
+
+ blackfin_set_p0(jtag_info, blackfin->mdma_s0);
+ s0_irq_status = mmr_read_clobber_r0(jtag_info, 0x28, 2);
+ blackfin_set_p0(jtag_info, blackfin->mdma_d0);
+ d0_irq_status = mmr_read_clobber_r0(jtag_info, 0x28, 2);
+
+ if (s0_irq_status & DMA_IRQ_STATUS_DMA_ERR)
+ {
+ LOG_ERROR("MDMA0_S0 DMA error: 0x%08X: IRQ_STATUS [0x%04X]",
+ src, s0_irq_status);
+ retval = ERROR_FAIL;
+ goto finish_dma_copy;
+ }
+ if (d0_irq_status & DMA_IRQ_STATUS_DMA_ERR)
+ {
+ LOG_ERROR("MDMA0_D0 DMA error: 0x%08X: IRQ_STATUS [0x%04X]",
+ dest, d0_irq_status);
+ retval = ERROR_FAIL;
+ goto finish_dma_copy;
+ }
+ else if (!(s0_irq_status & DMA_IRQ_STATUS_DMA_DONE))
+ {
+ LOG_INFO("MDMA_S0 wait for done: IRQ_STATUS [0x%04X]", s0_irq_status);
+ nanosleep (&dma_wait, NULL);
+ goto wait_dma;
+ }
+ else if (!(d0_irq_status & DMA_IRQ_STATUS_DMA_DONE))
+ {
+ LOG_INFO("MDMA_D0 wait for done: IRQ_STATUS [0x%04X]", d0_irq_status);
+ nanosleep (&dma_wait, NULL);
+ goto wait_dma;
+ }
+ else
+ retval = ERROR_OK;
+
+ LOG_DEBUG("done dma copy MDMA_S0: 0x%08X: IRQ_STATUS [0x%04X]",
+ src, s0_irq_status);
+
+ LOG_DEBUG("done dma copy MDMA_D0: 0x%08X: IRQ_STATUS [0x%04X]",
+ dest, d0_irq_status);
+
+ if ((s0_irq_status & DMA_IRQ_STATUS_DMA_ERR)
+ || (s0_irq_status & DMA_IRQ_STATUS_DMA_DONE))
+ {
+ blackfin_set_p0(jtag_info, blackfin->mdma_s0);
+ mmr_write_clobber_r0(jtag_info,
+ 0x28, DMA_IRQ_STATUS_DMA_ERR | DMA_IRQ_STATUS_DMA_DONE, 2);
+ }
+
+ if ((d0_irq_status & DMA_IRQ_STATUS_DMA_ERR)
+ || (d0_irq_status & DMA_IRQ_STATUS_DMA_DONE))
+ {
+ blackfin_set_p0(jtag_info, blackfin->mdma_d0);
+ mmr_write_clobber_r0(jtag_info,
+ 0x28, DMA_IRQ_STATUS_DMA_ERR | DMA_IRQ_STATUS_DMA_DONE, 2);
+ }
+
+
+ dma_context_restore_clobber_p0r0(jtag_info, blackfin->mdma_s0, &mdma_s0_save);
+ dma_context_restore_clobber_p0r0(jtag_info, blackfin->mdma_d0, &mdma_d0_save);
+
+ finish_dma_copy:
+
+ blackfin_set_p0(jtag_info, p0);
+ blackfin_set_r0(jtag_info, r0);
+
+ return retval;
+}
+
+/* TODO optimize it by using blackfin_emudat_defer_get and blackfin_emudat_get_done. */
+
+static int memory_read_1(struct blackfin_jtag *jtag_info, uint32_t addr, uint8_t *buf, int size)
+{
+ uint32_t p0, r0;
+ bool dcplb_enabled;
+
+ assert (size > 0);
+
+ p0 = blackfin_get_p0(jtag_info);
+ r0 = blackfin_get_r0(jtag_info);
+
+ dcplb_enabled = dcplb_disable_clobber_p0r0(jtag_info);
+
+ blackfin_set_p0(jtag_info, addr);
+
+ if ((addr & 0x3) != 0)
+ blackfin_emuir_set_2(jtag_info,
+ blackfin_gen_load8zpi(REG_R0, REG_P0),
+ blackfin_gen_move(REG_EMUDAT, REG_R0), TAP_DRPAUSE);
+
+ while ((addr & 0x3) != 0 && size != 0)
+ {
+ *buf++ = blackfin_emudat_get(jtag_info, TAP_IDLE);
+ addr++;
+ size--;
+ }
+ if (size == 0)
+ goto finish_read;
+
+ if (size >= 4)
+ blackfin_emuir_set_2(jtag_info,
+ blackfin_gen_load32pi(REG_R0, REG_P0),
+ blackfin_gen_move(REG_EMUDAT, REG_R0), TAP_DRPAUSE);
+
+ for (; size >= 4; size -= 4)
+ {
+ uint32_t data;
+
+ data = blackfin_emudat_get(jtag_info, TAP_IDLE);
+ *buf++ = data & 0xff;
+ *buf++ = (data >> 8) & 0xff;
+ *buf++ = (data >> 16) & 0xff;
+ *buf++ = (data >> 24) & 0xff;
+ }
+
+ if (size == 0)
+ goto finish_read;
+
+ blackfin_emuir_set_2 (jtag_info,
+ blackfin_gen_load8zpi(REG_R0, REG_P0),
+ blackfin_gen_move(REG_EMUDAT, REG_R0), TAP_DRPAUSE);
+
+ for (; size > 0; size--)
+ *buf++ = blackfin_emudat_get(jtag_info, TAP_IDLE);
+
+ finish_read:
+
+ if (dcplb_enabled)
+ dcplb_enable_clobber_p0r0(jtag_info);
+
+ blackfin_set_p0(jtag_info, p0);
+ blackfin_set_r0(jtag_info, r0);
+
+ return 0;
+}
+
+static int memory_read(struct blackfin_jtag *jtag_info, uint32_t addr, uint32_t size, uint8_t *buf)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(jtag_info->target);
+ uint32_t s;
+
+ if ((addr & 0x3) != 0)
+ {
+ s = 4 - (addr & 0x3);
+ s = size < s ? size : s;
+ memory_read_1(jtag_info, addr, buf, s);
+ size -= s;
+ addr += s;
+ buf += s;
+ }
+
+ while (size > 0)
+ {
+ blackfin_emupc_reset(jtag_info);
+
+ /* The overhead should be no larger than 0x20. */
+ s = (RTI_LIMIT(blackfin) - 0x20) * 4;
+ s = size < s ? size : s;
+ memory_read_1(jtag_info, addr, buf, s);
+ size -= s;
+ addr += s;
+ buf += s;
+ }
+
+ return ERROR_OK;
+}
+
+static int memory_write_1 (struct blackfin_jtag *jtag_info, uint32_t addr, uint8_t *buf, int size)
+{
+ uint32_t p0, r0;
+ bool dcplb_enabled;
+
+ assert (size > 0);
+
+ p0 = blackfin_get_p0(jtag_info);
+ r0 = blackfin_get_r0(jtag_info);
+
+ dcplb_enabled = dcplb_disable_clobber_p0r0(jtag_info);
+
+ blackfin_set_p0(jtag_info, addr);
+
+ if ((addr & 0x3) != 0)
+ blackfin_emuir_set_2(jtag_info,
+ blackfin_gen_move(REG_R0, REG_EMUDAT),
+ blackfin_gen_store8pi(REG_P0, REG_R0), TAP_DRPAUSE);
+
+ while ((addr & 0x3) != 0 && size != 0)
+ {
+ blackfin_emudat_set(jtag_info, *buf++, TAP_IDLE);
+ addr++;
+ size--;
+ }
+ if (size == 0)
+ goto finish_write;
+
+ if (size >= 4)
+ blackfin_emuir_set_2(jtag_info,
+ blackfin_gen_move(REG_R0, REG_EMUDAT),
+ blackfin_gen_store32pi(REG_P0, REG_R0), TAP_DRPAUSE);
+
+ for (; size >= 4; size -= 4)
+ {
+ uint32_t data;
+
+ data = *buf++;
+ data |= (*buf++) << 8;
+ data |= (*buf++) << 16;
+ data |= (*buf++) << 24;
+ blackfin_emudat_set(jtag_info, data, TAP_IDLE);
+ }
+
+ if (size == 0)
+ goto finish_write;
+
+ blackfin_emuir_set_2(jtag_info,
+ blackfin_gen_move(REG_R0, REG_EMUDAT),
+ blackfin_gen_store8pi(REG_P0, REG_R0), TAP_DRPAUSE);
+
+ for (; size > 0; size--)
+ blackfin_emudat_set(jtag_info, *buf++, TAP_IDLE);
+
+ finish_write:
+
+ if (dcplb_enabled)
+ dcplb_enable_clobber_p0r0(jtag_info);
+
+ blackfin_set_p0(jtag_info, p0);
+ blackfin_set_r0(jtag_info, r0);
+
+ return 0;
+}
+
+static int memory_write(struct blackfin_jtag *jtag_info, uint32_t addr, uint32_t size, uint8_t *buf)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(jtag_info->target);
+ uint32_t s;
+
+ if ((addr & 0x3) != 0)
+ {
+ s = 4 - (addr & 0x3);
+ s = size < s ? size : s;
+ memory_write_1(jtag_info, addr, buf, s);
+ size -= s;
+ addr += s;
+ buf += s;
+ }
+
+ while (size > 0)
+ {
+ blackfin_emupc_reset(jtag_info);
+
+ /* The overhead should be no larger than 0x20. */
+ s = (RTI_LIMIT(blackfin) - 0x20) * 4;
+ s = size < s ? size : s;
+ memory_write_1(jtag_info, addr, buf, s);
+ size -= s;
+ addr += s;
+ buf += s;
+ }
+
+ return ERROR_OK;
+}
+
+static int dma_sram_read(struct blackfin_jtag *jtag_info, uint32_t address,
+ uint32_t size, uint8_t *buffer)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(jtag_info->target);
+ uint32_t l1_addr;
+ uint8_t *tmp;
+ int retval;
+
+ l1_addr = blackfin->l1_map->l1_data_a;
+
+ assert(size < 0x4000);
+
+ tmp = (uint8_t *) malloc(size);
+ if (tmp == NULL)
+ abort();
+
+ memory_read(jtag_info, l1_addr, size, tmp);
+
+ retval = dma_copy(jtag_info, l1_addr, address, size);
+
+ memory_read(jtag_info, l1_addr, size, buffer);
+
+ memory_write(jtag_info, l1_addr, size, buffer);
+
+ free(tmp);
+
+ return retval;
+}
+
+static int dma_sram_write(struct blackfin_jtag *jtag_info, uint32_t address,
+ uint32_t size, uint8_t *buffer)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(jtag_info->target);
+ uint32_t l1_addr;
+ uint8_t *tmp;
+ int retval;
+
+ l1_addr = blackfin->l1_map->l1_data_a;
+
+ assert(l1_addr);
+ assert(size <= MAP_LEN(blackfin->l1_map->l1_data_a));
+
+ tmp = (uint8_t *) malloc(size);
+ if (tmp == NULL)
+ abort();
+
+ memory_read(jtag_info, l1_addr, size, tmp);
+
+ memory_write(jtag_info, l1_addr, size, buffer);
+
+ retval = dma_copy(jtag_info, address, l1_addr, size);
+
+ memory_write(jtag_info, l1_addr, size, tmp);
+
+ free(tmp);
+
+ return retval;
+}
+
+/* Read Instruction SRAM using Instruction Test Registers. */
+
+static void test_command (struct blackfin_jtag *jtag_info, uint32_t addr, bool write_p,
+ uint32_t command_addr, uint32_t *command_value)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(jtag_info->target);
+
+ /* The shifting here is a bit funky, but should be straight forward and
+ easier to maintain than hand coded masks. So, start with the break
+ down of the [DI]TEST_COMMAND MMR in the HRM and follow along:
+
+ We need to put bit 11 of the address into bit 26 of the MMR. So first
+ we mask off ADDR[11] with:
+ (addr & (1 << 11))
+
+ Then we shift it from its current position (11) to its new one (26):
+ ((...) << (26 - 11))
+ */
+
+ /* Start with the bits ITEST/DTEST share. */
+ *command_value =
+ ((addr & (0x03 << 12)) << (16 - 12)) | /* ADDR[13:12] -> MMR[17:16] */
+ ((addr & (0x01 << 14)) << (14 - 14)) | /* ADDR[14] -> MMR[14] */
+ ((addr & (0xff << 3)) << ( 3 - 3)) | /* ADDR[10:3] -> MMR[10:3] */
+ (1 << 2) | /* 1 (data) -> MMR[2] */
+ (write_p << 1); /* read/write -> MMR[1] */
+
+ /* Now for the bits that aren't the same. */
+ if (command_addr == ITEST_COMMAND)
+ *command_value |=
+ ((addr & (0x03 << 10)) << (26 - 10)); /* ADDR[11:10] -> MMR[27:26] */
+ else
+ *command_value |=
+ ((addr & (0x01 << 11)) << (26 - 11)) | /* ADDR[11] -> MMR[26] */
+ ((addr & (0x01 << 21)) << (24 - 21)); /* ADDR[21] -> MMR[24] */
+
+ /* Now, just for fun, some parts are slightly different. */
+ if (command_addr == DTEST_COMMAND)
+ {
+ /* BF50x has no additional needs. */
+ if (!strcasecmp (blackfin->part, "BF518"))
+ {
+ /* MMR[23]:
+ 0 - Data Bank A (0xff800000) / Inst Bank A (0xffa00000)
+ 1 - Data Bank B (0xff900000) / Inst Bank B (0xffa04000)
+ */
+ if ((addr & 0xfff04000) == 0xffa04000 ||
+ (addr & 0xfff00000) == 0xff900000)
+ *command_value |= (1 << 23);
+ }
+ else if (!strcasecmp (blackfin->part, "BF526") ||
+ !strcasecmp (blackfin->part, "BF527") ||
+ !strcasecmp (blackfin->part, "BF533") ||
+ !strcasecmp (blackfin->part, "BF534") ||
+ !strcasecmp (blackfin->part, "BF537") ||
+ !strcasecmp (blackfin->part, "BF538") ||
+ !strcasecmp (blackfin->part, "BF548") ||
+ !strcasecmp (blackfin->part, "BF548M"))
+ {
+ /* MMR[23]:
+ 0 - Data Bank A (0xff800000) / Inst Bank A (0xffa00000)
+ 1 - Data Bank B (0xff900000) / Inst Bank B (0xffa08000)
+ */
+ if ((addr & 0xfff08000) == 0xffa08000 ||
+ (addr & 0xfff00000) == 0xff900000)
+ *command_value |= (1 << 23);
+ }
+ else if (!strcasecmp (blackfin->part, "BF561"))
+ {
+ /* MMR[23]:
+ 0 - Data Bank A (Core A: 0xff800000 Core B: 0xff400000)
+ Inst Bank A (Core A: 0xffa00000 Core B: 0xff600000)
+ 1 - Data Bank B (Core A: 0xff900000 Core B: 0xff500000)
+ N/A for Inst (no Bank B)
+ */
+ uint32_t hi = (addr >> 20);
+ if (hi == 0xff9 || hi == 0xff5)
+ *command_value |= (1 << 23);
+ }
+ else if (!strcasecmp (blackfin->part, "BF592"))
+ {
+ /* ADDR[15] -> MMR[15]
+ MMR[22]:
+ 0 - L1 Inst (0xffa00000)
+ 1 - L1 ROM (0xffa10000)
+ */
+ *command_value |= (addr & (1 << 15));
+ if ((addr >> 16) == 0xffa1)
+ *command_value |= (1 << 22);
+ }
+ }
+}
+
+/* Do one ITEST read. ADDR should be aligned to 8 bytes. BUF should
+ be enough large to hold 64 bits. */
+static void itest_read_clobber_r0 (struct blackfin_jtag *jtag_info,
+ struct blackfin_test_data *test_data, uint32_t addr, uint8_t *buf)
+{
+ uint32_t command, data1, data0;
+
+ assert ((addr & 0x7) == 0);
+
+ test_command (jtag_info, addr, false, test_data->command_addr, &command);
+
+ mmr_write_clobber_r0 (jtag_info, 0, command, 4);
+ blackfin_emuir_set (jtag_info, BLACKFIN_INSN_CSYNC, TAP_IDLE);
+ data1 = mmr_read_clobber_r0 (jtag_info, test_data->data1_off, 4);
+ data0 = mmr_read_clobber_r0 (jtag_info, test_data->data0_off, 4);
+
+ *buf++ = data0 & 0xff;
+ *buf++ = (data0 >> 8) & 0xff;
+ *buf++ = (data0 >> 16) & 0xff;
+ *buf++ = (data0 >> 24) & 0xff;
+ *buf++ = data1 & 0xff;
+ *buf++ = (data1 >> 8) & 0xff;
+ *buf++ = (data1 >> 16) & 0xff;
+ *buf++ = (data1 >> 24) & 0xff;
+}
+
+/* Do one ITEST write. ADDR should be aligned to 8 bytes. BUF should
+ be enough large to hold 64 bits. */
+static void itest_write_clobber_r0 (struct blackfin_jtag *jtag_info,
+ struct blackfin_test_data *test_data, uint32_t addr, uint8_t *buf)
+{
+ uint32_t command, data1, data0;
+
+ assert ((addr & 0x7) == 0);
+
+ test_command(jtag_info, addr, true, test_data->command_addr, &command);
+
+ data0 = *buf++;
+ data0 |= (*buf++) << 8;
+ data0 |= (*buf++) << 16;
+ data0 |= (*buf++) << 24;
+ data1 = *buf++;
+ data1 |= (*buf++) << 8;
+ data1 |= (*buf++) << 16;
+ data1 |= (*buf++) << 24;
+
+ mmr_write_clobber_r0(jtag_info, test_data->data1_off, data1, 4);
+ mmr_write_clobber_r0(jtag_info, test_data->data0_off, data0, 4);
+ mmr_write_clobber_r0(jtag_info, 0, command, 4);
+ blackfin_emuir_set(jtag_info, BLACKFIN_INSN_CSYNC, TAP_IDLE);
+}
+
+static void test_context_save_clobber_r0(struct blackfin_jtag *jtag_info, struct blackfin_test_data *test_data)
+{
+ test_data->data1 = mmr_read_clobber_r0(jtag_info, test_data->data1_off, 4);
+ test_data->data0 = mmr_read_clobber_r0(jtag_info, test_data->data0_off, 4);
+}
+
+static void test_context_restore_clobber_r0(struct blackfin_jtag *jtag_info, struct blackfin_test_data *test_data)
+{
+ mmr_write_clobber_r0 (jtag_info, test_data->data1_off, test_data->data1, 4);
+ mmr_write_clobber_r0 (jtag_info, test_data->data0_off, test_data->data0, 4);
+ /* Yeah, TEST_COMMAND is reset to 0, i.e. clobbered! But it should
+ not do any harm to any reasonable user programs. Codes trying to
+ peek TEST_COMMAND might be affected. But why do such codes
+ exist? */
+ mmr_write_clobber_r0 (jtag_info, 0, 0, 4);
+ blackfin_emuir_set (jtag_info, BLACKFIN_INSN_CSYNC, TAP_IDLE);
+}
+
+static void test_command_mmrs(struct blackfin_jtag *jtag_info, uint32_t addr, int icache, uint32_t *command_addr, uint32_t *data0_addr, uint32_t *data1_addr)
+{
+ if (icache) {
+ *command_addr = ITEST_COMMAND;
+ *data0_addr = ITEST_DATA0;
+ *data1_addr = ITEST_DATA1;
+ } else {
+ *command_addr = DTEST_COMMAND;
+ *data0_addr = DTEST_DATA0;
+ *data1_addr = DTEST_DATA1;
+ }
+}
+
+static int itest_sram_1(struct blackfin_jtag *jtag_info, uint32_t addr, uint8_t *buf, uint32_t size, int write_p)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(jtag_info->target);
+ struct blackfin_test_data test_data;
+ uint32_t p0, r0;
+ uint8_t data[8];
+
+ p0 = blackfin_get_p0(jtag_info);
+ r0 = blackfin_get_r0(jtag_info);
+
+ test_command_mmrs(jtag_info, addr,
+ IN_MAP(addr, blackfin->l1_map->l1_code_cache),
+ &test_data.command_addr,
+ &test_data.data0_addr,
+ &test_data.data1_addr);
+ test_data.data0_off = test_data.data0_addr - test_data.command_addr;
+ test_data.data1_off = test_data.data1_addr - test_data.command_addr;
+ blackfin_register_set(jtag_info, REG_P0, test_data.command_addr);
+
+ test_context_save_clobber_r0(jtag_info, &test_data);
+
+ if ((addr & 0x7) != 0)
+ {
+ uint32_t aligned_addr = addr & 0xfffffff8;
+
+ itest_read_clobber_r0(jtag_info, &test_data, aligned_addr, data);
+
+ if (write_p)
+ {
+ while ((addr & 0x7) != 0 && size != 0)
+ {
+ data[addr & 0x7] = *buf++;
+ addr++;
+ size--;
+ }
+
+ itest_write_clobber_r0(jtag_info, &test_data, aligned_addr, data);
+ }
+ else
+ {
+ while ((addr & 0x7) != 0 && size != 0)
+ {
+ *buf++ = data[addr & 0x7];
+ addr++;
+ size--;
+ }
+ }
+ }
+
+ for (; size >= 8; size -= 8)
+ {
+ if (write_p)
+ itest_write_clobber_r0(jtag_info, &test_data, addr, buf);
+ else
+ itest_read_clobber_r0(jtag_info, &test_data, addr, buf);
+ addr += 8;
+ buf += 8;
+ }
+
+ if (size != 0)
+ {
+ itest_read_clobber_r0(jtag_info, &test_data, addr, data);
+
+ if (write_p)
+ {
+ memcpy(data, buf, size);
+ itest_write_clobber_r0(jtag_info, &test_data, addr, data);
+ }
+ else
+ {
+ memcpy(buf, data, size);
+ }
+ }
+
+ test_context_restore_clobber_r0(jtag_info, &test_data);
+
+ blackfin_set_p0(jtag_info, p0);
+ blackfin_set_r0(jtag_info, r0);
+
+ return 0;
+}
+
+static int itest_sram(struct blackfin_jtag *jtag_info, uint32_t addr,
+ uint32_t size, uint8_t *buf, bool write_p)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(jtag_info->target);
+ uint32_t s;
+
+ if ((addr & 0x7) != 0)
+ {
+ s = 8 - (addr & 0x7);
+ s = size < s ? size : s;
+ itest_sram_1(jtag_info, addr, buf, s, write_p);
+ size -= s;
+ addr += s;
+ buf += s;
+ }
+
+ while (size > 0)
+ {
+ blackfin_emupc_reset(jtag_info);
+
+ /* The overhead should be no larger than 0x20. */
+ s = (RTI_LIMIT(blackfin) - 0x20) / 25 * 32;
+ s = size < s ? size : s;
+ /* We also need to keep transfers from spanning SRAM banks.
+ The core itest logic looks up appropriate MMRs once per
+ call, and different SRAM banks might require a different
+ set of MMRs. */
+ if ((addr / 0x4000) != ((addr + s) / 0x4000))
+ s -= ((addr + s) % 0x4000);
+ itest_sram_1(jtag_info, addr, buf, s, write_p);
+ size -= s;
+ addr += s;
+ buf += s;
+ }
+
+ return ERROR_OK;
+}
+
+static int sram_read_write(struct blackfin_jtag *jtag_info, uint32_t addr,
+ uint32_t size, uint8_t *buf, bool dma_p, bool write_p)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(jtag_info->target);
+
+ assert(!dma_p || blackfin->mdma_d0 != 0);
+
+ /* FIXME Add an option to control using dma or itest. BF592 can only use itest for its L1 ROM. */
+ if (dma_p)
+ {
+ if (write_p)
+ return dma_sram_write(jtag_info, addr, size, buf);
+ else
+ return dma_sram_read(jtag_info, addr, size, buf);
+ }
+ else
+ return itest_sram(jtag_info, addr, size, buf, write_p);
+}
+
+static int sram_read(struct blackfin_jtag *jtag_info, uint32_t addr,
+ uint32_t size, uint8_t *buf, bool dma_p)
+{
+ return sram_read_write(jtag_info, addr, size, buf, dma_p, false);
+}
+
+static int sram_write(struct blackfin_jtag *jtag_info, uint32_t addr,
+ uint32_t size, uint8_t *buf, bool dma_p)
+{
+ return sram_read_write(jtag_info, addr, size, buf, dma_p, true);
+}
+
+int blackfin_read_mem(struct blackfin_jtag *jtag_info, uint32_t addr,
+ uint32_t size, uint8_t *buf)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(jtag_info->target);
+ int retval;
+ uint32_t value;
+ uint32_t end;
+
+ LOG_DEBUG("bfin_read_mem(0x%08X, %d)", addr, size);
+
+ blackfin_emupc_reset(jtag_info);
+
+ if (!IN_MAP(addr, blackfin->mem_map->l1))
+ goto skip_l1;
+
+ if (IN_MAP(addr, blackfin->l1_map->l1))
+ cache_status_get(jtag_info);
+
+ if (IN_MAP(addr, blackfin->l1_map->l1_code))
+ {
+ if (!blackfin->l1_code_cache_enabled &&
+ (blackfin->l1_map->l1_code_end == blackfin->l1_map->l1_code_cache))
+ end = blackfin->l1_map->l1_code_cache_end;
+ else
+ end = blackfin->l1_map->l1_code_end;
+
+ if (addr + size > end)
+ size = end - addr;
+
+ retval = sram_read(jtag_info, addr, size, buf, false);
+ goto done;
+ }
+ else if (!blackfin->l1_code_cache_enabled &&
+ IN_MAP(addr, blackfin->l1_map->l1_code_cache))
+ {
+ if (addr + size > blackfin->l1_map->l1_code_cache_end)
+ size = blackfin->l1_map->l1_code_cache_end - addr;
+
+ retval = sram_read(jtag_info, addr, size, buf, false);
+ goto done;
+ }
+ else if (IN_MAP(addr, blackfin->l1_map->l1_code_rom))
+ {
+ if (addr + size > blackfin->l1_map->l1_code_rom_end)
+ size = blackfin->l1_map->l1_code_rom_end - addr;
+
+ retval = sram_read(jtag_info, addr, size, buf, false);
+ goto done;
+ }
+ else if (IN_MAP(addr, blackfin->l1_map->l1_data_a))
+ {
+ if (!blackfin->l1_data_a_cache_enabled &&
+ (blackfin->l1_map->l1_data_a_end == blackfin->l1_map->l1_data_a_cache))
+ end = blackfin->l1_map->l1_data_a_cache_end;
+ else
+ end = blackfin->l1_map->l1_data_a_end;
+
+ if (addr + size > end)
+ size = end - addr;
+
+ retval = memory_read(jtag_info, addr, size, buf);
+ goto done;
+ }
+ else if (!blackfin->l1_data_a_cache_enabled &&
+ IN_MAP (addr, blackfin->l1_map->l1_data_a_cache))
+ {
+ if (addr + size > blackfin->l1_map->l1_data_a_cache_end)
+ size = blackfin->l1_map->l1_data_a_cache_end - addr;
+
+ retval = memory_read(jtag_info, addr, size, buf);
+ goto done;
+ }
+ else if (IN_MAP (addr, blackfin->l1_map->l1_data_b))
+ {
+ if (!blackfin->l1_data_b_cache_enabled
+ && (blackfin->l1_map->l1_data_b_end
+ == blackfin->l1_map->l1_data_b_cache))
+ end = blackfin->l1_map->l1_data_b_cache_end;
+ else
+ end = blackfin->l1_map->l1_data_b_end;
+
+ if (addr + size > end)
+ size = end - addr;
+
+ retval = memory_read(jtag_info, addr, size, buf);
+ goto done;
+ }
+ else if (!blackfin->l1_data_b_cache_enabled &&
+ IN_MAP (addr, blackfin->l1_map->l1_data_b_cache))
+ {
+ if (addr + size > blackfin->l1_map->l1_data_b_cache_end)
+ size = blackfin->l1_map->l1_data_b_cache_end - addr;
+
+ retval = memory_read(jtag_info, addr, size, buf);
+ goto done;
+ }
+ else if (IN_MAP (addr, blackfin->l1_map->l1_scratch))
+ {
+ if (addr + size > blackfin->l1_map->l1_scratch_end)
+ size = blackfin->l1_map->l1_scratch_end - addr;
+
+ retval = memory_read(jtag_info, addr, size, buf);
+ goto done;
+ }
+ else if (IN_MAP (addr, blackfin->l1_map->l1))
+ {
+ LOG_ERROR("invalid L1 memory address [0x%08X]", addr);
+ retval = ERROR_FAIL;
+ goto done;
+ }
+
+ skip_l1:
+
+ /* TODO Accurately check MMR validity. */
+
+ if ((IN_RANGE (addr, blackfin->mem_map->sysmmr, blackfin->mem_map->coremmr)
+ && addr + size > blackfin->mem_map->coremmr)
+ || (addr >= blackfin->mem_map->coremmr && addr + size < addr))
+ {
+ LOG_ERROR("bad MMR addr or size [0x%08X] size %d", addr, size);
+ return ERROR_FAIL;
+ }
+
+ if (addr >= blackfin->mem_map->sysmmr)
+ {
+ if (size != 2 && size != 4)
+ {
+ LOG_ERROR("bad MMR size [0x%08X] size %d", addr, size);
+ return ERROR_FAIL;
+ }
+
+ if ((addr & 0x1) == 1)
+ {
+ LOG_ERROR("odd MMR addr [0x%08X]", addr);
+ return ERROR_FAIL;
+ }
+
+ value = mmr_read(jtag_info, addr, size);
+ *buf++ = value & 0xff;
+ *buf++ = (value >> 8) & 0xff;
+ if (size == 4)
+ {
+ *buf++ = (value >> 16) & 0xff;
+ *buf++ = (value >> 24) & 0xff;
+ }
+ retval = ERROR_OK;
+ goto done;
+ }
+
+ if (IN_MAP (addr, blackfin->mem_map->sdram))
+ {
+ if (addr + size > blackfin->mem_map->sdram_end)
+ size = blackfin->mem_map->sdram_end - addr;
+
+ retval = memory_read(jtag_info, addr, size, buf);
+ }
+ else if (IN_MAP (addr, blackfin->mem_map->async_mem))
+ {
+ if (addr + size > blackfin->mem_map->async_mem_end)
+ size = blackfin->mem_map->async_mem_end - addr;
+
+ retval = memory_read(jtag_info, addr, size, buf);
+ }
+ /* TODO Allow access to devices mapped to async mem. */
+ else if (IN_MAP (addr, blackfin->mem_map->boot_rom))
+ {
+ if (addr + size > blackfin->mem_map->boot_rom_end)
+ size = blackfin->mem_map->boot_rom_end - addr;
+ retval = memory_read(jtag_info, addr, size, buf);
+ }
+ else if (IN_MAP (addr, blackfin->mem_map->l2_sram))
+ {
+ if (addr + size > blackfin->mem_map->l2_sram_end)
+ size = blackfin->mem_map->l2_sram_end - addr;
+
+ retval = memory_read(jtag_info, addr, size, buf);
+ }
+ else
+ {
+ LOG_ERROR("invalid L1 memory address [0x%08X]", addr);
+ retval = ERROR_FAIL;
+ }
+
+ done:
+
+ return retval;
+}
+
+static void icache_flush(struct blackfin_jtag *jtag_info, uint32_t addr, int size)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(jtag_info->target);
+ uint32_t p0, r0;
+ int i;
+
+ assert (size > 0);
+
+ p0 = blackfin_get_p0(jtag_info);
+
+ if (!blackfin->imem_control_valid_p)
+ {
+ r0 = blackfin_get_r0(jtag_info);
+ blackfin_set_p0(jtag_info, IMEM_CONTROL);
+ blackfin_emuir_set(jtag_info, BLACKFIN_INSN_CSYNC, TAP_IDLE);
+ blackfin->imem_control = mmr_read_clobber_r0(jtag_info, 0, 4);
+ blackfin->imem_control_valid_p = 1;
+ blackfin_set_r0(jtag_info, r0);
+ }
+
+ if (blackfin->imem_control & IMC)
+ {
+ blackfin_set_p0(jtag_info, addr);
+ for (i = (size + addr % CACHE_LINE_BYTES - 1) / CACHE_LINE_BYTES + 1;
+ i > 0; i--)
+ blackfin_emuir_set(jtag_info, blackfin_gen_iflush_pm(REG_P0), TAP_IDLE);
+ }
+
+ blackfin_set_p0(jtag_info, p0);
+}
+
+int blackfin_write_mem(struct blackfin_jtag *jtag_info, uint32_t addr,
+ uint32_t size, const uint8_t *buffer)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(jtag_info->target);
+ int retval;
+ uint32_t value;
+ uint32_t end;
+ uint8_t *buf = (uint8_t *) buffer; /* TODO remove this cast. */
+
+ LOG_DEBUG("bfin_write_mem(0x%08X, %d)", addr, size);
+
+ blackfin_emupc_reset(jtag_info);
+
+ if (!IN_MAP (addr, blackfin->mem_map->l1))
+ goto skip_l1;
+
+ if (IN_MAP (addr, blackfin->l1_map->l1))
+ cache_status_get(jtag_info);
+
+ if (IN_MAP(addr, blackfin->l1_map->l1_code) &&
+ ((!blackfin->l1_code_cache_enabled &&
+ (blackfin->l1_map->l1_code_end == blackfin->l1_map->l1_code_cache)
+ && (end = blackfin->l1_map->l1_code_cache_end))
+ || (end = blackfin->l1_map->l1_code_end))
+ && addr + size <= end)
+ {
+ retval = sram_write(jtag_info, addr, size, buf, false);
+ icache_flush(jtag_info, addr, size);
+ goto done;
+ }
+ else if (IN_MAP (addr, blackfin->l1_map->l1_code_cache) &&
+ addr + size <= blackfin->l1_map->l1_code_cache_end)
+ {
+ if (blackfin->l1_code_cache_enabled)
+ {
+ LOG_ERROR("cannot write L1 icache when enabled [0x%08X] size %d", addr, size);
+ return ERROR_FAIL;
+ }
+
+ retval = sram_write(jtag_info, addr, size, buf, false);
+ goto done;
+ }
+ else if (IN_MAP (addr, blackfin->l1_map->l1_data_a) &&
+ ((!blackfin->l1_data_a_cache_enabled &&
+ (blackfin->l1_map->l1_data_a_end == blackfin->l1_map->l1_data_a_cache)
+ && (end = blackfin->l1_map->l1_data_a_cache_end))
+ || (end = blackfin->l1_map->l1_data_a_end))
+ && addr + size <= end)
+ {
+ retval = memory_write(jtag_info, addr, size, buf);
+ goto done;
+ }
+ else if (IN_MAP (addr, blackfin->l1_map->l1_data_a_cache) &&
+ addr + size <= blackfin->l1_map->l1_data_a_cache_end)
+ {
+ if (blackfin->l1_data_a_cache_enabled)
+ {
+ LOG_ERROR("cannot write L1 dcache when enabled [0x%08X] size %d", addr, size);
+ return ERROR_FAIL;
+ }
+
+ retval = memory_write(jtag_info, addr, size, buf);
+ goto done;
+ }
+ else if (IN_MAP(addr, blackfin->l1_map->l1_data_b) &&
+ ((!blackfin->l1_data_b_cache_enabled &&
+ (blackfin->l1_map->l1_data_b_end == blackfin->l1_map->l1_data_b_cache)
+ && (end = blackfin->l1_map->l1_data_b_cache_end))
+ || (end = blackfin->l1_map->l1_data_b_end))
+ && addr + size <= end)
+ {
+ retval = memory_write(jtag_info, addr, size, buf);
+ goto done;
+ }
+ else if (IN_MAP(addr, blackfin->l1_map->l1_data_b_cache) &&
+ addr + size <= blackfin->l1_map->l1_data_b_cache_end)
+ {
+ if (blackfin->l1_data_b_cache_enabled)
+ {
+ LOG_ERROR("cannot write L1 dcache when enabled [0x%08X] size %d", addr, size);
+ return ERROR_FAIL;
+ }
+
+ retval = memory_write(jtag_info, addr, size, buf);
+ goto done;
+ }
+ else if (IN_MAP(addr, blackfin->l1_map->l1_scratch) &&
+ addr + size <= blackfin->l1_map->l1_scratch_end)
+ {
+ retval = memory_write(jtag_info, addr, size, buf);
+ goto done;
+ }
+ else if (IN_MAP(addr, blackfin->l1_map->l1))
+ {
+ LOG_ERROR("cannot write reserved L1 [0x%08X] size %d", addr, size);
+ return ERROR_FAIL;
+ }
+
+ skip_l1:
+
+ /* TODO Accurately check MMR validity. */
+
+ if ((IN_RANGE (addr, blackfin->mem_map->sysmmr, blackfin->mem_map->coremmr) &&
+ addr + size > blackfin->mem_map->coremmr)
+ || (addr >= blackfin->mem_map->coremmr && addr + size < addr))
+ {
+ LOG_ERROR("bad MMR addr or size [0x%08X] size %d", addr, size);
+ return ERROR_FAIL;
+ }
+
+ if (addr >= blackfin->mem_map->sysmmr)
+ {
+ if (size != 2 && size != 4)
+ {
+ LOG_ERROR("bad MMR size [0x%08X] size %d", addr, size);
+ return ERROR_FAIL;
+ }
+
+ if ((addr & 0x1) == 1)
+ {
+ LOG_ERROR("odd MMR addr [0x%08X]", addr);
+ return ERROR_FAIL;
+ }
+
+ value = *buf++;
+ value |= (*buf++) << 8;
+ if (size == 4)
+ {
+ value |= (*buf++) << 16;
+ value |= (*buf++) << 24;
+ }
+ mmr_write(jtag_info, addr, value, size);
+ retval = ERROR_OK;
+ goto done;
+ }
+
+ if ((IN_MAP (addr, blackfin->mem_map->sdram) &&
+ addr + size <= blackfin->mem_map->sdram_end)
+ || (IN_MAP (addr, blackfin->mem_map->async_mem) &&
+ addr + size <= blackfin->mem_map->async_mem_end)
+ || (IN_MAP (addr, blackfin->mem_map->l2_sram) &&
+ addr + size <= blackfin->mem_map->l2_sram_end))
+ {
+ retval = memory_write(jtag_info, addr, size, buf);
+ icache_flush(jtag_info, addr, size);
+ }
+ else
+ {
+ LOG_ERROR("cannot write memory [0x%08X]", addr);
+ return ERROR_FAIL;
+ }
+
+ done:
+
+ return retval;
+}
diff --git a/src/target/blackfin_mem.h b/src/target/blackfin_mem.h
new file mode 100644
index 0000000..aa6f0fb
--- /dev/null
+++ b/src/target/blackfin_mem.h
@@ -0,0 +1,86 @@
+/***************************************************************************
+ * Copyright (C) 2011 by Analog Devices, Inc. *
+ * Written by Jie Zhang <***@analog.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 BLACKFIN_MEM_H
+#define BLACKFIN_MEM_H
+
+struct blackfin_mem_map
+{
+ uint32_t sdram;
+ uint32_t sdram_end;
+ uint32_t async_mem;
+ uint32_t flash;
+ uint32_t flash_end;
+ uint32_t async_mem_end;
+ uint32_t boot_rom;
+ uint32_t boot_rom_end;
+ uint32_t l2_sram;
+ uint32_t l2_sram_end;
+ uint32_t l1;
+ uint32_t l1_end;
+ uint32_t sysmmr;
+ uint32_t coremmr;
+};
+
+struct blackfin_l1_map
+{
+ uint32_t l1;
+ uint32_t l1_data_a;
+ uint32_t l1_data_a_end;
+ uint32_t l1_data_a_cache;
+ uint32_t l1_data_a_cache_end;
+ uint32_t l1_data_b;
+ uint32_t l1_data_b_end;
+ uint32_t l1_data_b_cache;
+ uint32_t l1_data_b_cache_end;
+ uint32_t l1_code;
+ uint32_t l1_code_end;
+ uint32_t l1_code_cache;
+ uint32_t l1_code_cache_end;
+ uint32_t l1_code_rom;
+ uint32_t l1_code_rom_end;
+ uint32_t l1_scratch;
+ uint32_t l1_scratch_end;
+ uint32_t l1_end;
+};
+
+struct blackfin_sdram_config
+{
+ uint16_t sdrrc;
+ uint16_t sdbctl;
+ uint32_t sdgctl;
+};
+
+struct blackfin_ddr_config
+{
+ uint32_t ddrctl0;
+ uint32_t ddrctl1;
+ uint32_t ddrctl2;
+};
+
+extern int blackfin_read_mem(struct blackfin_jtag *jtag_info, uint32_t addr,
+ uint32_t size, uint8_t *buf);
+extern int blackfin_write_mem(struct blackfin_jtag *jtag_info, uint32_t addr,
+ uint32_t size, const uint8_t *buf);
+extern int blackfin_sdram_init(struct blackfin_jtag *jtag_info);
+extern int blackfin_ddr_init(struct blackfin_jtag *jtag_info);
+
+#endif /* BLACKFIN_MEM_H */
diff --git a/src/target/blackfin_memory_map.c b/src/target/blackfin_memory_map.c
new file mode 100644
index 0000000..f1f3701
--- /dev/null
+++ b/src/target/blackfin_memory_map.c
@@ -0,0 +1,267 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "helper/log.h"
+
+#include "target.h"
+#include "blackfin.h"
+#include "blackfin_memory_map.h"
+
+
+#if !defined(HAVE_LIBEXPAT)
+
+int parse_memory_map(struct target *target, const char *memory_map)
+{
+ LOG_WARNING("%s: cannot parse XML memory map; XML support was disabled at compile time", target_name(target));
+ return ERROR_FAIL;
+}
+
+#else /* HAVE_LIBEXPAT */
+
+#include "xml_support.h"
+
+struct memory_map_parsing_data
+{
+ const char *name;
+ struct blackfin_mem_map *mem_map;
+ struct blackfin_l1_map *l1_map;
+ char *processor;
+ char *core;
+ bool skip;
+};
+
+
+/* Callback called by Expat on start of element.
+ This function handles the following elements:
+ * processor: unused now
+ * core: contains the memory map for the core
+ * memory: a memory region
+ * property: unused now
+ The target name is in format PROCESSOR or PROCESSOR.CORE */
+static void memory_map_start_element(void *data_, const XML_Char *name,
+ const XML_Char **attrs)
+{
+ struct memory_map_parsing_data *data = data_;
+
+ if (strcmp(name, "processor") == 0)
+ {
+ const char *attr = xml_find_attribute(attrs, "name");
+ if (!attr)
+ attr = "";
+ data->processor = strdup(attr);
+ if (!data->processor)
+ LOG_ERROR("%s: strdup(%s) failed", data->name, attr);
+ }
+ else if (strcmp(name, "core") == 0)
+ {
+ char buf[40];
+ const char *attr = xml_find_attribute(attrs, "name");
+
+ if (!attr)
+ {
+ attr = "";
+ sprintf(buf, "%s", data->processor);
+ }
+ else
+ sprintf(buf, "%s.%s", data->processor, attr);
+
+ data->core = strdup(attr);
+ if (!data->core)
+ LOG_ERROR("%s: strdup(%s) failed", data->name, attr);
+
+ if (strcmp(buf, data->name) == 0)
+ data->skip = false;
+ else
+ data->skip = true;
+ }
+ else if (strcmp(name, "memory") == 0 && !data->skip)
+ {
+ const XML_Char *memory_name;
+ uint32_t *start = NULL, *end = NULL;
+
+ memory_name = xml_find_attribute(attrs, "name");
+ if (!data->core)
+ {
+ if (strcmp(memory_name, "sdram") == 0)
+ {
+ start = &data->mem_map->sdram;
+ end = &data->mem_map->sdram_end;
+ }
+ else if (strcmp(memory_name, "async_mem") == 0)
+ {
+ start = &data->mem_map->async_mem;
+ end = &data->mem_map->async_mem_end;
+ }
+ else if (strcmp(memory_name, "flash") == 0)
+ {
+ start = &data->mem_map->flash;
+ end = &data->mem_map->flash_end;
+ }
+ else if (strcmp(memory_name, "boot_rom") == 0)
+ {
+ start = &data->mem_map->boot_rom;
+ end = &data->mem_map->boot_rom_end;
+ }
+ else if (strcmp(memory_name, "l2_sram") == 0)
+ {
+ start = &data->mem_map->l2_sram;
+ end = &data->mem_map->l2_sram_end;
+ }
+ else if (strcmp(memory_name, "sysmmr") == 0)
+ {
+ start = &data->mem_map->sysmmr;
+ end = NULL;
+ }
+ else if (strcmp(memory_name, "coremmr") == 0)
+ {
+ start = &data->mem_map->coremmr;
+ end = NULL;
+ }
+ else if (strcmp(memory_name, "l1") == 0)
+ {
+ start = &data->mem_map->l1;
+ end = &data->mem_map->l1_end;
+ }
+ }
+ else
+ {
+ if (strcmp(memory_name, "l1") == 0)
+ {
+ start = &data->l1_map->l1;
+ end = &data->l1_map->l1_end;
+ }
+ else if (strcmp(memory_name, "l1_data_a") == 0)
+ {
+ start = &data->l1_map->l1_data_a;
+ end = &data->l1_map->l1_data_a_end;
+ }
+ else if (strcmp(memory_name, "l1_data_a_cache") == 0)
+ {
+ start = &data->l1_map->l1_data_a_cache;
+ end = &data->l1_map->l1_data_a_cache_end;
+ }
+ else if (strcmp(memory_name, "l1_data_b") == 0)
+ {
+ start = &data->l1_map->l1_data_b;
+ end = &data->l1_map->l1_data_b_end;
+ }
+ else if (strcmp(memory_name, "l1_data_b_cache") == 0)
+ {
+ start = &data->l1_map->l1_data_b_cache;
+ end = &data->l1_map->l1_data_b_cache_end;
+ }
+ else if (strcmp(memory_name, "l1_code") == 0)
+ {
+ start = &data->l1_map->l1_code;
+ end = &data->l1_map->l1_code_end;
+ }
+ else if (strcmp(memory_name, "l1_code_cache") == 0)
+ {
+ start = &data->l1_map->l1_code_cache;
+ end = &data->l1_map->l1_code_cache_end;
+ }
+ else if (strcmp(memory_name, "l1_code_rom") == 0)
+ {
+ start = &data->l1_map->l1_code_rom;
+ end = &data->l1_map->l1_code_rom_end;
+ }
+ else if (strcmp(memory_name, "l1_scratch") == 0)
+ {
+ start = &data->l1_map->l1_scratch;
+ end = &data->l1_map->l1_scratch_end;
+ }
+ }
+
+ if (xml_parse_uint32(xml_find_attribute(attrs, "start"), start) < 0)
+ return;
+
+ if (end)
+ {
+ if (xml_parse_uint32(xml_find_attribute(attrs, "length"), end) < 0)
+ return;
+ *end += *start;
+ }
+ }
+ else if (strcmp(name, "property") == 0)
+ {
+ /* Ignore for now */
+ }
+}
+
+static void memory_map_end_element(void *data_, const XML_Char *name)
+{
+ struct memory_map_parsing_data *data = data_;
+
+ if (strcmp(name, "processor") == 0)
+ {
+ free(data->processor);
+ data->processor = NULL;
+ }
+ else if (strcmp(name, "core") == 0)
+ {
+ free(data->core);
+ data->core = NULL;
+ data->skip = false;
+ }
+}
+
+static void memory_map_character_data(void *data_, const XML_Char *s, int len)
+{
+ return;
+}
+
+int parse_memory_map(struct target *target, const char *memory_map)
+{
+ struct blackfin_common *blackfin = target_to_blackfin(target);
+ int retval;
+
+ struct memory_map_parsing_data data;
+
+ data.name = blackfin->part;
+ data.mem_map = calloc(1, sizeof (struct blackfin_mem_map));
+ if (!data.mem_map)
+ {
+ LOG_ERROR("%s: malloc(%"PRIzu") failed",
+ target_name(target), sizeof (struct blackfin_mem_map));
+ return ERROR_FAIL;
+ }
+ data.l1_map = calloc(1, sizeof (struct blackfin_l1_map));
+ if (!data.l1_map)
+ {
+ LOG_ERROR("%s: malloc(%"PRIzu") failed",
+ target_name(target), sizeof (struct blackfin_l1_map));
+ free(data.mem_map);
+ return ERROR_FAIL;
+ }
+ data.processor = NULL;
+ data.core = NULL;
+ data.skip = false;
+
+ XML_Parser parser = XML_ParserCreateNS(NULL, '!');
+ if (parser == NULL)
+ return ERROR_FAIL;
+
+ XML_SetElementHandler(parser, memory_map_start_element, memory_map_end_element);
+ XML_SetCharacterDataHandler(parser, memory_map_character_data);
+ XML_SetUserData(parser, &data);
+
+ retval = XML_Parse(parser, memory_map, strlen(memory_map), 1);
+ if (retval != XML_STATUS_OK)
+ {
+ enum XML_Error err = XML_GetErrorCode(parser);
+ LOG_ERROR("%s: cannot parse XML memory map [%s]",
+ target_name(target), XML_ErrorString(err));
+ free(data.mem_map);
+ free(data.l1_map);
+ return ERROR_FAIL;
+ }
+
+ blackfin->mem_map = data.mem_map;
+ blackfin->l1_map = data.l1_map;
+
+ return ERROR_OK;
+}
+
+#endif
+
diff --git a/src/target/blackfin_memory_map.h b/src/target/blackfin_memory_map.h
new file mode 100644
index 0000000..4455182
--- /dev/null
+++ b/src/target/blackfin_memory_map.h
@@ -0,0 +1,6 @@
+#ifndef BLACKFIN_MEMORY_MAP_H
+#define BLACKFIN_MEMORY_MAP_H
+
+extern int parse_memory_map(struct target *target, const char *memory_map);
+
+#endif
diff --git a/src/target/cortex_a.c b/src/target/cortex_a.c
index 207fb81..e087923 100644
--- a/src/target/cortex_a.c
+++ b/src/target/cortex_a.c
@@ -55,6 +55,8 @@
#include "target_request.h"
#include "target_type.h"
#include "arm_opcodes.h"
+#include "arm_semihosting.h"
+#include "cortex_a_memory_map.h"
#include <helper/time_support.h>
static int cortex_a_poll(struct target *target);
@@ -75,9 +77,11 @@ static int cortex_a_dap_write_coreregister_u32(struct target *target,
static int cortex_a_mmu(struct target *target, int *enabled);
static int cortex_a_virt2phys(struct target *target,
uint32_t virt, uint32_t *phys);
+static int cortex_a_write_phys_memory(struct target *target,
+ uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer);
static int cortex_a_read_apb_ab_memory(struct target *target,
uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer);
-
+static int cortex_a_setup_semihosting(struct target *target, int enable);
/* restore cp15_control_reg at resume */
static int cortex_a_restore_cp15_control_reg(struct target *target)
@@ -96,7 +100,7 @@ static int cortex_a_restore_cp15_control_reg(struct target *target)
}
return retval;
}
-
+#if 0
/* check address before cortex_a_apb read write access with mmu on
* remove apb predictible data abort */
static int cortex_a_check_address(struct target *target, uint32_t address)
@@ -124,6 +128,7 @@ static int cortex_a_check_address(struct target *target, uint32_t address)
}
return ERROR_OK;
}
+#endif
/* modify cp15_control_reg in order to enable or disable mmu for :
* - virt2phys address conversion
* - read or write memory in phys or virt address */
@@ -879,6 +884,10 @@ static int cortex_a_poll(struct target *target)
retval = cortex_a_debug_entry(target);
if (retval != ERROR_OK)
return retval;
+ /* cortex_a_debug_entry could resume target to ignore
+ a halting event */
+ if (target->state == TARGET_RUNNING)
+ return ERROR_OK;
if (target->smp) {
retval = update_halt_gdb(target);
if (retval != ERROR_OK)
@@ -972,6 +981,11 @@ static int cortex_a_internal_restore(struct target *target, int current,
if (!debug_execution)
target_free_all_working_areas(target);
+ if (arm->hit_syscall) {
+ arm_semihosting_step_over_svc(target);
+ arm->hit_syscall = false;
+ }
+
#if 0
if (debug_execution) {
/* Disable interrupts */
@@ -1083,9 +1097,16 @@ static int cortex_a_internal_restart(struct target *target)
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 (target->restart_use_cti) {
+ // Send DBGRESTART signal
+ uint8_t value[4] = {0, 0, 0, 0};
+ value[0] = 1 << target->restart_cti_channel;
+ retval = cortex_a_write_phys_memory(target, target->restart_cti_reg_addr, 1, 4, value);
+ } else {
+ 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;
@@ -1168,6 +1189,78 @@ static int cortex_a_resume(struct target *target, int current,
return ERROR_OK;
}
+static int cortex_a_step_quiet(struct target *target)
+{
+ struct armv7a_common *armv7a = target_to_armv7a(target);
+ struct arm *arm = &armv7a->arm;
+ struct adiv5_dap *swjdp = armv7a->arm.dap;
+ struct breakpoint stepbreakpoint;
+ struct reg *r = arm->pc;
+ uint32_t address = buf_get_u32(r->value, 0, 32);
+ int retval;
+ uint32_t dscr;
+ int semihosting_disabled = 0;
+
+ if (arm->is_semihosting) {
+ uint32_t vector_base;
+
+ /* MRC p15,0,<Rt>,c12,c0,0 ; Read Vector Base Register */
+ retval = arm->mrc(target, 15,
+ 0, 0, /* op1, op2 */
+ 12, 0, /* CRn, CRm */
+ &vector_base);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* TODO We should check DBGVCR.V */
+ if (address == vector_base + 0x8 || address == 0xffff0008) {
+ cortex_a_setup_semihosting(target, 0);
+ semihosting_disabled = 1;
+ }
+ }
+
+ /* 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_a_set_breakpoint(target, &stepbreakpoint, 0x04);
+
+ retval = cortex_a_resume(target, 1, address, 0, 0);
+ if (retval != ERROR_OK)
+ return retval;
+
+ while (target->state != TARGET_HALTED) {
+ 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_RUN_MODE(dscr) == (DSCR_CORE_HALTED | DSCR_CORE_RESTARTED))
+ target->state = TARGET_HALTED;
+ }
+
+ /* 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;
+
+ retval = arm_dpm_read_current_registers(&armv7a->dpm);
+ if (retval != ERROR_OK)
+ return retval;
+
+ cortex_a_unset_breakpoint(target, &stepbreakpoint);
+
+ if (semihosting_disabled)
+ cortex_a_setup_semihosting(target, 1);
+
+ return ERROR_OK;
+}
+
static int cortex_a_debug_entry(struct target *target)
{
int i;
@@ -1286,6 +1379,15 @@ static int cortex_a_debug_entry(struct target *target)
return retval;
}
+ if (DSCR_ENTRY(dscr) == DSCR_ENTRY_VECT_CATCH) {
+ if (arm_semihosting(target))
+ arm->hit_syscall = true;
+ else if (!cortex_a->is_stepping) {
+ cortex_a_step_quiet(target);
+ cortex_a_resume(target, 1, 0, 0, 0);
+ }
+ }
+
return retval;
}
@@ -1326,18 +1428,25 @@ static int cortex_a_post_debug_entry(struct target *target)
static int cortex_a_step(struct target *target, int current, uint32_t address,
int handle_breakpoints)
{
+ struct cortex_a_common *cortex_a = target_to_cortex_a(target);
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;
+ int semihosting_disabled = 0;
if (target->state != TARGET_HALTED) {
LOG_WARNING("target not halted");
return ERROR_TARGET_NOT_HALTED;
}
+ if (arm->hit_syscall) {
+ retval = cortex_a_internal_restore(target, current, &address, handle_breakpoints, 0);
+ return retval;
+ }
+
/* current = 1: continue on current pc, otherwise continue at <address> */
r = arm->pc;
if (!current)
@@ -1345,6 +1454,24 @@ static int cortex_a_step(struct target *target, int current, uint32_t address,
else
address = buf_get_u32(r->value, 0, 32);
+ if (arm->is_semihosting) {
+ uint32_t vector_base;
+
+ /* MRC p15,0,<Rt>,c12,c0,0 ; Read Vector Base Register */
+ retval = arm->mrc(target, 15,
+ 0, 0, /* op1, op2 */
+ 12, 0, /* CRn, CRm */
+ &vector_base);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* TODO We should check DBGVCR.V */
+ if (address == vector_base + 0x8 || address == 0xffff0008) {
+ cortex_a_setup_semihosting(target, 0);
+ semihosting_disabled = 1;
+ }
+ }
+
/* The front-end may request us not to handle breakpoints.
* But since Cortex-A uses breakpoint for single step,
* we MUST handle breakpoints.
@@ -1366,6 +1493,8 @@ static int cortex_a_step(struct target *target, int current, uint32_t address,
/* Break on IVA mismatch */
cortex_a_set_breakpoint(target, &stepbreakpoint, 0x04);
+ cortex_a->is_stepping = 1;
+
target->debug_reason = DBG_REASON_SINGLESTEP;
retval = cortex_a_resume(target, 1, address, 0, 0);
@@ -1383,6 +1512,8 @@ static int cortex_a_step(struct target *target, int current, uint32_t address,
}
}
+ cortex_a->is_stepping = 0;
+
cortex_a_unset_breakpoint(target, &stepbreakpoint);
target->debug_reason = DBG_REASON_BREAKPOINT;
@@ -1393,6 +1524,9 @@ static int cortex_a_step(struct target *target, int current, uint32_t address,
if (target->state != TARGET_HALTED)
LOG_DEBUG("target stepped");
+ if (semihosting_disabled)
+ cortex_a_setup_semihosting(target, 1);
+
return ERROR_OK;
}
@@ -2571,31 +2705,53 @@ static int cortex_a_read_phys_memory(struct target *target,
uint32_t address, uint32_t size,
uint32_t count, uint8_t *buffer)
{
+ int mmu_enabled = 0;
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%" PRIx32 "; size %" PRId32 "; count %" PRId32,
address, size, count);
if (count && buffer) {
- if (armv7a->memory_ap_available && (apsel == armv7a->memory_ap)) {
+ if (armv7a->memory_ap_available
+ && address >= swjdp->ahb_mem_start_address
+ && address + size * count <= swjdp->ahb_mem_end_address) {
/* read memory through AHB-AP */
retval = mem_ap_sel_read_buf(swjdp, armv7a->memory_ap, buffer, size, count, address);
- } else {
+ } else if (target->state == TARGET_HALTED) {
- /* read memory through APB-AP */
+ /* determine if MMU was enabled on target stop */
if (!armv7a->is_armv7r) {
+ retval = cortex_a_mmu(target, &mmu_enabled);
+ if (retval != ERROR_OK)
+ return retval;
+ }
+
+ /* read memory through APB-AP */
+ if (mmu_enabled) {
/* disable mmu */
retval = cortex_a_mmu_modify(target, 0);
if (retval != ERROR_OK)
return retval;
}
+
retval = cortex_a_read_apb_ab_memory(target, address, size, count, buffer);
+ if (retval != ERROR_OK)
+ return retval;
+
+ if (mmu_enabled) {
+ /* enable mmu */
+ retval = cortex_a_mmu_modify(target, 1);
+ if (retval != ERROR_OK)
+ return retval;
+ }
+ } else {
+ retval = ERROR_TARGET_NOT_HALTED;
}
}
+
return retval;
}
@@ -2603,11 +2759,8 @@ static int cortex_a_read_memory(struct target *target, uint32_t address,
uint32_t size, uint32_t count, uint8_t *buffer)
{
int mmu_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_a handles unaligned memory access */
LOG_DEBUG("Reading memory at address 0x%" PRIx32 "; size %" PRId32 "; count %" PRId32, address,
@@ -2619,32 +2772,22 @@ static int cortex_a_read_memory(struct target *target, uint32_t address,
if (retval != ERROR_OK)
return retval;
}
+ /*
+ if (mmu_enabled) {
+ retval = cortex_a_check_address(target, address);
+ if (retval != ERROR_OK)
+ return retval;
+ }
+ */
+ if (target->state != TARGET_HALTED) {
- if (armv7a->memory_ap_available && (apsel == armv7a->memory_ap)) {
- if (mmu_enabled) {
- virt = address;
- retval = cortex_a_virt2phys(target, virt, &phys);
- if (retval != ERROR_OK)
- return retval;
-
- LOG_DEBUG("Reading at virtual address. Translating v:0x%" PRIx32 " to r:0x%" PRIx32,
- virt, phys);
- address = phys;
- }
- retval = cortex_a_read_phys_memory(target, address, size,
- count, buffer);
- } else {
- if (mmu_enabled) {
- retval = cortex_a_check_address(target, address);
- if (retval != ERROR_OK)
- return retval;
- /* enable MMU as we could have disabled it for phys access */
- retval = cortex_a_mmu_modify(target, 1);
- if (retval != ERROR_OK)
- return retval;
- }
+ if (mmu_enabled)
+ retval = ERROR_TARGET_NOT_HALTED;
+ else
+ retval = cortex_a_read_phys_memory(target, address, size, count, buffer);
+ } else
retval = cortex_a_read_apb_ab_memory(target, address, size, count, buffer);
- }
+
return retval;
}
@@ -2652,85 +2795,50 @@ static int cortex_a_write_phys_memory(struct target *target,
uint32_t address, uint32_t size,
uint32_t count, const uint8_t *buffer)
{
+ int mmu_enabled = 0;
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%" PRIx32 "; size %" PRId32 "; count %" PRId32, address,
size, count);
if (count && buffer) {
- if (armv7a->memory_ap_available && (apsel == armv7a->memory_ap)) {
+ if (armv7a->memory_ap_available
+ && address >= swjdp->ahb_mem_start_address
+ && address + size * count <= swjdp->ahb_mem_end_address) {
/* write memory through AHB-AP */
retval = mem_ap_sel_write_buf(swjdp, armv7a->memory_ap, buffer, size, count, address);
- } else {
+ } else if (target->state == TARGET_HALTED) {
- /* write memory through APB-AP */
+ /* determine if MMU was enabled on target stop */
if (!armv7a->is_armv7r) {
- retval = cortex_a_mmu_modify(target, 0);
+ retval = cortex_a_mmu(target, &mmu_enabled);
if (retval != ERROR_OK)
return retval;
}
- return cortex_a_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-A 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 = 0;
- cacheline < size * count;
- cacheline += 64) {
- retval = dpm->instr_write_data_r0(dpm,
- ARMV4_5_MCR(15, 0, 0, 7, 5, 1),
- address + cacheline);
+ /* write memory through APB-AP */
+ if (mmu_enabled) {
+ retval = cortex_a_mmu_modify(target, 0);
if (retval != ERROR_OK)
return retval;
}
- }
+ retval = cortex_a_write_apb_ab_memory(target, address, size, count, buffer);
+ 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 = 0;
- cacheline < size * count;
- cacheline += 64) {
- retval = dpm->instr_write_data_r0(dpm,
- ARMV4_5_MCR(15, 0, 0, 7, 6, 1),
- address + cacheline);
+ if (mmu_enabled) {
+ /* enable mmu */
+ retval = cortex_a_mmu_modify(target, 1);
if (retval != ERROR_OK)
return retval;
}
+ } else {
+ retval = ERROR_TARGET_NOT_HALTED;
}
-
- /* (void) */ dpm->finish(dpm);
}
return retval;
@@ -2740,11 +2848,8 @@ static int cortex_a_write_memory(struct target *target, uint32_t address,
uint32_t size, uint32_t count, const uint8_t *buffer)
{
int mmu_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_a handles unaligned memory access */
LOG_DEBUG("Writing memory at address 0x%" PRIx32 "; size %" PRId32 "; count %" PRId32, address,
@@ -2756,35 +2861,48 @@ static int cortex_a_write_memory(struct target *target, uint32_t address,
if (retval != ERROR_OK)
return retval;
}
+ /*
+ if (mmu_enabled) {
+ retval = cortex_a_check_address(target, address);
+ if (retval != ERROR_OK)
+ return retval;
+ }
+ */
+ if (target->state != TARGET_HALTED) {
- if (armv7a->memory_ap_available && (apsel == armv7a->memory_ap)) {
- LOG_DEBUG("Writing memory to address 0x%" PRIx32 "; size %" PRId32 "; count %" PRId32, address, size,
- count);
- if (mmu_enabled) {
- virt = address;
- retval = cortex_a_virt2phys(target, virt, &phys);
- if (retval != ERROR_OK)
- return retval;
-
- LOG_DEBUG("Writing to virtual address. Translating v:0x%" PRIx32 " to r:0x%" PRIx32,
- virt,
- phys);
- address = phys;
- }
- retval = cortex_a_write_phys_memory(target, address, size,
- count, buffer);
+ if (mmu_enabled)
+ retval = ERROR_TARGET_NOT_HALTED;
+ else
+ retval = cortex_a_write_phys_memory(target, address, size, count, buffer);
} else {
- if (mmu_enabled) {
- retval = cortex_a_check_address(target, address);
- if (retval != ERROR_OK)
- return retval;
- /* enable MMU as we could have disabled it for phys access */
- retval = cortex_a_mmu_modify(target, 1);
+ retval = cortex_a_write_apb_ab_memory(target, address, size, count, buffer);
+#if 0
+ {
+ uint8_t *new_buf = malloc (size * count);
+ int i;
+ //retval = mem_ap_sel_read_buf(swjdp, armv7a->memory_ap, new_buf, size, count, address);
+ retval = cortex_a_read_apb_ab_memory(target, address, size, count, new_buf);
if (retval != ERROR_OK)
return retval;
+ for (i = 0; i < size * count; i++)
+ if (buffer[i] != new_buf[i]) {
+ uint32_t r0;
+ cortex_a_dap_read_coreregister_u32(target, &r0, 0);
+ return ERROR_FAIL;
+ }
}
- retval = cortex_a_write_apb_ab_memory(target, address, size, count, buffer);
+#endif
}
+ if (retval == ERROR_OK && mmu_enabled)
+ retval = armv7a_clean_data_cache(target, address, size, count);
+
+ if (retval == ERROR_OK)
+ retval = armv7a_invalidate_instruction_cache(target, address, size, count);
+
+ if (retval == ERROR_OK && !mmu_enabled
+ && armv7a->armv7a_mmu.armv7a_cache.l2_cache)
+ retval = armv7a_l2x_invalidate_all_data(target);
+
return retval;
}
@@ -2999,6 +3117,21 @@ static int cortex_a_examine(struct target *target)
return retval;
}
+static int cortex_a_setup_semihosting(struct target *target, int enable)
+{
+ struct armv7a_common *armv7a = target_to_armv7a(target);
+ struct adiv5_dap *swjdp = armv7a->arm.dap;
+ uint32_t vcr;
+
+ mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap, armv7a->debug_base + CPUDBG_VCR, &vcr);
+ if (enable)
+ mem_ap_sel_write_atomic_u32(swjdp, armv7a->debug_ap, armv7a->debug_base + CPUDBG_VCR, vcr | VCR_SVC);
+ else
+ mem_ap_sel_write_atomic_u32(swjdp, armv7a->debug_ap, armv7a->debug_base + CPUDBG_VCR, vcr & ~VCR_SVC);
+
+ return ERROR_OK;
+}
+
/*
* Cortex-A target creation and initialization
*/
@@ -3006,15 +3139,27 @@ static int cortex_a_examine(struct target *target)
static int cortex_a_init_target(struct command_context *cmd_ctx,
struct target *target)
{
- /* examine_first() does a bunch of this */
+ target->fileio_info = malloc(sizeof(struct gdb_fileio_info));
+ target->fileio_info->identifier = NULL;
+
return ERROR_OK;
}
static int cortex_a_init_arch_info(struct target *target,
- struct cortex_a_common *cortex_a, struct jtag_tap *tap)
+ struct cortex_a_common *cortex_a, struct jtag_tap *tap,
+ Jim_Interp *interp)
{
struct armv7a_common *armv7a = &cortex_a->armv7a_common;
struct adiv5_dap *dap = &armv7a->dap;
+ struct Jim_Obj *objPtr;
+ const char *map;
+
+ armv7a->arm.setup_semihosting = cortex_a_setup_semihosting;
+ armv7a->arm.is_semihosting = false;
+ armv7a->arm.hit_syscall = false;
+ armv7a->arm.active_syscall_id = 0;
+ armv7a->arm.semihosting_errno = 0;
+ armv7a->arm.semihosting_ctrl_c = false;
armv7a->arm.dap = dap;
@@ -3041,6 +3186,8 @@ static int cortex_a_init_arch_info(struct target *target,
cortex_a->fast_reg_read = 0;
+ cortex_a->is_stepping = 0;
+
/* register arch-specific functions */
armv7a->examine_debug_reason = NULL;
@@ -3055,6 +3202,16 @@ static int cortex_a_init_arch_info(struct target *target,
/* REVISIT v7a setup should be in a v7a-specific routine */
armv7a_init_arch_info(target, armv7a);
+
+ objPtr = Jim_GetGlobalVariableStr(interp, "MEMORY_MAP", JIM_NONE);
+ if (objPtr) {
+ map = Jim_GetString(objPtr, NULL);
+ cortex_a_parse_memory_map(target, map);
+ } else {
+ dap->ahb_mem_start_address = 0;
+ dap->ahb_mem_end_address = 0xffffffff;
+ }
+
target_register_timer_callback(cortex_a_handle_target_request, 1, 1, target);
return ERROR_OK;
@@ -3066,7 +3223,7 @@ static int cortex_a_target_create(struct target *target, Jim_Interp *interp)
cortex_a->armv7a_common.is_armv7r = false;
- return cortex_a_init_arch_info(target, cortex_a, target->tap);
+ return cortex_a_init_arch_info(target, cortex_a, target->tap, interp);
}
static int cortex_r4_target_create(struct target *target, Jim_Interp *interp)
@@ -3075,7 +3232,7 @@ static int cortex_r4_target_create(struct target *target, Jim_Interp *interp)
cortex_a->armv7a_common.is_armv7r = true;
- return cortex_a_init_arch_info(target, cortex_a, target->tap);
+ return cortex_a_init_arch_info(target, cortex_a, target->tap, interp);
}
@@ -3193,6 +3350,53 @@ COMMAND_HANDLER(cortex_a_handle_smp_gdb_command)
return ERROR_OK;
}
+COMMAND_HANDLER(cortex_a_handle_mmu_command)
+{
+ struct target *target = get_current_target(CMD_CTX);
+ struct armv7a_common *armv7a = target_to_armv7a(target);
+ struct arm *arm = &armv7a->arm;
+ int 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;
+ uint32_t sctlr;
+
+ COMMAND_PARSE_ENABLE(CMD_ARGV[0], enable);
+
+ /* MRC p15, 0, <Rt>, c1, c0, 0 ; Read SCTLR */
+ retval = arm->mrc(target, 15,
+ 0, 0, /* op1, op2 */
+ 1, 0, /* CRn, CRm */
+ &sctlr);
+ if (retval != ERROR_OK)
+ return retval;
+
+ if (enable)
+ sctlr |= 0x1;
+ else
+ sctlr &= ~0x1;
+
+ /* MCR p15, 0, <Rt>, c1, c0, 0 ; Write SCTLR */
+ retval = arm->mcr(target, 15,
+ 0, 0, /* op1, op2 */
+ 1, 0, /* CRn, CRm */
+ sctlr);
+ if (retval != ERROR_OK)
+ return retval;
+
+ armv7a->armv7a_mmu.mmu_enabled = enable;
+ }
+
+ command_print(CMD_CTX, "mmu %s",
+ (armv7a->armv7a_mmu.mmu_enabled) ? "enabled" : "disabled");
+
+ return ERROR_OK;
+}
static const struct command_registration cortex_a_exec_command_handlers[] = {
{
.name = "cache_info",
@@ -3227,6 +3431,13 @@ static const struct command_registration cortex_a_exec_command_handlers[] = {
.help = "display/fix current core played to gdb",
.usage = "",
},
+ {
+ .name = "mmu",
+ .handler = cortex_a_handle_mmu_command,
+ .mode = COMMAND_EXEC,
+ .help = "enable or disable the MMU",
+ .usage = "['enable'|'disable']",
+ },
COMMAND_REGISTRATION_DONE
@@ -3279,6 +3490,7 @@ struct target_type cortexa_target = {
.remove_breakpoint = cortex_a_remove_breakpoint,
.add_watchpoint = NULL,
.remove_watchpoint = NULL,
+ .hit_watchpoint = NULL,
.commands = cortex_a_command_handlers,
.target_create = cortex_a_target_create,
@@ -3289,6 +3501,10 @@ struct target_type cortexa_target = {
.write_phys_memory = cortex_a_write_phys_memory,
.mmu = cortex_a_mmu,
.virt2phys = cortex_a_virt2phys,
+
+ .get_gdb_fileio_info = arm_get_gdb_fileio_info,
+ .gdb_fileio_end = arm_gdb_fileio_end,
+ .pre_write_buffer = arm_gdb_fileio_pre_write_buffer,
};
static const struct command_registration cortex_r4_exec_command_handlers[] = {
diff --git a/src/target/cortex_a.h b/src/target/cortex_a.h
index ebf79b8..0a86eac 100644
--- a/src/target/cortex_a.h
+++ b/src/target/cortex_a.h
@@ -91,8 +91,9 @@ struct cortex_a_common {
uint32_t ttypr;
uint32_t didr;
- struct armv7a_common armv7a_common;
+ int is_stepping;
+ struct armv7a_common armv7a_common;
};
static inline struct cortex_a_common *
diff --git a/src/target/cortex_a_memory_map.c b/src/target/cortex_a_memory_map.c
new file mode 100644
index 0000000..7c4205c
--- /dev/null
+++ b/src/target/cortex_a_memory_map.c
@@ -0,0 +1,130 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "helper/log.h"
+
+#include "target.h"
+#include "armv7a.h"
+#include "cortex_a_memory_map.h"
+
+
+#if !defined(HAVE_LIBEXPAT)
+
+int cortex_a_parse_memory_map(struct target *target, const char *memory_map)
+{
+ LOG_WARNING("%s: cannot parse XML memory map; XML support was disabled at compile time", target_name(target));
+ return ERROR_FAIL;
+}
+
+#else /* HAVE_LIBEXPAT */
+
+#include "xml_support.h"
+
+struct cortex_a_memory_map_parsing_data
+{
+ char *processor;
+ uint32_t ahb_mem;
+ uint32_t ahb_mem_end;
+};
+
+
+/* Callback called by Expat on start of element.
+ This function handles the following elements:
+ * processor: unused now
+ * memory: a memory region
+ * property: unused now
+ The target name is in format PROCESSOR */
+static void memory_map_start_element(void *data_, const XML_Char *name,
+ const XML_Char **attrs)
+{
+ struct cortex_a_memory_map_parsing_data *data = data_;
+
+ if (strcmp(name, "processor") == 0)
+ {
+ const char *attr = xml_find_attribute(attrs, "name");
+ if (!attr)
+ attr = "";
+ data->processor = strdup(attr);
+ if (!data->processor)
+ LOG_ERROR("cortex_a: strdup(%s) failed", attr);
+ }
+ else if (strcmp(name, "memory") == 0)
+ {
+ const XML_Char *memory_name;
+ uint32_t *start = NULL, *end = NULL;
+
+ memory_name = xml_find_attribute(attrs, "name");
+ if (strcmp(memory_name, "ahb_mem") == 0)
+ {
+ start = &data->ahb_mem;
+ end = &data->ahb_mem_end;
+ }
+
+ if (xml_parse_uint32(xml_find_attribute(attrs, "start"), start) < 0)
+ return;
+
+ if (end)
+ {
+ if (xml_parse_uint32(xml_find_attribute(attrs, "length"), end) < 0)
+ return;
+ *end += *start - 1;
+ }
+ }
+ else if (strcmp(name, "property") == 0)
+ {
+ /* Ignore for now */
+ }
+}
+
+static void memory_map_end_element(void *data_, const XML_Char *name)
+{
+ struct cortex_a_memory_map_parsing_data *data = data_;
+
+ if (strcmp(name, "processor") == 0)
+ {
+ free(data->processor);
+ data->processor = NULL;
+ }
+}
+
+static void memory_map_character_data(void *data_, const XML_Char *s, int len)
+{
+ return;
+}
+
+int cortex_a_parse_memory_map(struct target *target, const char *memory_map)
+{
+ struct armv7a_common *armv7a = target_to_armv7a(target);
+ struct adiv5_dap *dap = armv7a->arm.dap;
+ int retval;
+
+ struct cortex_a_memory_map_parsing_data data;
+
+ data.processor = NULL;
+
+ XML_Parser parser = XML_ParserCreateNS(NULL, '!');
+ if (parser == NULL)
+ return ERROR_FAIL;
+
+ XML_SetElementHandler(parser, memory_map_start_element, memory_map_end_element);
+ XML_SetCharacterDataHandler(parser, memory_map_character_data);
+ XML_SetUserData(parser, &data);
+
+ retval = XML_Parse(parser, memory_map, strlen(memory_map), 1);
+ if (retval != XML_STATUS_OK)
+ {
+ enum XML_Error err = XML_GetErrorCode(parser);
+ LOG_ERROR("%s: cannot parse XML memory map [%s]",
+ target_name(target), XML_ErrorString(err));
+ return ERROR_FAIL;
+ }
+
+ dap->ahb_mem_start_address = data.ahb_mem;
+ dap->ahb_mem_end_address = data.ahb_mem_end;
+
+ return ERROR_OK;
+}
+
+#endif
+
diff --git a/src/target/cortex_a_memory_map.h b/src/target/cortex_a_memory_map.h
new file mode 100644
index 0000000..8f4aa25
--- /dev/null
+++ b/src/target/cortex_a_memory_map.h
@@ -0,0 +1,6 @@
+#ifndef CORTEX_A_MEMORY_MAP_H
+#define CORTEX_A_MEMORY_MAP_H
+
+extern int cortex_a_parse_memory_map(struct target *target, const char *memory_map);
+
+#endif
diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c
index 2cb83a4..06a67e3 100644
--- a/src/target/cortex_m.c
+++ b/src/target/cortex_m.c
@@ -56,7 +56,9 @@
/**
* Returns the type of a break point required by address location
*/
-#define BKPT_TYPE_BY_ADDR(addr) ((addr) < 0x20000000 ? BKPT_HARD : BKPT_SOFT)
+/* #define BKPT_TYPE_BY_ADDR(addr) ((addr) < 0x20000000 ? BKPT_HARD : BKPT_SOFT) */
+/* This is only for ADuCM302x */
+#define BKPT_TYPE_BY_ADDR(addr) ((addr) < 0x40800 ? BKPT_HARD : BKPT_SOFT)
/* forward declarations */
static int cortex_m_store_core_reg_u32(struct target *target,
@@ -168,39 +170,6 @@ static int cortex_m_clear_halt(struct target *target)
return ERROR_OK;
}
-static int cortex_m_single_step_core(struct target *target)
-{
- struct cortex_m_common *cortex_m = target_to_cm(target);
- struct adiv5_dap *swjdp = cortex_m->armv7m.arm.dap;
- uint32_t dhcsr_save;
- int retval;
-
- /* backup dhcsr reg */
- dhcsr_save = cortex_m->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_m->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_m->dcb_dhcsr = dhcsr_save;
- cortex_m_clear_halt(target);
-
- return ERROR_OK;
-}
-
static int cortex_m_enable_fpb(struct target *target)
{
int retval = target_write_u32(target, FP_CTRL, 3);
@@ -549,8 +518,8 @@ static int cortex_m_poll(struct target *target)
if (retval != ERROR_OK)
return retval;
- if (arm_semihosting(target, &retval) != 0)
- return retval;
+ if (arm_semihosting(target))
+ cortex_m->armv7m.arm.hit_syscall = true;
target_call_event_callbacks(target, TARGET_EVENT_HALTED);
}
@@ -690,7 +659,6 @@ static int cortex_m_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;
@@ -699,6 +667,11 @@ static int cortex_m_resume(struct target *target, int current,
return ERROR_TARGET_NOT_HALTED;
}
+ if (armv7m->arm.hit_syscall) {
+ arm_semihosting_step_over_bkpt(target);
+ armv7m->arm.hit_syscall = false;
+ }
+
if (!debug_execution) {
target_free_all_working_areas(target);
cortex_m_enable_breakpoints(target);
@@ -738,32 +711,10 @@ static int cortex_m_resume(struct target *target, int current,
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: %" PRIu32 ")",
- breakpoint->address,
- breakpoint->unique_id);
- cortex_m_unset_breakpoint(target, breakpoint);
- cortex_m_single_step_core(target);
- cortex_m_set_breakpoint(target, breakpoint);
- }
- }
-
/* Restart core */
cortex_m_write_debug_halt_mask(target, 0, C_HALT);
@@ -794,7 +745,6 @@ static int cortex_m_step(struct target *target, int current,
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;
@@ -803,6 +753,13 @@ static int cortex_m_step(struct target *target, int current,
return ERROR_TARGET_NOT_HALTED;
}
+ if (armv7m->arm.hit_syscall) {
+ arm_semihosting_step_over_bkpt(target);
+ armv7m->arm.hit_syscall = false;
+ target_call_event_callbacks(target, TARGET_EVENT_HALTED);
+ return ERROR_OK;
+ }
+
/* current = 1: continue on current pc, otherwise continue at <address> */
if (!current)
buf_set_u32(pc->value, 0, 32, address);
@@ -816,10 +773,6 @@ static int cortex_m_step(struct target *target, int current,
cortex_m_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);
@@ -827,7 +780,18 @@ static int cortex_m_step(struct target *target, int current,
/* 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) {
+
+ /* pretend that we hit a breakpoint and check if the instruction is a
+ semihosting call */
+ target->debug_reason = DBG_REASON_BREAKPOINT;
+ if (arm_semihosting(target)) {
+ armv7m->arm.hit_syscall = true;
+ target_call_event_callbacks(target, TARGET_EVENT_HALTED);
+ return ERROR_OK;
+ }
+
+ target->debug_reason = DBG_REASON_SINGLESTEP;
+
/* Automatic ISR masking mode off: Just step over the next instruction */
if ((cortex_m->isrmasking_mode != CORTEX_M_ISRMASK_AUTO))
cortex_m_write_debug_halt_mask(target, C_STEP, C_HALT);
@@ -926,7 +890,6 @@ static int cortex_m_step(struct target *target, int current,
}
}
}
- }
retval = mem_ap_read_atomic_u32(swjdp, DCB_DHCSR, &cortex_m->dcb_dhcsr);
if (retval != ERROR_OK)
@@ -1470,6 +1433,19 @@ int cortex_m_remove_watchpoint(struct target *target, struct watchpoint *watchpo
return ERROR_OK;
}
+static int cortex_m_hit_watchpoint(struct target *target, struct watchpoint **hit_watchpoint)
+{
+ struct watchpoint *watchpoint = target->watchpoints;
+
+ /* we only support only 1 watchpoint */
+ if (watchpoint) {
+ *hit_watchpoint = watchpoint;
+ return ERROR_OK;
+ }
+
+ return ERROR_FAIL;
+}
+
void cortex_m_enable_watchpoints(struct target *target)
{
struct watchpoint *watchpoint = target->watchpoints;
@@ -1685,6 +1661,9 @@ static int cortex_m_write_memory(struct target *target, uint32_t address,
static int cortex_m_init_target(struct command_context *cmd_ctx,
struct target *target)
{
+ target->fileio_info = malloc(sizeof(struct gdb_fileio_info));
+ target->fileio_info->identifier = NULL;
+
armv7m_build_reg_cache(target);
return ERROR_OK;
}
@@ -1982,6 +1961,11 @@ int cortex_m_examine(struct target *target)
target_name(target),
cortex_m->fp_num_code,
cortex_m->dwt_num_comp);
+
+ if (cortex_m->dwt_num_comp > 1) {
+ cortex_m->dwt_num_comp = 1;
+ LOG_INFO("%s: but you can only set 1 watchpoint", target_name(target));
+ }
}
return ERROR_OK;
@@ -2087,6 +2071,8 @@ static int cortex_m_init_arch_info(struct target *target,
* if not it will use CORTEX_M3_RESET_VECTRESET */
cortex_m->soft_reset_config = CORTEX_M_RESET_VECTRESET;
+ armv7m->arm.hit_syscall = false;
+
armv7m->arm.dap = &armv7m->dap;
/* Leave (only) generic DAP stuff for debugport_init(); */
@@ -2383,10 +2369,15 @@ struct target_type cortexm_target = {
.remove_breakpoint = cortex_m_remove_breakpoint,
.add_watchpoint = cortex_m_add_watchpoint,
.remove_watchpoint = cortex_m_remove_watchpoint,
+ .hit_watchpoint = cortex_m_hit_watchpoint,
.commands = cortex_m_command_handlers,
.target_create = cortex_m_target_create,
.init_target = cortex_m_init_target,
.examine = cortex_m_examine,
.deinit_target = cortex_m_deinit_target,
+
+ .get_gdb_fileio_info = arm_get_gdb_fileio_info,
+ .gdb_fileio_end = arm_gdb_fileio_end,
+ .pre_write_buffer = arm_gdb_fileio_pre_write_buffer,
};
diff --git a/src/target/hla_target.c b/src/target/hla_target.c
index d0be966..5859d26 100644
--- a/src/target/hla_target.c
+++ b/src/target/hla_target.c
@@ -463,9 +463,6 @@ static int adapter_poll(struct target *target)
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);
}
diff --git a/src/target/image.c b/src/target/image.c
index b1b7e3a..6bd4618 100644
--- a/src/target/image.c
+++ b/src/target/image.c
@@ -483,7 +483,7 @@ static int image_elf_read_section(struct image *image,
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,
+ LOG_DEBUG("read elf: size = 0x%"PRIzu" 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);
diff --git a/src/target/target.c b/src/target/target.c
index 4ea445f..5e24f7c 100644
--- a/src/target/target.c
+++ b/src/target/target.c
@@ -65,9 +65,9 @@ static int target_read_buffer_default(struct target *target, uint32_t address,
static int target_write_buffer_default(struct target *target, uint32_t address,
uint32_t count, const uint8_t *buffer);
static int target_array2mem(Jim_Interp *interp, struct target *target,
- int argc, Jim_Obj * const *argv);
+ int argc, Jim_Obj * const *argv, bool physical);
static int target_mem2array(Jim_Interp *interp, struct target *target,
- int argc, Jim_Obj * const *argv);
+ int argc, Jim_Obj * const *argv, bool physical);
static int target_register_user_commands(struct command_context *cmd_ctx);
static int target_get_gdb_fileio_info_default(struct target *target,
struct gdb_fileio_info *fileio_info);
@@ -104,6 +104,7 @@ extern struct target_type nds32_v3_target;
extern struct target_type nds32_v3m_target;
extern struct target_type or1k_target;
extern struct target_type quark_x10xx_target;
+extern struct target_type blackfin_target;
static struct target_type *target_types[] = {
&arm7tdmi_target,
@@ -133,6 +134,7 @@ static struct target_type *target_types[] = {
&nds32_v3m_target,
&or1k_target,
&quark_x10xx_target,
+ &blackfin_target,
NULL,
};
@@ -896,12 +898,15 @@ int target_run_flash_async_algorithm(struct target *target,
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;
+ /* make sure the size of FIFO is multiple of block_size */
+ assert((fifo_end_addr - fifo_start_addr) % block_size == 0);
/* validate block_size is 2^n */
assert(!block_size || !(block_size & (block_size - 1)));
+ uint32_t wp = fifo_start_addr;
+ uint32_t rp = fifo_start_addr;
+
retval = target_write_u32(target, wp_addr, wp);
if (retval != ERROR_OK)
return retval;
@@ -929,8 +934,8 @@ int target_run_flash_async_algorithm(struct target *target,
break;
}
- LOG_DEBUG("offs 0x%zx count 0x%" PRIx32 " wp 0x%" PRIx32 " rp 0x%" PRIx32,
- (size_t) (buffer - buffer_orig), count, wp, rp);
+ LOG_DEBUG("offs 0x%"PRIz"x count 0x%" PRIx32 " wp 0x%" PRIx32 " rp 0x%" PRIx32,
+ (buffer - buffer_orig), count, wp, rp);
if (rp == 0) {
LOG_ERROR("flash write algorithm aborted by target");
@@ -1208,6 +1213,8 @@ static int target_init_one(struct command_context *cmd_ctx,
return retval;
}
+ target->no_callbacks = false;
+
/* Sanity-check MMU support ... stub in what we must, to help
* implement it in stages, but warn if we need to do so.
*/
@@ -1985,6 +1992,12 @@ int target_write_buffer(struct target *target, uint32_t address, uint32_t size,
return ERROR_FAIL;
}
+ if (target->type->pre_write_buffer) {
+ int ret = target->type->pre_write_buffer(target, address, size, buffer);
+ if (ret == ERROR_OK)
+ return ret;
+ }
+
return target->type->write_buffer(target, address, size, buffer);
}
@@ -3346,7 +3359,7 @@ static COMMAND_HELPER(handle_verify_image_command_internal, int verify)
free(data);
}
} else {
- command_print(CMD_CTX, "address 0x%08" PRIx32 " length 0x%08zx",
+ command_print(CMD_CTX, "address 0x%08" PRIx32 " length 0x%08"PRIzx,
image.sections[i].base_address,
buf_cnt);
}
@@ -3626,7 +3639,7 @@ 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));
+ LOG_ERROR("failed to write %"PRIzu" bytes: %s", len, strerror(errno));
}
static void writeLong(FILE *f, int l, struct target *target)
@@ -3854,10 +3867,28 @@ static int jim_mem2array(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
return JIM_ERR;
}
- return target_mem2array(interp, target, argc - 1, argv + 1);
+ return target_mem2array(interp, target, argc - 1, argv + 1, false /* physical */);
}
-static int target_mem2array(Jim_Interp *interp, struct target *target, int argc, Jim_Obj *const *argv)
+static int jim_pmem2array(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, true /* physical */);
+}
+
+
+static int target_mem2array(Jim_Interp *interp, struct target *target, int argc, Jim_Obj *const *argv, bool physical)
{
long l;
uint32_t width;
@@ -3959,7 +3990,11 @@ static int target_mem2array(Jim_Interp *interp, struct target *target, int argc,
if (count > (buffersize / width))
count = (buffersize / width);
- retval = target_read_memory(target, addr, width, count, buffer);
+ if (physical)
+ retval = target_read_phys_memory(target, addr, width, count, buffer);
+ else
+ 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",
@@ -4042,11 +4077,28 @@ static int jim_array2mem(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
return JIM_ERR;
}
- return target_array2mem(interp, target, argc-1, argv + 1);
+ return target_array2mem(interp, target, argc-1, argv + 1, false /* physical */);
+}
+
+static int jim_array2pmem(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, true /* physical */);
}
static int target_array2mem(Jim_Interp *interp, struct target *target,
- int argc, Jim_Obj *const *argv)
+ int argc, Jim_Obj *const *argv, bool physical)
{
long l;
uint32_t width;
@@ -4169,7 +4221,11 @@ static int target_array2mem(Jim_Interp *interp, struct target *target,
}
len -= count;
- retval = target_write_memory(target, addr, width, count, buffer);
+ if (physical)
+ retval = target_write_phys_memory(target, addr, width, count, buffer);
+ else
+ 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",
@@ -4241,6 +4297,8 @@ enum target_cfg_param {
TCFG_CHAIN_POSITION,
TCFG_DBGBASE,
TCFG_RTOS,
+ TCFG_RESTART_CTI_REG_ADDR,
+ TCFG_RESTART_CTI_CHANNEL,
};
static Jim_Nvp nvp_config_opts[] = {
@@ -4255,6 +4313,8 @@ static Jim_Nvp nvp_config_opts[] = {
{ .name = "-chain-position", .value = TCFG_CHAIN_POSITION },
{ .name = "-dbgbase", .value = TCFG_DBGBASE },
{ .name = "-rtos", .value = TCFG_RTOS },
+ { .name = "-restart-cti-reg-addr", .value = TCFG_RESTART_CTI_REG_ADDR },
+ { .name = "-restart-cti-channel", .value = TCFG_RESTART_CTI_CHANNEL },
{ .name = NULL, .value = -1 }
};
@@ -4529,6 +4589,35 @@ no_params:
}
/* loop for more */
break;
+
+ case TCFG_RESTART_CTI_REG_ADDR:
+ if (goi->isconfigure) {
+ e = Jim_GetOpt_Wide(goi, &w);
+ if (e != JIM_OK)
+ return e;
+ target->restart_cti_reg_addr = (uint32_t)w;
+ target->restart_use_cti = true;
+ } else {
+ if (goi->argc != 0)
+ goto no_params;
+ }
+ Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, target->restart_cti_reg_addr));
+ /* loop for more */
+ break;
+
+ case TCFG_RESTART_CTI_CHANNEL:
+ if (goi->isconfigure) {
+ e = Jim_GetOpt_Wide(goi, &w);
+ if (e != JIM_OK)
+ return e;
+ target->restart_cti_channel = (int32_t)w;
+ } else {
+ if (goi->argc != 0)
+ goto no_params;
+ }
+ Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, target->restart_cti_channel));
+ /* loop for more */
+ break;
}
} /* while (goi->argc) */
@@ -4781,14 +4870,28 @@ 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);
+ return target_mem2array(interp, target, argc - 1, argv + 1, false /* physical */);
}
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);
+ return target_array2mem(interp, target, argc - 1, argv + 1, false /* physical */);
+}
+
+static int jim_target_pmem2array(Jim_Interp *interp,
+ int argc, Jim_Obj *const *argv)
+{
+ struct target *target = Jim_CmdPrivData(interp);
+ return target_mem2array(interp, target, argc - 1, argv + 1, true /* physical */);
+}
+
+static int jim_target_array2pmem(Jim_Interp *interp,
+ int argc, Jim_Obj *const *argv)
+{
+ struct target *target = Jim_CmdPrivData(interp);
+ return target_array2mem(interp, target, argc - 1, argv + 1, true /* physical */);
}
static int jim_target_tap_disabled(Jim_Interp *interp)
@@ -5077,6 +5180,22 @@ static const struct command_registration target_instance_command_handlers[] = {
.usage = "arrayname bitwidth address count",
},
{
+ .name = "array2pmem",
+ .mode = COMMAND_EXEC,
+ .jim_handler = jim_target_array2pmem,
+ .help = "Writes Tcl array of 8/16/32 bit numbers "
+ "to target physical memory",
+ .usage = "arrayname bitwidth address count",
+ },
+ {
+ .name = "pmem2array",
+ .mode = COMMAND_EXEC,
+ .jim_handler = jim_target_pmem2array,
+ .help = "Loads Tcl array of 8/16/32 bit numbers "
+ "from target physical memory",
+ .usage = "arrayname bitwidth address count",
+ },
+ {
.name = "eventlist",
.mode = COMMAND_EXEC,
.jim_handler = jim_target_event_list,
@@ -5263,6 +5382,10 @@ static int target_create(Jim_GetOptInfo *goi)
target->rtos = NULL;
target->rtos_auto_detect = false;
+ target->restart_use_cti = false;
+ target->restart_cti_reg_addr = 0;
+ target->restart_cti_channel = 0;
+
/* Do the rest as "configure" options */
goi->isconfigure = 1;
e = target_configure(goi, target);
@@ -6098,6 +6221,22 @@ static const struct command_registration target_exec_command_handlers[] = {
.usage = "arrayname bitwidth address count",
},
{
+ .name = "pmem2array",
+ .mode = COMMAND_EXEC,
+ .jim_handler = jim_pmem2array,
+ .help = "read 8/16/32 bit physical memory and return as a TCL array "
+ "for script processing",
+ .usage = "arrayname bitwidth address count",
+ },
+ {
+ .name = "array2pmem",
+ .mode = COMMAND_EXEC,
+ .jim_handler = jim_array2pmem,
+ .help = "convert a TCL array to physical 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,
diff --git a/src/target/target.h b/src/target/target.h
index 7471c1b..b01cfb2 100644
--- a/src/target/target.h
+++ b/src/target/target.h
@@ -197,6 +197,14 @@ struct target {
/* file-I/O information for host to do syscall */
struct gdb_fileio_info *fileio_info;
+
+ /** Shut off callbacks */
+ bool no_callbacks;
+
+ /* Some targets use CoreSight CTI to do restart */
+ bool restart_use_cti;
+ uint32_t restart_cti_reg_addr;
+ int restart_cti_channel;
};
struct target_list {
diff --git a/src/target/target_type.h b/src/target/target_type.h
index 234cdfb..5da48cc 100644
--- a/src/target/target_type.h
+++ b/src/target/target_type.h
@@ -126,6 +126,11 @@ struct target_type {
int (*read_buffer)(struct target *target, uint32_t address,
uint32_t size, uint8_t *buffer);
+ /* Allow target to do some pre-processing before write_buffer.
+ Don't call write_buffer if this function returns ERROR_OK. */
+ int (*pre_write_buffer)(struct target *target, uint32_t address,
+ uint32_t size, const 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);
diff --git a/src/target/trace.c b/src/target/trace.c
index 9c2d369..f2425dc 100644
--- a/src/target/trace.c
+++ b/src/target/trace.c
@@ -55,7 +55,7 @@ COMMAND_HANDLER(handle_trace_point_command)
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)",
+ command_print(CMD_CTX, "trace point 0x%8.8" PRIx32 " (%"PRIlld" times hit)",
trace->trace_points[i].address,
(long long)trace->trace_points[i].hit_counter);
}
diff --git a/src/target/xml_support.c b/src/target/xml_support.c
new file mode 100644
index 0000000..5f267b8
--- /dev/null
+++ b/src/target/xml_support.c
@@ -0,0 +1,39 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+
+#if defined(HAVE_LIBEXPAT)
+
+#include <expat.h>
+
+const XML_Char *xml_find_attribute(const XML_Char **attrs, const XML_Char *attr)
+{
+ const XML_Char **p;
+ for (p = attrs; *p; p += 2)
+ {
+ const char *name = p[0];
+ const char *val = p[1];
+ if (strcmp(name, attr) == 0)
+ return val;
+ }
+ return NULL;
+}
+
+int xml_parse_uint32(const char *str, uint32_t *p)
+{
+ char *endptr;
+ unsigned long result;
+
+ if (*str == '\0')
+ return -1;
+
+ result = strtol(str, &endptr, 0);
+ if (*endptr != '\0')
+ return -1;
+
+ *p = result;
+ return 0;
+}
+
+#endif /* HAVE_LIBEXPAT */
diff --git a/src/target/xml_support.h b/src/target/xml_support.h
new file mode 100644
index 0000000..b9cbd3e
--- /dev/null
+++ b/src/target/xml_support.h
@@ -0,0 +1,9 @@
+#ifndef XML_SUPPORT_H
+#define XML_SUPPORT_H
+
+#include <expat.h>
+
+extern const XML_Char *xml_find_attribute(const XML_Char **attrs, const XML_Char *attr);
+extern int xml_parse_uint32(const char *str, uint32_t *p);
+
+#endif /* XML_SUPPORT_H */
diff --git a/src/xsvf/xsvf.c b/src/xsvf/xsvf.c
index 6f8db8c..e5521bc 100644
--- a/src/xsvf/xsvf.c
+++ b/src/xsvf/xsvf.c
@@ -1016,7 +1016,7 @@ COMMAND_HANDLER(handle_xsvf_command)
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",
+ "unsupported xsvf command (0x%02X) at offset %"PRIjd", aborting",
uc, (intmax_t)offset);
return ERROR_FAIL;
}
diff --git a/tcl/board/adspsc573_ezkit.cfg b/tcl/board/adspsc573_ezkit.cfg
new file mode 100644
index 0000000..3795c3a
--- /dev/null
+++ b/tcl/board/adspsc573_ezkit.cfg
@@ -0,0 +1,11 @@
+# Analog Devices ADSP-SC573 EZ-KIT with SDRAM initialization
+
+set CHIPNAME adspsc573
+
+source [find target/adspsc57x.cfg]
+source [find board/adspsc5xx_ezbrd.tcl]
+
+proc adspsc57x_init {} {
+ cortex_a mmu disable
+ adspsc5xx_init_ddr3 0
+}
diff --git a/tcl/board/adspsc584_ezbrd.cfg b/tcl/board/adspsc584_ezbrd.cfg
new file mode 100644
index 0000000..0ffbb19
--- /dev/null
+++ b/tcl/board/adspsc584_ezbrd.cfg
@@ -0,0 +1,11 @@
+# Analog Devices ADSP-SC584 EZ-BRD with SDRAM initialization
+
+set CHIPNAME adspsc584
+
+source [find target/adspsc58x.cfg]
+source [find board/adspsc5xx_ezbrd.tcl]
+
+proc adspsc58x_init {} {
+ cortex_a mmu disable
+ adspsc5xx_init_ddr2
+}
diff --git a/tcl/board/adspsc589_ezbrd.cfg b/tcl/board/adspsc589_ezbrd.cfg
new file mode 100644
index 0000000..3c2fa4b
--- /dev/null
+++ b/tcl/board/adspsc589_ezbrd.cfg
@@ -0,0 +1,12 @@
+# Analog Devices ADSP-SC589 EZ-BRD with SDRAM initialization
+
+set CHIPNAME adspsc589
+
+source [find target/adspsc58x.cfg]
+source [find board/adspsc5xx_ezbrd.tcl]
+
+proc adspsc58x_init {} {
+ cortex_a mmu disable
+ adspsc5xx_init_ddr3 0
+ adspsc5xx_init_ddr3 1
+}
diff --git a/tcl/board/adspsc5xx_ezbrd.tcl b/tcl/board/adspsc5xx_ezbrd.tcl
new file mode 100644
index 0000000..6188734
--- /dev/null
+++ b/tcl/board/adspsc5xx_ezbrd.tcl
@@ -0,0 +1,274 @@
+# Common routines used by ADI ADSP-SC58x and ADSP-SC57x boards
+
+proc smpu_config { smpu } {
+ # Use SMPU instances to disable accesses to system memory that may not be
+ # populated or needs to be initialized before being accessed. This will
+ # avoid the possibility of an infinite stall in the system due to a
+ # speculative access to a disabled or uninitialized memory. This is also
+ # part of the workaround for silicon anomaly 20000018.
+
+ if { $smpu == 0 } {
+ set smpu_baseaddr 0x31007000
+ } elseif { $smpu == 8 } {
+ set smpu_baseaddr 0x31099000
+ } elseif { $smpu == 9 } {
+ set smpu_baseaddr 0x310a0000
+ } elseif { $smpu == 10 } {
+ set smpu_baseaddr 0x310a1000
+ } else {
+ puts stderr "Error: unknown SMPU number"
+ shutdown error
+ }
+
+ set smpu_ctl [expr {$smpu_baseaddr + 0x0}]
+ set smpu_securectl [expr {$smpu_baseaddr + 0x800}]
+
+ # SMC - SMPU instance 0
+ # *pREG_SMPU0_CTL |= ENUM_SMPU_CTL_RSDIS;
+ pmmw $smpu_ctl 0x1 0
+
+ # *pREG_SMPU0_SECURECTL = 0xf01;
+ mww phys $smpu_securectl 0xf01
+}
+
+proc adspsc5xx_init_ddr3 { dmc } {
+ global CHIPNAME
+
+ if { $dmc == 0 } {
+ set dmc_baseaddr 0x31070000
+ set dummy_addr 0x80000000
+ } else {
+ set dmc_baseaddr 0x31073000
+ set dummy_addr 0xc0000000
+ }
+
+ set dmc_ctl [expr {$dmc_baseaddr + 0x4}]
+ set dmc_stat [expr {$dmc_baseaddr + 0x8}]
+ set dmc_cfg [expr {$dmc_baseaddr + 0x40}]
+ set dmc_tr0 [expr {$dmc_baseaddr + 0x44}]
+ set dmc_tr1 [expr {$dmc_baseaddr + 0x48}]
+ set dmc_tr2 [expr {$dmc_baseaddr + 0x4c}]
+ set dmc_mr [expr {$dmc_baseaddr + 0x60}]
+ set dmc_emr1 [expr {$dmc_baseaddr + 0x64}]
+ set dmc_emr2 [expr {$dmc_baseaddr + 0x68}]
+ set dmc_dllctl [expr {$dmc_baseaddr + 0x80}]
+ set dmc_phy_ctl0 [expr {$dmc_baseaddr + 0x1000}]
+ set dmc_phy_ctl1 [expr {$dmc_baseaddr + 0x1004}]
+ set dmc_phy_ctl2 [expr {$dmc_baseaddr + 0x1008}]
+ set dmc_phy_ctl3 [expr {$dmc_baseaddr + 0x100c}]
+ set dmc_phy_ctl4 [expr {$dmc_baseaddr + 0x1010}]
+ set dmc_cal_padctl0 [expr {$dmc_baseaddr + 0x1034}]
+ set dmc_cal_padctl2 [expr {$dmc_baseaddr + 0x103c}]
+
+ # Configure SMPU (silicon anomaly 20000018)
+ if { $CHIPNAME == "adspsc589" } {
+ smpu_config 0
+ smpu_config 8
+ } elseif { $CHIPNAME == "adspsc573" } {
+ smpu_config 0
+ }
+
+ # Set the RESETDLL bit (bit 11 of the DMC_PHY_CTL0 register) before CGU Initialization.
+ # *pREG_DMC0_PHY_CTL0 |= BITM_DMC_PHY_CTL0_RESETDLL;
+ pmmw $dmc_phy_ctl0 0x800 0
+
+ # Set CGU clock select register to CLKO2/4 (ARM core)
+ mww phys 0x3108d010 4
+
+ # Reset processor to default power settings
+ # Clear DISABLE and set EXIT_ACTIVE in CGU0_PLLCTL
+ mww phys 0x3108d004 0x2
+ # Set DF = 0 MSEL = 0x12 in CGU0_CTL
+ mww phys 0x3108d000 0x1200
+ # Set SYSSEL = 2 S0SEL = 2 S1SEL = 2 CSEL = 1 DSEL = 1 in CGU0_DIV
+ mww phys 0x3108d00c 0x44014241
+
+ # Read CGU0_STAT to make sure it's in FULL ON mode
+ #mdw phys 0x3108d008
+
+ # Clear the PHY_CTL0 after CGU Initialization
+ mww phys $dmc_phy_ctl0 0
+
+ # Wait for DLL lock - 9000 DCLK cycles
+ # 1ms should be enough
+ after 1
+
+ # *pREG_DMC0_PHY_CTL0 |= 0x0000000F;
+ pmmw $dmc_phy_ctl0 0xf 0
+ # *pREG_DMC0_PHY_CTL2 |= 0xFC000000;
+ pmmw $dmc_phy_ctl2 0xfc000000 0
+ # *pREG_DMC0_PHY_CTL3 |= 0x0A0000C0;
+ pmmw $dmc_phy_ctl3 0xa0000c0 0
+
+ # *pREG_DMC0_PHY_CTL1 = 0x00000000;
+ mww phys $dmc_phy_ctl1 0
+
+ # *pREG_DMC0_PHY_CTL4 = 0x00000000;
+ mww phys $dmc_phy_ctl4 0
+
+ # Program the PAD RTT and driver impedance values required here
+ # *pREG_DMC0_CAL_PADCTL0 = 0xE0000000;
+ mww phys $dmc_cal_padctl0 0xe0000000
+ # *pREG_DMC0_CAL_PADCTL2 = 0x0078283C;
+ mww phys $dmc_cal_padctl2 0x0078283c
+
+ # Start calibration
+ # *pREG_DMC0_CAL_PADCTL0 |= 0x10000000;
+ pmmw $dmc_cal_padctl0 0x10000000 0
+
+ # Wait for PAD calibration to complete - 300 DCLK cycle.
+ # 1ms should be enough
+ after 1
+
+ # *pREG_DMC0_CFG = 0x00000522;
+ mww phys $dmc_cfg 0x00000522
+ # *pREG_DMC0_TR0 = 0x41711646;
+ mww phys $dmc_tr0 0x41711646
+ # *pREG_DMC0_TR1 = 0x40480db6;
+ mww phys $dmc_tr1 0x40480db6
+ # *pREG_DMC0_TR2 = 0x00347417;
+ mww phys $dmc_tr2 0x00347417
+ # *pREG_DMC0_MR = 0x00000D30;
+ mww phys $dmc_mr 0x00000D30
+ # *pREG_DMC0_EMR1 = 0x00000006;
+ mww phys $dmc_emr1 0x00000006
+ # *pREG_DMC0_EMR2 = 0x00000008;
+ mww phys $dmc_emr2 0x00000008
+ # *pREG_DMC0_CTL = 0x00000405;
+ mww phys $dmc_ctl 0x00000405
+
+ # Wait till INIDONE is set
+ # while((*pREG_DMC0_STAT&BITM_DMC_STAT_INITDONE)==0);
+ set data 0
+ while { [expr {$data & 4}] == 0 } {
+ set data [pmemread32 $dmc_stat]
+ }
+
+ # *pREG_DMC0_DLLCTL = 0x00000948;
+ mww phys $dmc_dllctl 0x00000948
+
+ # Workaround for silicon anomaly 20000037
+ # Dummy read
+ set data [memread32 $dummy_addr]
+ # *pREG_DMC0_PHY_CTL0|=0x1000;
+ # *pREG_DMC0_PHY_CTL0&=~0x1000;
+ set data [pmemread32 $dmc_phy_ctl0]
+ mww phys $dmc_phy_ctl0 [expr {$data | 0x1000}]
+ mww phys $dmc_phy_ctl0 [expr {$data & ~0x1000}]
+}
+
+proc adspsc5xx_init_ddr2 { } {
+ set dmc_baseaddr 0x31070000
+ set dummy_addr 0x80000000
+
+ set dmc_ctl [expr {$dmc_baseaddr + 0x4}]
+ set dmc_stat [expr {$dmc_baseaddr + 0x8}]
+ set dmc_cfg [expr {$dmc_baseaddr + 0x40}]
+ set dmc_tr0 [expr {$dmc_baseaddr + 0x44}]
+ set dmc_tr1 [expr {$dmc_baseaddr + 0x48}]
+ set dmc_tr2 [expr {$dmc_baseaddr + 0x4c}]
+ set dmc_mr [expr {$dmc_baseaddr + 0x60}]
+ set dmc_emr1 [expr {$dmc_baseaddr + 0x64}]
+ set dmc_emr2 [expr {$dmc_baseaddr + 0x68}]
+ set dmc_dllctl [expr {$dmc_baseaddr + 0x80}]
+ set dmc_phy_ctl0 [expr {$dmc_baseaddr + 0x1000}]
+ set dmc_phy_ctl1 [expr {$dmc_baseaddr + 0x1004}]
+ set dmc_phy_ctl2 [expr {$dmc_baseaddr + 0x1008}]
+ set dmc_phy_ctl3 [expr {$dmc_baseaddr + 0x100c}]
+ set dmc_phy_ctl4 [expr {$dmc_baseaddr + 0x1010}]
+ set dmc_cal_padctl0 [expr {$dmc_baseaddr + 0x1034}]
+ set dmc_cal_padctl2 [expr {$dmc_baseaddr + 0x103c}]
+
+ # Configure SMPU (silicon anomaly 20000018)
+ smpu_config 0
+ smpu_config 8
+ smpu_config 10
+
+ # Set the RESETDLL bit (bit 11 of the DMC_PHY_CTL0 register) before CGU Initialization.
+ # *pREG_DMC0_PHY_CTL0 |= BITM_DMC_PHY_CTL0_RESETDLL;
+ pmmw $dmc_phy_ctl0 0x800 0
+
+ # Set CGU clock select register to CLKO2/4 (ARM core)
+ mww phys 0x3108d010 4
+
+ # Reset processor to default power settings
+ # Clear DISABLE and set EXIT_ACTIVE in CGU0_PLLCTL
+ mww phys 0x3108d004 0x2
+ # Set DF = 0 MSEL = 0x10 in CGU0_CTL
+ mww phys 0x3108d000 0x1000
+ # Set SYSSEL = 2 S0SEL = 2 S1SEL = 2 CSEL = 1 DSEL = 1 in CGU0_DIV
+ mww phys 0x3108d00c 0x44014241
+
+ # Read CGU0_STAT to make sure it's in FULL ON mode
+ #mdw phys 0x3108d008
+
+ # Clear the PHY_CTL0 after CGU Initialization
+ mww phys $dmc_phy_ctl0 0
+
+ # Wait for DLL lock - 9000 DCLK cycles
+ # 1ms should be enough
+ after 1
+
+ # *pREG_DMC0_PHY_CTL0 |= 0x0000000F;
+ pmmw $dmc_phy_ctl0 0xf 0
+ # *pREG_DMC0_PHY_CTL2 |= 0xFC000000;
+ pmmw $dmc_phy_ctl2 0xfc000000 0
+ # *pREG_DMC0_PHY_CTL3 |= 0x0A0000C0;
+ pmmw $dmc_phy_ctl3 0xa0000c0 0
+
+ # *pREG_DMC0_PHY_CTL1 = 0x00000000;
+ mww phys $dmc_phy_ctl1 0
+
+ # *pREG_DMC0_PHY_CTL4 = 0x00000001;
+ mww phys $dmc_phy_ctl4 1
+
+ # Program the PAD RTT and driver impedance values required here
+ # *pREG_DMC0_CAL_PADCTL0 = 0xE0000000;
+ mww phys $dmc_cal_padctl0 0xe0000000
+ # *pREG_DMC0_CAL_PADCTL2 = 0x0078283C;
+ mww phys $dmc_cal_padctl2 0x0078283c
+
+ # Start calibration
+ # *pREG_DMC0_CAL_PADCTL0 |= 0x10000000;
+ pmmw $dmc_cal_padctl0 0x10000000 0
+
+ # Wait for PAD calibration to complete - 300 DCLK cycle.
+ # 1ms should be enough
+ after 1
+
+ # *pREG_DMC0_CFG = 0x00000522;
+ mww phys $dmc_cfg 0x00000522
+ # *pREG_DMC0_TR0 = 0x21610535;
+ mww phys $dmc_tr0 0x21610535
+ # *pREG_DMC0_TR1 = 0x404e0c30;
+ mww phys $dmc_tr1 0x404e0c30
+ # *pREG_DMC0_TR2 = 0x00326312;
+ mww phys $dmc_tr2 0x00326312
+ # *pREG_DMC0_MR = 0x00000a52;
+ mww phys $dmc_mr 0x00000a52
+ # *pREG_DMC0_EMR1 = 0x00000004;
+ mww phys $dmc_emr1 0x00000004
+ # *pREG_DMC0_EMR2 = 0x00000000;
+ mww phys $dmc_emr2 0x00000000
+ # *pREG_DMC0_CTL = 0x00000404;
+ mww phys $dmc_ctl 0x00000404
+
+ # Wait till INIDONE is set
+ # while((*pREG_DMC0_STAT&BITM_DMC_STAT_INITDONE)==0);
+ set data 0
+ while { [expr {$data & 4}] == 0 } {
+ set data [pmemread32 $dmc_stat]
+ }
+
+ # *pREG_DMC0_DLLCTL = 0x00000948;
+ mww phys $dmc_dllctl 0x00000948
+
+ # Workaround for silicon anomaly 20000037
+ # Dummy read
+ set data [memread32 $dummy_addr]
+ # *pREG_DMC0_PHY_CTL0|=0x1000;
+ # *pREG_DMC0_PHY_CTL0&=~0x1000;
+ set data [pmemread32 $dmc_phy_ctl0]
+ mww phys $dmc_phy_ctl0 [expr {$data | 0x1000}]
+ mww phys $dmc_phy_ctl0 [expr {$data & ~0x1000}]
+}
diff --git a/tcl/board/bf537_ezkit.cfg b/tcl/board/bf537_ezkit.cfg
new file mode 100644
index 0000000..86bd898
--- /dev/null
+++ b/tcl/board/bf537_ezkit.cfg
@@ -0,0 +1,21 @@
+# Analog Devices ADSP-BF537 EZ-KIT LITE board
+
+set SDRAM_SIZE 0x4000000
+set FLASH_SIZE 0x400000
+
+# Config parameters for SDRAM on the board
+
+global SDRRC
+global SDBCTL
+global SDGCTL
+set SDRRC 0x03a0
+set SDBCTL 0x0025
+set SDGCTL 0x0091998d
+
+source [find target/bf537.cfg]
+
+$_TARGETNAME configure -event reset-init {
+ blackfin wpu_init
+ blackfin sdram_init
+}
+$_TARGETNAME configure -event gdb-attach { reset init }
diff --git a/tcl/board/bf561_ezkit.cfg b/tcl/board/bf561_ezkit.cfg
new file mode 100644
index 0000000..8f349f1
--- /dev/null
+++ b/tcl/board/bf561_ezkit.cfg
@@ -0,0 +1,21 @@
+# Analog Devices ADSP-BF537 EZ-KIT LITE board
+
+set SDRAM_SIZE 0x4000000
+set FLASH_SIZE 0x800000
+
+# Config parameters for SDRAM on the board
+
+global SDRRC
+global SDBCTL
+global SDGCTL
+set SDRRC 0x01cf
+set SDBCTL 0x0013
+set SDGCTL 0x0091998d
+
+source [find target/bf561.cfg]
+
+$_TARGETNAME_A configure -event reset-init {
+ blackfin wpu_init
+ blackfin sdram_init
+}
+$_TARGETNAME_A configure -event gdb-attach { reset init }
diff --git a/tcl/cpu/blackfin/blackfin.cfg b/tcl/cpu/blackfin/blackfin.cfg
new file mode 100644
index 0000000..e2921c1
--- /dev/null
+++ b/tcl/cpu/blackfin/blackfin.cfg
@@ -0,0 +1,18 @@
+# common script for Blackfin
+
+set _CHIPNAME $CHIPNAME
+set _CPUTAPID $CPUTAPID
+
+jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id $_CPUTAPID -ignore-version
+
+set _TARGETNAME $_CHIPNAME.cpu
+target create $_TARGETNAME blackfin -chain-position $_TARGETNAME
+
+adapter_nsrst_delay 100
+jtag_ntrst_delay 100
+
+reset_config trst_only
+
+# FIXME
+gdb_memory_map disable
+
diff --git a/tcl/interface/ftdi/gnice+.cfg b/tcl/interface/ftdi/gnice+.cfg
new file mode 100644
index 0000000..16d0f3f
--- /dev/null
+++ b/tcl/interface/ftdi/gnice+.cfg
@@ -0,0 +1,13 @@
+#
+# Blackfin gnICE+
+#
+
+interface ftdi
+ftdi_device_desc "Blackfin gnICE+"
+ftdi_vid_pid 0x0456 0xf001
+
+ftdi_layout_init 0x0208 0x0a0b
+ftdi_layout_signal LED -ndata 0x0800
+ftdi_layout_signal nTRST -data 0x0020
+
+adapter_khz 30000
diff --git a/tcl/interface/ftdi/gnice.cfg b/tcl/interface/ftdi/gnice.cfg
new file mode 100644
index 0000000..a93e60f
--- /dev/null
+++ b/tcl/interface/ftdi/gnice.cfg
@@ -0,0 +1,13 @@
+#
+# Blackfin gnICE
+#
+
+interface ftdi
+ftdi_device_desc "Blackfin gnICE"
+ftdi_vid_pid 0x0456 0xf000
+
+ftdi_layout_init 0x0208 0x0a0b
+ftdi_layout_signal LED -ndata 0x0800
+ftdi_layout_signal nTRST -data 0x0020
+
+adapter_khz 6000
diff --git a/tcl/interface/ice1000.cfg b/tcl/interface/ice1000.cfg
new file mode 100644
index 0000000..91689e4
--- /dev/null
+++ b/tcl/interface/ice1000.cfg
@@ -0,0 +1,11 @@
+# Analog Devices ICE-1000 Emulator
+#
+# http://www.analog.com/ice1000
+#
+
+interface ice1000
+
+# valid frequencies: 1000: 1 MHz
+# 2000: 2 MHz
+# 5000: 5 MHz
+adapter_khz 1000
diff --git a/tcl/interface/ice2000.cfg b/tcl/interface/ice2000.cfg
new file mode 100644
index 0000000..ff59548
--- /dev/null
+++ b/tcl/interface/ice2000.cfg
@@ -0,0 +1,25 @@
+# Analog Devices ICE-2000 Emulator
+#
+# http://www.analog.com/ice2000
+#
+
+interface ice2000
+
+# valid voltages: 1: 1.8 V
+# 2: 2.5 V
+# 3: 3.3 V
+# default 3
+#ice2000_voltage 3
+
+# valid frequencies: 1000: 1 MHz
+# 2000: 2 MHz
+# 5000: 5 MHz
+# 9000: 9 MHz
+# 15000: 15 MHz
+# 23000: 23 MHz
+adapter_khz 1000
+
+# ICE-2000 supports up to 46 MHz. But not all processors will work
+# with this emuator frequency for all transport types (JTAG and SWD).
+#
+# 46000: 46 MHz
diff --git a/tcl/mem_helper.tcl b/tcl/mem_helper.tcl
index a3d92cb..563ff95 100644
--- a/tcl/mem_helper.tcl
+++ b/tcl/mem_helper.tcl
@@ -20,3 +20,24 @@ proc mmw {reg setbits clearbits} {
add_usage_text mmw "address setbits clearbits"
add_help_text mmw "Modify word in memory. new_val = (old_val & ~clearbits) | setbits;"
+
+# pmrw: "physical memory read word", returns value of $reg
+proc pmrw {reg} {
+ set value ""
+ pmem2array value 32 $reg 1
+ return $value(0)
+}
+
+add_usage_text pmrw "address"
+add_help_text pmrw "Returns value of word in physical memory."
+
+# pmmw: "physical memory modify word", updates value of $reg
+# $reg <== ((value & ~$clearbits) | $setbits)
+proc pmmw {reg setbits clearbits} {
+ set old [pmrw $reg]
+ set new [expr ($old & ~$clearbits) | $setbits]
+ mww phys $reg $new
+}
+
+add_usage_text pmmw "address setbits clearbits"
+add_help_text pmmw "Modify word in physical memory. new_val = (old_val & ~clearbits) | setbits;"
diff --git a/tcl/memory.tcl b/tcl/memory.tcl
index 2719d3f..9677e0f 100644
--- a/tcl/memory.tcl
+++ b/tcl/memory.tcl
@@ -131,3 +131,57 @@ proc memwrite8 {ADDR DATA} {
error "memwrite8: $msg"
}
}
+
+proc pmemread32 {ADDR} {
+ set foo(0) 0
+ if ![ catch { pmem2array foo 32 $ADDR 1 } msg ] {
+ return $foo(0)
+ } else {
+ error "pmemread32: $msg"
+ }
+}
+
+proc pmemread16 {ADDR} {
+ set foo(0) 0
+ if ![ catch { pmem2array foo 16 $ADDR 1 } msg ] {
+ return $foo(0)
+ } else {
+ error "pmemread16: $msg"
+ }
+}
+
+proc pmemread8 {ADDR} {
+ set foo(0) 0
+ if ![ catch { pmem2array foo 8 $ADDR 1 } msg ] {
+ return $foo(0)
+ } else {
+ error "pmemread8: $msg"
+ }
+}
+
+proc pmemwrite32 {ADDR DATA} {
+ set foo(0) $DATA
+ if ![ catch { array2pmem foo 32 $ADDR 1 } msg ] {
+ return $foo(0)
+ } else {
+ error "pmemwrite32: $msg"
+ }
+}
+
+proc pmemwrite16 {ADDR DATA} {
+ set foo(0) $DATA
+ if ![ catch { array2pmem foo 16 $ADDR 1 } msg ] {
+ return $foo(0)
+ } else {
+ error "pmemwrite16: $msg"
+ }
+}
+
+proc pmemwrite8 {ADDR DATA} {
+ set foo(0) $DATA
+ if ![ catch { array2pmem foo 8 $ADDR 1 } msg ] {
+ return $foo(0)
+ } else {
+ error "pmemwrite8: $msg"
+ }
+}
diff --git a/tcl/mmr_helpers.tcl b/tcl/mmr_helpers.tcl
index ce116e4..d76ee5d 100644
--- a/tcl/mmr_helpers.tcl
+++ b/tcl/mmr_helpers.tcl
@@ -12,7 +12,7 @@ proc show_mmr32_reg { NAME } {
# we want $($NAME)
set a [set [set NAME]]
- if ![catch { set v [memread32 $a] } msg ] {
+ if ![catch { set v [pmemread32 $a] } msg ] {
echo [format "%15s: (0x%08x): 0x%08x" $NAME $a $v]
# Was a helper defined?
@@ -61,7 +61,7 @@ proc show_mmr32_bits { NAMES VAL } {
proc show_mmr_bitfield { MSB LSB VAL FIELDNAME FIELDVALUES } {
set width [expr (($MSB - $LSB + 1) + 7) / 4]
- set nval [show_normalize_bitfield $VAL $MSB $LSB ]
+ set nval [normalize_bitfield $VAL $MSB $LSB ]
set name0 [lindex $FIELDVALUES 0 ]
if [ string compare $name0 _NUMBER_ ] {
set sval [lindex $FIELDVALUES $nval]
diff --git a/tcl/target/adspsc57x.cfg b/tcl/target/adspsc57x.cfg
new file mode 100644
index 0000000..571ed6e
--- /dev/null
+++ b/tcl/target/adspsc57x.cfg
@@ -0,0 +1,256 @@
+# Analog Devices ADSP-SC57x
+
+#
+# ADSP-SC57x devices support JTAG and SWD transports.
+#
+transport select jtag
+#transport select swd
+
+source [find target/swj-dp.tcl]
+
+set CPU_MAX_ADDRESS 0xFFFFFFFF
+source [find bitsbytes.tcl]
+source [find memory.tcl]
+source [find mem_helper.tcl]
+source [find mmr_helpers.tcl]
+source [find target/adspsc5xx.tcl]
+
+# memory map
+
+set MAP_XML [find target/adspsc57x_memory_map.xml]
+set MAP_FILE [open $MAP_XML]
+set _MEMORY_MAP [read $MAP_FILE]
+close $MAP_FILE
+
+global MEMORY_MAP
+# substitute SDRAM_SIZE and FLASH_SIZE
+set MEMORY_MAP [subst $_MEMORY_MAP]
+
+# UserKey
+
+# Uncomment the following 4 lines and change 0x00000000 to key values
+#set USERKEY0 0x00000000
+#set USERKEY1 0x00000000
+#set USERKEY2 0x00000000
+#set USERKEY3 0x00000000
+
+if { [info exists USERKEY0] } {
+ set _USERKEY0 $USERKEY0
+} else {
+ set _USERKEY0 0x00000000
+}
+
+if { [info exists USERKEY1] } {
+ set _USERKEY1 $USERKEY1
+} else {
+ set _USERKEY1 0x00000000
+}
+
+if { [info exists USERKEY2] } {
+ set _USERKEY2 $USERKEY2
+} else {
+ set _USERKEY2 0x00000000
+}
+
+if { [info exists USERKEY3] } {
+ set _USERKEY3 $USERKEY3
+} else {
+ set _USERKEY3 0x00000000
+}
+
+# target config
+
+if { [info exists CHIPNAME] } {
+ set _CHIPNAME $CHIPNAME
+} else {
+ set _CHIPNAME adspsc57x
+}
+
+# CoreSight Debug Access Port (DAP)
+if { [info exists DAP_TAPID ] } {
+ set _DAP_TAPID $DAP_TAPID
+} else {
+ if { [using_jtag] } {
+ set _DAP_TAPID 0x4ba00477
+ } else {
+ set _DAP_TAPID 0x3ba02477
+ }
+}
+
+if { [using_swd] } {
+ swj_newdap $_CHIPNAME dap -expected-id $_DAP_TAPID
+} else {
+ jtag newtap $_CHIPNAME dap -irlen 4 -expected-id $_DAP_TAPID -disable
+ jtag configure $_CHIPNAME.dap -event tap-enable "adjc_enable_dap $_CHIPNAME.adjc"
+
+ # ADI JTAG Controller
+ if { [info exists ADJC_TAPID ] } {
+ set _ADJC_TAPID $ADJC_TAPID
+ } else {
+ set _ADJC_TAPID 0x0280f0cb
+ }
+
+ jtag newtap $_CHIPNAME adjc -irlen 5 -expected-id $_ADJC_TAPID
+
+ # Once the JRC is up, enable our TAPs
+ jtag configure $_CHIPNAME.adjc -event setup "jtag tapenable $_CHIPNAME.dap"
+}
+
+# GDB target: Cortex-A5, using DAP
+set _TARGETNAME $_CHIPNAME.dap
+target create $_TARGETNAME cortex_a -chain-position $_TARGETNAME -dbgbase 0x80020000
+
+# system reset
+proc adspsc57x_system_reset {} {
+
+ # Read BMODE from RCU0_STAT
+ set data [pmemread32 0x3108c004]
+ set bootmode [expr {($data >> 8) & 0xf}]
+ puts "Boot Mode $bootmode"
+
+ # Clear SHARC-XI debug registers for both SHARC-XI cores
+ # If EMUCTL.EMUENA bit is set, the SHARC-XI core cannot be reset
+ reset_sharcxi_debug_regs 0x80001000
+ reset_sharcxi_debug_regs 0x80005000
+
+ puts "start system reset ..."
+
+ # Clear REG_RCU0_MSG
+ # *pREG_RCU0_MSG = 0x0
+ mww phys 0x3108c06c 0
+
+ # Deassert RSTOUT in REG_RCU0_STAT
+ # *pREG_RCU0_CTL |= 0x4
+ pmmw 0x3108c000 0x4 0
+
+ # Clear REG_RCU0_STAT
+ # *pREG_RCU0_STAT = 0x7000d
+ mww phys 0x3108c004 0x7000d
+
+ # Set HALT (bit 2)
+ # *pREG_RCU0_BCODE = 0x4
+ mww phys 0x3108c028 0x4
+
+ # There are two methods to do system reset
+
+ # Use RCU_CTL to do system reset
+ # *pREG_RCU0_CTL |= 0x00000001;
+ #pmmw 0x3108c000 0x1 0
+
+ # Use CTI to do system reset
+ # Unlock CTI3 (System CTI)
+ # *pREG_CTI3_LAR = 0xC5ACCE55
+ mww phys 0x3110dfb0 0xC5ACCE55
+
+ # Enable CTI3 (System CTI)
+ # *pREG_CTI3_CTICONTROL = 1
+ mww phys 0x3110d000 0x1
+
+ # Connect CTITRIGOUT[2] of CTI3 to channel 2
+ # *pREG_CTI3_CTIOUTEN2 = 4
+ mww phys 0x3110d0a8 0x4
+
+ # Send a signal to channel 2
+ # *pREG_CTI3_CTIAPPPULSE = 4
+ mww phys 0x3110d01c 0x4
+
+ puts "system reset asserted"
+
+ # Wait till Core 0 is idle
+ # while((*pREG_RCU0_MSG & BITM_RCU_MSG_C0IDLE) == 0);
+ set data 0
+ set retry 0
+ while { [expr {$data & 0x100}] == 0 } {
+ set data [pmemread32 0x3108c06c]
+ set retry [expr {$retry + 1}]
+ if { $retry > 10 } break;
+ }
+ if { $retry > 10 } {
+ set msg [format 0x%08x $data]
+ puts stderr "Error: BCODE.HALT failed (REG_RCU0_MSG $msg)"
+ }
+
+ # update target state
+ poll
+
+ # Halt the core
+ halt
+
+ # Clear C0IDLE from REG_RCU0_MSG
+ # *pREG_RCU0_MSG_CLR = 0x100
+ mww phys 0x3108c074 0x100
+
+ # Now BOOT is done
+ puts "system reset done"
+
+ set data [pmemread32 0x3108c004]
+ show_rcu_stat "REG_RCU0_STAT" $data
+
+ # Show REG_RCU0_MSG
+ set data [pmemread32 0x3108c06c]
+ show_rcu_msg "REG_RCU0_MSG" $data
+
+ # clear REG_RCU0_MSG
+ mww phys 0x3108c06c 0
+ # clear REG_RCU0_BCODE
+ mww phys 0x3108c028 0
+ # Disable CTI3 (System CTI)
+ mww phys 0x3110d000 0
+}
+
+$_TARGETNAME configure -event reset-assert {
+ adspsc57x_system_reset
+}
+
+$_TARGETNAME configure -event examine-end {
+ global _CHIPNAME
+
+ # read PADS STAT register and store the value in data
+ set pads_stat 0x31004468
+ set data [pmemread32 $pads_stat]
+ if { "$_CHIPNAME" == "adspsc571" && [expr {$data & 1}] == 0 } {
+ puts stderr "Error: ADSP-SC573 found instead of ADSP-SC571"
+ shutdown error
+ } elseif { "$_CHIPNAME" == "adspsc573" && [expr {$data & 1}] == 1 } {
+ puts stderr "Error: ADSP-SC571 found instead of ADSP-SC573"
+ shutdown error
+ }
+}
+
+# default initialization
+proc adspsc57x_init {} {
+}
+
+# Unless USE_CTI is set to 0, CTI is used to restart the Cortex-A5 core
+# so system peripherals can be restarted at the same time
+
+if { [info exists USE_CTI] } {
+ set _USE_CTI $USE_CTI
+} else {
+ set _USE_CTI 1
+}
+if { $_USE_CTI != 0 } {
+ echo "halt and restart using CTI"
+ $_TARGETNAME configure -restart-cti-reg-addr 0x3110d01c -restart-cti-channel 1
+}
+
+$_TARGETNAME configure -event gdb-attach {
+ # set all bits in TAPC0_DBGCTL to enable all kinds of debug
+ mww phys 0x31131000 0xffff
+
+ reset
+
+ if { $_USE_CTI != 0 } {
+ adspsc5xx_configure_cti
+ }
+
+ adspsc57x_init
+
+ arm semihosting enable
+}
+
+reset_config trst_only
+
+$_TARGETNAME configure -event reset-assert-post "cortex_a dbginit"
+
+gdb_memory_map disable
diff --git a/tcl/target/adspsc57x_memory_map.xml b/tcl/target/adspsc57x_memory_map.xml
new file mode 100644
index 0000000..5141bf1
--- /dev/null
+++ b/tcl/target/adspsc57x_memory_map.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0"?>
+<!DOCTYPE memory-map SYSTEM "openocd_memory_map.dtd">
+<memory-map>
+ <processor name="adspsc57x">
+ <memory name="ahb_mem" start="0x20000000" length="0xe0000000" access="rw" />
+ </processor>
+</memory-map>
diff --git a/tcl/target/adspsc58x.cfg b/tcl/target/adspsc58x.cfg
new file mode 100644
index 0000000..2788748
--- /dev/null
+++ b/tcl/target/adspsc58x.cfg
@@ -0,0 +1,166 @@
+# Analog Devices ADSP-SC58x
+
+#
+# ADSP-SC58x devices support JTAG and SWD transports.
+#
+transport select jtag
+#transport select swd
+
+source [find target/swj-dp.tcl]
+
+set CPU_MAX_ADDRESS 0xFFFFFFFF
+source [find bitsbytes.tcl]
+source [find memory.tcl]
+source [find mem_helper.tcl]
+source [find target/adspsc5xx.tcl]
+
+# memory map
+
+set MAP_XML [find target/adspsc58x_memory_map.xml]
+set MAP_FILE [open $MAP_XML]
+set _MEMORY_MAP [read $MAP_FILE]
+close $MAP_FILE
+
+global MEMORY_MAP
+# substitute SDRAM_SIZE and FLASH_SIZE
+set MEMORY_MAP [subst $_MEMORY_MAP]
+
+# Uncomment the following 4 lines and change 0x00000000 to
+# userkey if the part is locked
+#set USERKEY0 0x00000000
+#set USERKEY1 0x00000000
+#set USERKEY2 0x00000000
+#set USERKEY3 0x00000000
+
+if { [info exists USERKEY0] } {
+ set _USERKEY0 $USERKEY0
+} else {
+ set _USERKEY0 0x00000000
+}
+
+if { [info exists USERKEY1] } {
+ set _USERKEY1 $USERKEY1
+} else {
+ set _USERKEY1 0x00000000
+}
+
+if { [info exists USERKEY2] } {
+ set _USERKEY2 $USERKEY2
+} else {
+ set _USERKEY2 0x00000000
+}
+
+if { [info exists USERKEY3] } {
+ set _USERKEY3 $USERKEY3
+} else {
+ set _USERKEY3 0x00000000
+}
+
+# target config
+
+if { [info exists CHIPNAME] } {
+ set _CHIPNAME $CHIPNAME
+} else {
+ set _CHIPNAME adspsc58x
+}
+
+# CoreSight Debug Access Port (DAP)
+if { [info exists DAP_TAPID ] } {
+ set _DAP_TAPID $DAP_TAPID
+} else {
+ if { [using_jtag] } {
+ set _DAP_TAPID 0x4ba00477
+ } else {
+ set _DAP_TAPID 0x3ba02477
+ }
+}
+
+if { [using_swd] } {
+ swj_newdap $_CHIPNAME dap -expected-id $_DAP_TAPID
+} else {
+ jtag newtap $_CHIPNAME dap -irlen 4 -expected-id $_DAP_TAPID -disable
+ jtag configure $_CHIPNAME.dap -event tap-enable "adjc_enable_dap $_CHIPNAME.adjc"
+
+ # ADI JTAG Controller
+ if { [info exists ADJC_TAPID ] } {
+ set _ADJC_TAPID $ADJC_TAPID
+ } else {
+ set _ADJC_TAPID 0x028080cb
+ }
+
+ if { [info exists ADJC_TAPID1 ] } {
+ set _ADJC_TAPID1 $ADJC_TAPID1
+ } else {
+ set _ADJC_TAPID1 0x128080cb
+ }
+
+ if { [info exists ADJC_TAPID2 ] } {
+ set _ADJC_TAPID2 $ADJC_TAPID2
+ } else {
+ set _ADJC_TAPID2 0x228080cb
+ }
+
+ jtag newtap $_CHIPNAME adjc -irlen 5 -expected-id $_ADJC_TAPID -expected-id $_ADJC_TAPID1 -expected-id $_ADJC_TAPID2
+
+ # Once the JRC is up, enable our TAPs
+ jtag configure $_CHIPNAME.adjc -event setup "jtag tapenable $_CHIPNAME.dap"
+}
+
+# GDB target: Cortex-A5, using DAP
+set _TARGETNAME $_CHIPNAME.dap
+target create $_TARGETNAME cortex_a -chain-position $_TARGETNAME -dbgbase 0x80020000
+
+cache_config l2x 0x10000000 8
+
+$_TARGETNAME configure -event examine-end {
+ global _CHIPNAME
+
+ # read PADS STAT register and store the value in data
+ set pads_stat 0x31004468
+ set data [pmemread32 $pads_stat]
+ if { "$_CHIPNAME" == "adspsc584" && [expr {$data & 1}] == 0 } {
+ puts stderr "Error: ADSP-SC589 found instead of ADSP-SC584"
+ shutdown error
+ } elseif { "$_CHIPNAME" == "adspsc589" && [expr {$data & 1}] == 1 } {
+ puts stderr "Error: ADSP-SC584 found instead of ADSP-SC589"
+ shutdown error
+ }
+}
+
+# default initialization
+proc adspsc58x_init {} {
+}
+
+# Unless USE_CTI is set to 0, CTI is used to restart the Cortex-A5 core
+# so system peripherals can be restarted at the same time
+
+if { [info exists USE_CTI] } {
+ set _USE_CTI $USE_CTI
+} else {
+ set _USE_CTI 1
+}
+if { $_USE_CTI != 0 } {
+ echo "halt and restart using CTI"
+ $_TARGETNAME configure -restart-cti-reg-addr 0x3110d01c -restart-cti-channel 1
+}
+
+$_TARGETNAME configure -event gdb-attach {
+ # set all bits in TAPC0_DBGCTL to enable all kinds of debug
+ mww phys 0x31131000 0xffff
+
+ if { $_USE_CTI != 0 } {
+ adspsc5xx_configure_cti
+ }
+
+ halt
+
+ adspsc58x_init
+
+ arm semihosting enable
+}
+
+reset_config trst_only
+
+$_TARGETNAME configure -event reset-assert-post "cortex_a dbginit"
+
+gdb_memory_map disable
diff --git a/tcl/target/adspsc58x_memory_map.xml b/tcl/target/adspsc58x_memory_map.xml
new file mode 100644
index 0000000..9937662
--- /dev/null
+++ b/tcl/target/adspsc58x_memory_map.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0"?>
+<!DOCTYPE memory-map SYSTEM "openocd_memory_map.dtd">
+<memory-map>
+ <processor name="adspsc58x">
+ <memory name="ahb_mem" start="0x20000000" length="0xe0000000" access="rw" />
+ </processor>
+</memory-map>
diff --git a/tcl/target/adspsc5xx.tcl b/tcl/target/adspsc5xx.tcl
new file mode 100644
index 0000000..c071755
--- /dev/null
+++ b/tcl/target/adspsc5xx.tcl
@@ -0,0 +1,127 @@
+# Common routines for Analog Devices ADSP-SC57x/SC58x
+
+# Unlock the processor
+proc adjc_unlock {adjc} {
+ global _USERKEY0
+ global _USERKEY1
+ global _USERKEY2
+ global _USERKEY3
+
+ irscan $adjc 0xa -endstate IRPAUSE
+ drscan $adjc 32 $_USERKEY0 32 $_USERKEY1 32 $_USERKEY2 32 $_USERKEY3 -endstate RUN/IDLE
+}
+
+# ADJC is the TAP name for the ADI JTAG Controller
+proc adjc_enable_dap {adjc} {
+ # Unlock the processor before enabling DAP
+ adjc_unlock $adjc
+
+ irscan $adjc 0x5 -endstate IRPAUSE
+ drscan $adjc 8 0x4 -endstate RUN/IDLE
+ runtest 2
+}
+
+# Show RCU_MSG bitfields
+proc show_rcu_msg { name val } {
+ puts "$name [format 0x%08x $val]"
+ show_mmr_bitfield 7 0 $val BOOTERROR { _NUMBER_ }
+ show_mmr_bitfield 8 8 $val C0IDLE { "" "Core 0 is IDLE" }
+ show_mmr_bitfield 9 9 $val C1IDLE { "" "Core 1 is IDLE" }
+ show_mmr_bitfield 10 10 $val C2IDLE { "" "Core 2 is IDLE" }
+ show_mmr_bitfield 12 12 $val C0TASK { "" "Core 0 has finished a task" }
+ show_mmr_bitfield 13 13 $val C1TASK { "" "Core 1 has finished a task" }
+ show_mmr_bitfield 14 14 $val C2TASK { "" "Core 2 has finished a task" }
+ show_mmr_bitfield 16 16 $val C0L1INIT { "" "Core 0 L1 initialized" }
+ show_mmr_bitfield 17 17 $val C1L1INIT { "" "Core 1 L1 initialized" }
+ show_mmr_bitfield 18 18 $val C2L1INIT { "" "Core 2 L1 initialized" }
+ show_mmr_bitfield 22 22 $val L2INIT { "" "L2 initialized" }
+ show_mmr_bitfield 24 24 $val HALTONAPP { "" "Halt on applicaton call" }
+ show_mmr_bitfield 25 25 $val HALTONINIT { "" "Halt on initcode call" }
+ show_mmr_bitfield 26 26 $val HALTONCALL { "" "Halt on callback call" }
+ show_mmr_bitfield 27 27 $val HALTONERR { "" "Halt on error call" }
+ show_mmr_bitfield 28 28 $val CALLAPP { "" "Call application flag" }
+ show_mmr_bitfield 29 29 $val CALLINIT { "" "Call initcode flag" }
+ show_mmr_bitfield 30 30 $val CALLBACK { "" "Call callback flag" }
+ show_mmr_bitfield 31 31 $val CALLERR { "" "Call error flag" }
+}
+
+# Show RCU_STAT bitfields
+proc show_rcu_stat { name val } {
+ puts "$name [format 0x%08x $val]"
+ show_mmr_bitfield 0 0 $val HWRST { "" HWRST }
+ show_mmr_bitfield 2 2 $val SSRST { "" SSRST }
+ show_mmr_bitfield 3 3 $val SWRST { "" SWRST }
+ show_mmr_bitfield 5 5 $val RSTOUT { "" RSTOUT }
+ show_mmr_bitfield 11 8 $val BMODE { _NUMBER_ }
+ show_mmr_bitfield 12 12 $val TESTMODE { "" TESTMODE }
+ show_mmr_bitfield 13 13 $val STESTMODE { "" STESTMODE }
+ show_mmr_bitfield 14 14 $val OTPLOCK { "" OTPLOCK }
+ show_mmr_bitfield 15 15 $val STESTROUTINE { "" STESTROUTINE }
+ show_mmr_bitfield 16 16 $val ADDRERR { "" ADDRERR }
+ show_mmr_bitfield 17 17 $val LWERR { "" LWERR }
+ show_mmr_bitfield 18 18 $val RSTOUTERR { "" RSTOUTERR }
+}
+
+# Show RCU_CRCTL bitfields
+proc show_rcu_crctl { name val } {
+ puts "$name [format 0x%08x $val]"
+ show_mmr_bitfield 0 0 $val CR0 { "" CR0 }
+ show_mmr_bitfield 1 1 $val CR1 { "" CR1 }
+ show_mmr_bitfield 2 2 $val CR2 { "" CR2 }
+ show_mmr_bitfield 3 3 $val CR3 { "" CR3 }
+}
+
+# Show RCU_CRSTAT bitfields
+proc show_rcu_crstat { name val } {
+ puts "$name [format 0x%08x $val]"
+ show_mmr_bitfield 0 0 $val CR0 { "" CR0 }
+ show_mmr_bitfield 1 1 $val CR1 { "" CR1 }
+ show_mmr_bitfield 2 2 $val CR2 { "" CR2 }
+ show_mmr_bitfield 3 3 $val CR3 { "" CR3 }
+}
+
+# Reset some debug registers in SHARC XI core debug component
+proc reset_sharcxi_debug_regs { base_addr } {
+ # Currently we only clear EMUCTL
+
+ set csdbg_emuctl [expr {$base_addr + 0x10}]
+ set csdbg_extdata [expr {$base_addr + 0x18}]
+
+ dap writemem 1 $csdbg_extdata 0
+ dap writemem 1 $csdbg_emuctl 0
+}
+
+# Configure CTIs so Cortex-A5 halt event will halt system peripherals, like watchdog timer
+proc adspsc5xx_configure_cti {} {
+ # Unlock CTI0 (Cortex A5 CTI)
+ # *pREG_CTI0_LAR = 0xC5ACCE55
+ mww phys 0x31128fb0 0xC5ACCE55
+
+ # Unlock CTI3 (System CTI)
+ # *pREG_CTI3_LAR = 0xC5ACCE55
+ mww phys 0x3110dfb0 0xC5ACCE55
+
+ # Enable CTI0 (Cortex A5 CTI)
+ # *pREG_CTI0_CTICONTROL = 1
+ mww phys 0x31128000 0x1
+
+ # Enable CTI3 (System CTI)
+ # *pREG_CTI3_CTICONTROL = 1
+ mww phys 0x3110d000 0x1
+
+ # Connect DBGTRIGGER of Cortex A5 to channel 0
+ # *pREG_CTI0_CTIINEN0 = 1
+ mww phys 0x31128020 0x1
+
+ # Connect peripheral halt to channel 0
+ # *pREG_CTI3_CTIOUTEN1 = 1
+ mww phys 0x3110d0a4 0x1
+
+ # Connect Cortex A5 DBGRESTART to channel 1
+ # *pREG_CTI0_CTIOUTEN7 = 2
+ mww phys 0x311280bc 0x2
+
+ # Connect peripheral DBGRESTART to channel 1
+ # *pREG_CTI3_CTIOUTEN7 = 2
+ mww phys 0x3110d0bc 0x2
+}
diff --git a/tcl/target/aducm3027.cfg b/tcl/target/aducm3027.cfg
new file mode 100644
index 0000000..a58ca3f
--- /dev/null
+++ b/tcl/target/aducm3027.cfg
@@ -0,0 +1,5 @@
+# Analog Devices ADuCM3027
+
+set CHIPNAME aducm3027
+set FLASHSIZE 0x20000
+source [find target/aducm302x.tcl]
diff --git a/tcl/target/aducm3029.cfg b/tcl/target/aducm3029.cfg
new file mode 100644
index 0000000..80252f5
--- /dev/null
+++ b/tcl/target/aducm3029.cfg
@@ -0,0 +1,5 @@
+# Analog Devices ADuCM3029
+
+set CHIPNAME aducm3029
+set FLASHSIZE 0x40000
+source [find target/aducm302x.tcl]
diff --git a/tcl/target/aducm302x.tcl b/tcl/target/aducm302x.tcl
new file mode 100644
index 0000000..b457a5a
--- /dev/null
+++ b/tcl/target/aducm302x.tcl
@@ -0,0 +1,90 @@
+# Common file for Analog Devices ADuCM302x
+
+# minimal dap memaccess values for adapter frequencies
+# 1 MHz: 6
+# 2 MHz: 8
+# 5 MHz: 18
+# 9 MHz: 27
+# 15 MHz: 43
+# 23 MHz: 74
+
+# hardware has 2 breakpoints, 1 watchpoints
+
+#
+# ADuCM302x devices support only SWD transport.
+#
+transport select swd
+
+source [find target/swj-dp.tcl]
+
+if { [info exists CHIPNAME] } {
+ set _CHIPNAME $CHIPNAME
+} else {
+ set _CHIPNAME aducm302x
+}
+
+if { [info exists ENDIAN] } {
+ set _ENDIAN $ENDIAN
+} else {
+ set _ENDIAN little
+}
+
+adapter_khz 1000
+
+if { [info exists CPUTAPID] } {
+ set _CPUTAPID $CPUTAPID
+} else {
+ set _CPUTAPID 0x2ba01477
+}
+
+swj_newdap $_CHIPNAME cpu -expected-id $_CPUTAPID
+
+set _TARGETNAME $_CHIPNAME.cpu
+target create $_TARGETNAME cortex_m -endian $_ENDIAN -chain-position $_TARGETNAME
+
+if { [info exists WORKAREASIZE] } {
+ set _WORKAREASIZE $WORKAREASIZE
+} else {
+ # default to 8K working area
+ set _WORKAREASIZE 0x2000
+}
+
+$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE
+
+$_TARGETNAME configure -event reset-init {
+ # disable watchdog, which will fire in about 32 second after reset.
+ mwh 0x40002c08 0x0
+ # After reset LR is 0xffffffff. There will be an error when GDB tries to
+ # read from that address.
+ reg lr 0
+}
+
+$_TARGETNAME configure -event gdb-attach {
+ reset init
+
+ arm semihosting enable
+}
+
+$_TARGETNAME configure -event gdb-flash-erase-start {
+ reset init
+ mww 0x40018054 0x1
+}
+
+$_TARGETNAME configure -event gdb-flash-write-end {
+ reset init
+ mww 0x40018054 0x1
+}
+
+set _FLASHNAME $_CHIPNAME.flash
+if { [info exists FLASHSIZE] } {
+ set _FLASHSIZE $FLASHSIZE
+} else {
+ set _FLASHSIZE 0x40000
+}
+flash bank $_FLASHNAME aducm302x 0 $_FLASHSIZE 0 0 $_TARGETNAME
+
+if {![using_hla]} {
+ # if srst is not fitted use SYSRESETREQ to
+ # perform a soft reset
+ cortex_m reset_config sysresetreq
+}
diff --git a/tcl/target/aducm350.cfg b/tcl/target/aducm350.cfg
new file mode 100644
index 0000000..142e7f7
--- /dev/null
+++ b/tcl/target/aducm350.cfg
@@ -0,0 +1,44 @@
+# script for ADUCM350
+
+#
+# ADUCM350 devices support both JTAG and SWD transports.
+#
+source [find target/swj-dp.tcl]
+
+# use SWD by default
+transport select swd
+
+if { [info exists CHIPNAME] } {
+ set _CHIPNAME $CHIPNAME
+} else {
+ set _CHIPNAME aducm350
+}
+
+if { [info exists ENDIAN] } {
+ set _ENDIAN $ENDIAN
+} else {
+ set _ENDIAN little
+}
+
+adapter_khz 1000
+
+if { [info exists CPUTAPID] } {
+ set _CPUTAPID $CPUTAPID
+} else {
+ if { [using_jtag] } {
+ # See STM Document RM0038
+ # Section 24.6.3
+ set _CPUTAPID 0x4ba00477
+ } {
+ set _CPUTAPID 0x2ba01477
+ }
+}
+
+swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID
+
+set _TARGETNAME $_CHIPNAME.cpu
+target create $_TARGETNAME cortex_m -endian $_ENDIAN -chain-position $_TARGETNAME
+
+$_TARGETNAME configure -event gdb-attach {
+ halt
+}
diff --git a/tcl/target/bf533.cfg b/tcl/target/bf533.cfg
new file mode 100644
index 0000000..7559e0d
--- /dev/null
+++ b/tcl/target/bf533.cfg
@@ -0,0 +1,6 @@
+set CHIPNAME bf533
+set CPUTAPID 0x027a50cb
+
+source [find cpu/blackfin/blackfin.cfg]
+
+# $_TARGETNAME configure -work-area-phys 0xffa00000 -work-area-size 0x4000 -work-area-backup 0
diff --git a/tcl/target/bf537.cfg b/tcl/target/bf537.cfg
new file mode 100644
index 0000000..57c25c5
--- /dev/null
+++ b/tcl/target/bf537.cfg
@@ -0,0 +1,34 @@
+set CHIPNAME bf537
+set CPUTAPID 0x027c80cb
+
+if {![info exists SDRAM_SIZE]} {
+ set SDRAM_SIZE 0x20000000
+}
+if {![info exists FLASH_SIZE]} {
+ set FLASH_SIZE 0x100000
+}
+
+# memory map
+
+set MAP_XML [find target/bf537_memory_map.xml]
+set MAP_FILE [open $MAP_XML]
+set _MEMORY_MAP [read $MAP_FILE]
+close $MAP_FILE
+
+global MEMORY_MAP
+# substitute SDRAM_SIZE and FLASH_SIZE
+set MEMORY_MAP [subst $_MEMORY_MAP]
+
+# target config
+
+set BLACKFIN_CONFIG_XML [find target/bf537_config.xml]
+set BLACKFIN_CONFIG_FILE [open $BLACKFIN_CONFIG_XML]
+set _BLACKFIN_CONFIG [read $BLACKFIN_CONFIG_FILE]
+close $BLACKFIN_CONFIG_FILE
+
+global BLACKFIN_CONFIG
+set BLACKFIN_CONFIG $_BLACKFIN_CONFIG
+
+source [find cpu/blackfin/blackfin.cfg]
+
+# $_TARGETNAME configure -work-area-phys 0xffa00000 -work-area-size 0x4000 -work-area-backup 0
diff --git a/tcl/target/bf537_config.xml b/tcl/target/bf537_config.xml
new file mode 100644
index 0000000..01e93a7
--- /dev/null
+++ b/tcl/target/bf537_config.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0"?>
+<!DOCTYPE blackfin-config SYSTEM "openocd_blackfin_config.dtd">
+<blackfin-config>
+ <processor name="bf537">
+ <config name="mdma_d0" value="0xffc00f00" />
+ <config name="mdma_s0" value="0xffc00f40" />
+ </processor>
+</blackfin-config>
diff --git a/tcl/target/bf537_memory_map.xml b/tcl/target/bf537_memory_map.xml
new file mode 100644
index 0000000..459c8cb
--- /dev/null
+++ b/tcl/target/bf537_memory_map.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0"?>
+<!DOCTYPE memory-map SYSTEM "openocd_memory_map.dtd">
+<memory-map>
+ <processor name="bf537">
+ <memory name="sdram" start="0x00000000" length="$SDRAM_SIZE" access="rw" />
+ <memory name="flash" start="0x20000000" length="$FLASH_SIZE" access="flash" />
+ <memory name="async_mem" start="0x20000000" length="0x400000" access="rw" />
+ <memory name="boot_rom" start="0xef000000" length="0x800" access="ro" />
+ <memory name="l1" start="0xff800000" length="0x400000" />
+ <core start="0xff800000" length="0x400000">
+ <memory name="l1" start="0xff800000" length="0x400000" />
+ <memory name="l1_data_a" start="0xff800000" length="0x4000" access="rw">
+ <property name="bank">"a"</property>
+ </memory>
+ <memory name="l1_data_a_cache" start="0xff804000" length="0x4000" access="dcache">
+ <property name="bank">"a"</property>
+ </memory>
+ <memory name="l1_data_b" start="0xff900000" length="0x4000" access="rw">
+ <property name="bank">"b"</property>
+ </memory>
+ <memory name="l1_data_b_cache" start="0xff904000" length="0x4000" access="dcache">
+ <property name="bank">"b"</property>
+ </memory>
+ <memory name="l1_code" start="0xffa00000" length="0x10000" access="itest" />
+ <memory name="l1_code_cache" start="0xffa10000" length="0x4000" access="icache" />
+ <memory name="l1_scratch" start="0xffb00000" length="0x1000" access="rw" />
+ </core>
+ <memory name="sysmmr" start="0xffc00000" length="0x200000" access="mmr" />
+ <memory name="coremmr" start="0xffe00000" length="0x200000" access="mmr" />
+ </processor>
+</memory-map>
diff --git a/tcl/target/bf561.cfg b/tcl/target/bf561.cfg
new file mode 100644
index 0000000..004998c
--- /dev/null
+++ b/tcl/target/bf561.cfg
@@ -0,0 +1,56 @@
+set CHIPNAME bf561
+set CPUTAPID 0x027bb0cb
+
+if {![info exists SDRAM_SIZE]} {
+ set SDRAM_SIZE 0x20000000
+}
+if {![info exists FLASH_SIZE]} {
+ set FLASH_SIZE 0x4000000
+}
+
+set MAP_XML [find target/bf561_memory_map.xml]
+set MAP_FILE [open $MAP_XML]
+set _MEMORY_MAP [read $MAP_FILE]
+close $MAP_FILE
+
+# Substitute SDRAM_SIZE and FLASH_SIZE
+global MEMORY_MAP
+set MEMORY_MAP [subst $_MEMORY_MAP]
+
+# target config
+
+set BLACKFIN_CONFIG_XML [find target/bf561_config.xml]
+set BLACKFIN_CONFIG_FILE [open $BLACKFIN_CONFIG_XML]
+set _BLACKFIN_CONFIG [read $BLACKFIN_CONFIG_FILE]
+close $BLACKFIN_CONFIG_FILE
+
+global BLACKFIN_CONFIG
+set BLACKFIN_CONFIG $_BLACKFIN_CONFIG
+
+# Maybe we should put the following into cpu/blackfin/bf561.cfg
+set _CHIPNAME $CHIPNAME
+set _CPUTAPID $CPUTAPID
+
+# TAP for Core B
+jtag newtap $_CHIPNAME b -irlen 5 -expected-id $_CPUTAPID -ignore-version
+
+# TAP for Core A
+jtag newtap $_CHIPNAME a -irlen 5 -expected-id $_CPUTAPID -ignore-version
+
+# Create target fore Core B
+set _TARGETNAME_B $_CHIPNAME.b
+target create $_TARGETNAME_B blackfin -chain-position $_TARGETNAME_B
+
+# Create target fore Core A
+set _TARGETNAME_A $_CHIPNAME.a
+target create $_TARGETNAME_A blackfin -chain-position $_TARGETNAME_A
+
+adapter_nsrst_delay 100
+jtag_ntrst_delay 100
+
+reset_config trst_only
+
+# FIXME
+gdb_memory_map disable
+
+# $_TARGETNAME configure -work-area-phys 0xffa00000 -work-area-size 0x4000 -work-area-backup 0
diff --git a/tcl/target/bf561_config.xml b/tcl/target/bf561_config.xml
new file mode 100644
index 0000000..29ed92b
--- /dev/null
+++ b/tcl/target/bf561_config.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0"?>
+<!DOCTYPE blackfin-config SYSTEM "openocd_blackfin_config.dtd">
+<blackfin-config>
+ <processor name="bf561">
+ <config name="mdma_d0" value="0xffc01800" />
+ <config name="mdma_s0" value="0xffc01840" />
+ </processor>
+</blackfin-config>
diff --git a/tcl/target/bf561_memory_map.xml b/tcl/target/bf561_memory_map.xml
new file mode 100644
index 0000000..f0e7060
--- /dev/null
+++ b/tcl/target/bf561_memory_map.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0"?>
+<!DOCTYPE memory-map SYSTEM "openocd_memory_map.dtd">
+<memory-map>
+ <processor name="bf561">
+ <memory name="sdram" start="0x00000000" length="0x20000000" access="rw" />
+ <memory name="flash" start="0x20000000" length="0x4000000" access="flash" />
+ <memory name="async_mem" start="0x20000000" length="0x10000000" access="rw" />
+ <memory name="boot_rom" start="0xef000000" length="0x800" access="ro" />
+ <memory name="l2_sram" start="0xfeb00000" length="0x20000" access="rw" />
+ <memory name="l1" start="0xff400000" length="0x800000" />
+ <core name="b" start="0xff400000" length="0x400000">
+ <memory name="l1" start="0xff400000" length="0x400000" />
+ <memory name="l1_data_a" start="0xff400000" length="0x4000" access="rw">
+ <property name="bank">"a"</property>
+ </memory>
+ <memory name="l1_data_a_cache" start="0xff404000" length="0x4000" access="dcache">
+ <property name="bank">"a"</property>
+ </memory>
+ <memory name="l1_data_b" start="0xff500000" length="0x4000" access="rw">
+ <property name="bank">"b"</property>
+ </memory>
+ <memory name="l1_data_b_cache" start="0xff504000" length="0x4000" access="dcache">
+ <property name="bank">"b"</property>
+ </memory>
+ <memory name="l1_code" start="0xff600000" length="0x4000" access="itest" />
+ <memory name="l1_code_cache" start="0xff610000" length="0x4000" access="icache" />
+ <memory name="l1_scratch" start="0xff700000" length="0x1000" access="rw" />
+ </core>
+ <core name="a" start="0xff800000" length="0x400000">
+ <memory name="l1" start="0xff800000" length="0x400000" />
+ <memory name="l1_data_a" start="0xff800000" length="0x4000" access="rw">
+ <property name="bank">"a"</property>
+ </memory>
+ <memory name="l1_data_a_cache" start="0xff804000" length="0x4000" access="dcache">
+ <property name="bank">"a"</property>
+ </memory>
+ <memory name="l1_data_b" start="0xff900000" length="0x4000" access="rw">
+ <property name="bank">"b"</property>
+ </memory>
+ <memory name="l1_data_b_cache" start="0xff904000" length="0x4000" access="dcache">
+ <property name="bank">"b"</property>
+ </memory>
+ <memory name="l1_code" start="0xffa00000" length="0x4000" access="itest" />
+ <memory name="l1_code_cache" start="0xffa10000" length="0x4000" access="icache" />
+ <memory name="l1_scratch" start="0xffb00000" length="0x1000" access="rw" />
+ </core>
+ <memory name="sysmmr" start="0xffc00000" length="0x200000" access="mmr" />
+ <memory name="coremmr" start="0xffe00000" length="0x200000" access="mmr" />
+ </processor>
+</memory-map>
diff --git a/tcl/target/omap3530.cfg b/tcl/target/omap3530.cfg
index f9dcf7c..9823072 100644
--- a/tcl/target/omap3530.cfg
+++ b/tcl/target/omap3530.cfg
@@ -39,7 +39,12 @@ set _TARGETNAME $_CHIPNAME.cpu
target create $_TARGETNAME cortex_a -chain-position $_CHIPNAME.dap
# SRAM: 64K at 0x4020.0000; use the first 16K
-$_TARGETNAME configure -work-area-phys 0x40200000 -work-area-size 0x4000
+# $_TARGETNAME configure -work-area-phys 0x40200000 -work-area-size 0x4000
+
+$_TARGETNAME configure -event gdb-attach {
+ reset init
+ arm semihosting enable stack_base=0x40210000
+}
###################
diff --git a/tcl/target/panther.cfg b/tcl/target/panther.cfg
new file mode 100644
index 0000000..ce99618
--- /dev/null
+++ b/tcl/target/panther.cfg
@@ -0,0 +1,51 @@
+if { [info exists CHIPNAME] } {
+ set _CHIPNAME $CHIPNAME
+} else {
+ set _CHIPNAME panther
+}
+
+source [find target/adi-jtag-controller.cfg]
+
+# CoreSight Debug Access Port (DAP)
+if { [info exists DAP_TAPID ] } {
+ set _DAP_TAPID $DAP_TAPID
+} else {
+ set _DAP_TAPID 0x4ba00477
+}
+
+jtag newtap $_CHIPNAME dap -irlen 4 -expected-id $_DAP_TAPID -disable
+jtag configure $_CHIPNAME.dap -event tap-enable "adjc_enable_dap $_CHIPNAME.adjc"
+
+# ADI JTAG Controller
+if { [info exists ADJC_TAPID ] } {
+ set _ADJC_TAPID $ADJC_TAPID
+} else {
+ set _ADJC_TAPID 0x028060cb
+}
+
+jtag newtap $_CHIPNAME adjc -irlen 5 -expected-id $_ADJC_TAPID
+
+
+# GDB target: Cortex-A5, using DAP
+set _TARGETNAME $_CHIPNAME.cpu
+# target create $_TARGETNAME cortex_a8 -chain-position $_CHIPNAME.dap -dbgbase 0x80110000
+target create $_TARGETNAME cortex_a8 -chain-position $_CHIPNAME.dap
+
+$_TARGETNAME configure -event gdb-attach {
+ reset init
+}
+
+# Once the JRC is up, enable our TAPs
+jtag configure $_CHIPNAME.adjc -event setup "
+ jtag tapenable $_CHIPNAME.dap
+"
+
+reset_config trst_only
+
+jtag_rclk 1000
+$_TARGETNAME configure -event "reset-start" { jtag_rclk 1000 }
+
+$_TARGETNAME configure -event reset-assert ""
+$_TARGETNAME configure -event reset-assert-post "cortex_a8 dbginit"
+
+gdb_memory_map disable
diff --git a/tcl/target/slater.cfg b/tcl/target/slater.cfg
new file mode 100644
index 0000000..09474f9
--- /dev/null
+++ b/tcl/target/slater.cfg
@@ -0,0 +1,46 @@
+if { [info exists CHIPNAME] } {
+ set _CHIPNAME $CHIPNAME
+} else {
+ set _CHIPNAME slater
+}
+
+source [find target/adi-jtag-controller.cfg]
+
+# CoreSight Debug Access Port (DAP)
+if { [info exists DAP_TAPID ] } {
+ set _DAP_TAPID $DAP_TAPID
+} else {
+ set _DAP_TAPID 0x4ba00477
+}
+
+jtag newtap $_CHIPNAME dap -irlen 4 -expected-id $_DAP_TAPID -disable
+jtag configure $_CHIPNAME.dap -event tap-enable "adjc_enable_dap $_CHIPNAME.adjc"
+
+# ADI JTAG Controller
+if { [info exists ADJC_TAPID ] } {
+ set _ADJC_TAPID $ADJC_TAPID
+} else {
+ set _ADJC_TAPID 0x028050cb
+}
+
+jtag newtap $_CHIPNAME adjc -irlen 5 -expected-id $_ADJC_TAPID
+
+
+set _TARGETNAME $_CHIPNAME.cpu
+target create $_TARGETNAME cortex_m3 -chain-position $_CHIPNAME.dap
+
+$_TARGETNAME configure -event gdb-attach { halt }
+
+# Once the JRC is up, enable our TAPs
+jtag configure $_CHIPNAME.adjc -event setup "
+ jtag tapenable $_CHIPNAME.dap
+"
+
+reset_config trst_only
+
+jtag_rclk 1000
+$_TARGETNAME configure -event "reset-start" { jtag_rclk 1000 }
+
+$_TARGETNAME configure -event reset-assert ""
+
+gdb_memory_map disable
--