debuggers: import openocd-0.7.0

Initial check-in of openocd-0.7.0 as it can be downloaded from
http://sourceforge.net/projects/openocd/files/openocd/0.7.0/

Any modifications will follow.

Change-Id: I6949beaefd589e046395ea0cb80f4e1ab1654d55
This commit is contained in:
Lars Rademacher
2013-10-21 00:50:02 +02:00
parent 85fffe007e
commit 83d72a091e
1148 changed files with 571445 additions and 0 deletions

View File

@ -0,0 +1,170 @@
include $(top_srcdir)/common.mk
if OOCD_TRACE
OOCD_TRACE_FILES = oocd_trace.c
else
OOCD_TRACE_FILES =
endif
BIN2C = $(top_builddir)/src/helper/bin2char$(EXEEXT_FOR_BUILD)
DEBUG_HANDLER = $(srcdir)/xscale/debug_handler.bin
EXTRA_DIST = \
startup.tcl \
$(DEBUG_HANDLER)
DEBUG_HEADER = xscale_debug.h
BUILT_SOURCES = $(DEBUG_HEADER)
CLEANFILES = $(DEBUG_HEADER)
$(DEBUG_HEADER): $(BIN2C) $(DEBUG_HANDLER)
$(BIN2C) < $(DEBUG_HANDLER) xscale_debug_handler > xscale_debug.h
METASOURCES = AUTO
noinst_LTLIBRARIES = libtarget.la
libtarget_la_SOURCES = \
$(TARGET_CORE_SRC) \
$(ARM_DEBUG_SRC) \
$(ARMV4_5_SRC) \
$(ARMV6_SRC) \
$(ARMV7_SRC) \
$(ARM_MISC_SRC) \
$(AVR32_SRC) \
$(MIPS32_SRC) \
avrt.c \
dsp563xx.c \
dsp563xx_once.c \
dsp5680xx.c \
hla_target.c
TARGET_CORE_SRC = \
algorithm.c \
register.c \
image.c \
breakpoints.c \
target.c \
target_request.c \
testee.c \
smp.c
ARMV4_5_SRC = \
armv4_5.c \
armv4_5_mmu.c \
armv4_5_cache.c \
$(ARM7_9_SRC)
ARM7_9_SRC = \
arm7_9_common.c \
arm7tdmi.c \
arm720t.c \
arm9tdmi.c \
arm920t.c \
arm966e.c \
arm946e.c \
arm926ejs.c \
feroceon.c
ARM_MISC_SRC = \
fa526.c \
xscale.c
ARMV6_SRC = \
arm11.c \
arm11_dbgtap.c
ARMV7_SRC = \
armv7m.c \
cortex_m.c \
armv7a.c \
cortex_a.c
ARM_DEBUG_SRC = \
arm_dpm.c \
arm_jtag.c \
arm_disassembler.c \
arm_simulator.c \
arm_semihosting.c \
arm_adi_v5.c \
adi_v5_jtag.c \
adi_v5_swd.c \
embeddedice.c \
trace.c \
etb.c \
etm.c \
$(OOCD_TRACE_FILES) \
etm_dummy.c
AVR32_SRC = \
avr32_ap7k.c \
avr32_jtag.c \
avr32_mem.c \
avr32_regs.c
MIPS32_SRC = \
mips32.c \
mips_m4k.c \
mips32_pracc.c \
mips32_dmaacc.c \
mips_ejtag.c
noinst_HEADERS = \
algorithm.h \
arm.h \
arm_dpm.h \
arm_jtag.h \
arm_adi_v5.h \
arm_disassembler.h \
arm_opcodes.h \
arm_simulator.h \
arm_semihosting.h \
arm7_9_common.h \
arm7tdmi.h \
arm720t.h \
arm9tdmi.h \
arm920t.h \
arm926ejs.h \
arm966e.h \
arm946e.h \
arm11.h \
arm11_dbgtap.h \
armv4_5.h \
armv4_5_mmu.h \
armv4_5_cache.h \
armv7a.h \
armv7m.h \
avrt.h \
dsp563xx.h \
dsp563xx_once.h \
dsp5680xx.h \
breakpoints.h \
cortex_m.h \
cortex_a.h \
embeddedice.h \
etb.h \
etm.h \
etm_dummy.h \
image.h \
mips32.h \
mips_m4k.h \
mips_ejtag.h \
mips32_pracc.h \
mips32_dmaacc.h \
oocd_trace.h \
register.h \
target.h \
target_type.h \
trace.h \
target_request.h \
trace.h \
xscale.h \
smp.h \
avr32_ap7k.h \
avr32_jtag.h \
avr32_mem.h \
avr32_regs.h
ocddatadir = $(pkglibdir)
nobase_dist_ocddata_DATA =
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in

View File

@ -0,0 +1,868 @@
# Makefile.in generated by automake 1.13.1 from Makefile.am.
# @configure_input@
# Copyright (C) 1994-2012 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
@SET_MAKE@
VPATH = @srcdir@
am__make_dryrun = \
{ \
am__dry=no; \
case $$MAKEFLAGS in \
*\\[\ \ ]*) \
echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \
| grep '^AM OK$$' >/dev/null || am__dry=yes;; \
*) \
for am__flg in $$MAKEFLAGS; do \
case $$am__flg in \
*=*|--*) ;; \
*n*) am__dry=yes; break;; \
esac; \
done;; \
esac; \
test $$am__dry = yes; \
}
pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkglibexecdir = $(libexecdir)/@PACKAGE@
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
install_sh_DATA = $(install_sh) -c -m 644
install_sh_PROGRAM = $(install_sh) -c
install_sh_SCRIPT = $(install_sh) -c
INSTALL_HEADER = $(INSTALL_DATA)
transform = $(program_transform_name)
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
DIST_COMMON = $(top_srcdir)/common.mk $(srcdir)/Makefile.in \
$(srcdir)/Makefile.am $(top_srcdir)/depcomp \
$(nobase_dist_ocddata_DATA) $(noinst_HEADERS)
@INTERNAL_JIMTCL_TRUE@am__append_1 = -I$(top_srcdir)/jimtcl \
@INTERNAL_JIMTCL_TRUE@ -I$(top_builddir)/jimtcl
subdir = src/target
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/config_subdir.m4 \
$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = $(top_builddir)/config.h
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
LTLIBRARIES = $(noinst_LTLIBRARIES)
libtarget_la_LIBADD =
am__libtarget_la_SOURCES_DIST = algorithm.c register.c image.c \
breakpoints.c target.c target_request.c testee.c smp.c \
arm_dpm.c arm_jtag.c arm_disassembler.c arm_simulator.c \
arm_semihosting.c arm_adi_v5.c adi_v5_jtag.c adi_v5_swd.c \
embeddedice.c trace.c etb.c etm.c oocd_trace.c etm_dummy.c \
armv4_5.c armv4_5_mmu.c armv4_5_cache.c arm7_9_common.c \
arm7tdmi.c arm720t.c arm9tdmi.c arm920t.c arm966e.c arm946e.c \
arm926ejs.c feroceon.c arm11.c arm11_dbgtap.c armv7m.c \
cortex_m.c armv7a.c cortex_a.c fa526.c xscale.c avr32_ap7k.c \
avr32_jtag.c avr32_mem.c avr32_regs.c mips32.c mips_m4k.c \
mips32_pracc.c mips32_dmaacc.c mips_ejtag.c avrt.c dsp563xx.c \
dsp563xx_once.c dsp5680xx.c hla_target.c
am__objects_1 = algorithm.lo register.lo image.lo breakpoints.lo \
target.lo target_request.lo testee.lo smp.lo
@OOCD_TRACE_TRUE@am__objects_2 = oocd_trace.lo
am__objects_3 = arm_dpm.lo arm_jtag.lo arm_disassembler.lo \
arm_simulator.lo arm_semihosting.lo arm_adi_v5.lo \
adi_v5_jtag.lo adi_v5_swd.lo embeddedice.lo trace.lo etb.lo \
etm.lo $(am__objects_2) etm_dummy.lo
am__objects_4 = arm7_9_common.lo arm7tdmi.lo arm720t.lo arm9tdmi.lo \
arm920t.lo arm966e.lo arm946e.lo arm926ejs.lo feroceon.lo
am__objects_5 = armv4_5.lo armv4_5_mmu.lo armv4_5_cache.lo \
$(am__objects_4)
am__objects_6 = arm11.lo arm11_dbgtap.lo
am__objects_7 = armv7m.lo cortex_m.lo armv7a.lo cortex_a.lo
am__objects_8 = fa526.lo xscale.lo
am__objects_9 = avr32_ap7k.lo avr32_jtag.lo avr32_mem.lo avr32_regs.lo
am__objects_10 = mips32.lo mips_m4k.lo mips32_pracc.lo \
mips32_dmaacc.lo mips_ejtag.lo
am_libtarget_la_OBJECTS = $(am__objects_1) $(am__objects_3) \
$(am__objects_5) $(am__objects_6) $(am__objects_7) \
$(am__objects_8) $(am__objects_9) $(am__objects_10) avrt.lo \
dsp563xx.lo dsp563xx_once.lo dsp5680xx.lo hla_target.lo
libtarget_la_OBJECTS = $(am_libtarget_la_OBJECTS)
AM_V_lt = $(am__v_lt_@AM_V@)
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
am__v_lt_0 = --silent
am__v_lt_1 =
AM_V_P = $(am__v_P_@AM_V@)
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
am__v_P_0 = false
am__v_P_1 = :
AM_V_GEN = $(am__v_GEN_@AM_V@)
am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
am__v_GEN_0 = @echo " GEN " $@;
am__v_GEN_1 =
AM_V_at = $(am__v_at_@AM_V@)
am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
am__v_at_0 = @
am__v_at_1 =
DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__depfiles_maybe = depfiles
am__mv = mv -f
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
$(AM_CFLAGS) $(CFLAGS)
AM_V_CC = $(am__v_CC_@AM_V@)
am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
am__v_CC_0 = @echo " CC " $@;
am__v_CC_1 =
CCLD = $(CC)
LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
$(AM_LDFLAGS) $(LDFLAGS) -o $@
AM_V_CCLD = $(am__v_CCLD_@AM_V@)
am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
am__v_CCLD_0 = @echo " CCLD " $@;
am__v_CCLD_1 =
SOURCES = $(libtarget_la_SOURCES)
DIST_SOURCES = $(am__libtarget_la_SOURCES_DIST)
am__can_run_installinfo = \
case $$AM_UPDATE_INFO_DIR in \
n|no|NO) false;; \
*) (install-info --version) >/dev/null 2>&1;; \
esac
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
am__vpath_adj = case $$p in \
$(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
*) f=$$p;; \
esac;
am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
am__install_max = 40
am__nobase_strip_setup = \
srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
am__nobase_strip = \
for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
am__nobase_list = $(am__nobase_strip_setup); \
for p in $$list; do echo "$$p $$p"; done | \
sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
$(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
if (++n[$$2] == $(am__install_max)) \
{ print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
END { for (dir in files) print dir, files[dir] }'
am__base_list = \
sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
am__uninstall_files_from_dir = { \
test -z "$$files" \
|| { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
|| { echo " ( cd '$$dir' && rm -f" $$files ")"; \
$(am__cd) "$$dir" && rm -f $$files; }; \
}
am__installdirs = "$(DESTDIR)$(ocddatadir)"
DATA = $(nobase_dist_ocddata_DATA)
HEADERS = $(noinst_HEADERS)
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
# Read a list of newline-separated strings from the standard input,
# and print each of them once, without duplicates. Input order is
# *not* preserved.
am__uniquify_input = $(AWK) '\
BEGIN { nonempty = 0; } \
{ items[$$0] = 1; nonempty = 1; } \
END { if (nonempty) { for (i in items) print i; }; } \
'
# Make sure the list of sources is unique. This is necessary because,
# e.g., the same source file might be shared among _SOURCES variables
# for different programs/libraries.
am__define_uniq_tagged_files = \
list='$(am__tagged_files)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | $(am__uniquify_input)`
ETAGS = etags
CTAGS = ctags
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
AMTAR = @AMTAR@
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
AR = @AR@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CC_FOR_BUILD = @CC_FOR_BUILD@
CFLAGS = @CFLAGS@
CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
CYGPATH_W = @CYGPATH_W@
DEFS = @DEFS@
DEPDIR = @DEPDIR@
DLLTOOL = @DLLTOOL@
DSYMUTIL = @DSYMUTIL@
DUMPBIN = @DUMPBIN@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
EXEEXT = @EXEEXT@
EXEEXT_FOR_BUILD = @EXEEXT_FOR_BUILD@
FGREP = @FGREP@
GREP = @GREP@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
LD = @LD@
LDFLAGS = @LDFLAGS@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LIBTOOL = @LIBTOOL@
LIBTOOL_DEPS = @LIBTOOL_DEPS@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
MAINT = @MAINT@
MAKEINFO = @MAKEINFO@
MANIFEST_TOOL = @MANIFEST_TOOL@
MKDIR_P = @MKDIR_P@
NM = @NM@
NMEDIT = @NMEDIT@
OBJDUMP = @OBJDUMP@
OBJEXT = @OBJEXT@
OTOOL = @OTOOL@
OTOOL64 = @OTOOL64@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
PACKAGE_NAME = @PACKAGE_NAME@
PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
RANLIB = @RANLIB@
SED = @SED@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
STRIP = @STRIP@
VERSION = @VERSION@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
abs_top_srcdir = @abs_top_srcdir@
ac_ct_AR = @ac_ct_AR@
ac_ct_CC = @ac_ct_CC@
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
am__tar = @am__tar@
am__untar = @am__untar@
bindir = @bindir@
build = @build@
build_alias = @build_alias@
build_cpu = @build_cpu@
build_os = @build_os@
build_vendor = @build_vendor@
builddir = @builddir@
datadir = @datadir@
datarootdir = @datarootdir@
docdir = @docdir@
doxygen_as_html = @doxygen_as_html@
doxygen_as_pdf = @doxygen_as_pdf@
dvidir = @dvidir@
exec_prefix = @exec_prefix@
host = @host@
host_alias = @host_alias@
host_cpu = @host_cpu@
host_os = @host_os@
host_vendor = @host_vendor@
htmldir = @htmldir@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
libdir = @libdir@
libexecdir = @libexecdir@
localedir = @localedir@
localstatedir = @localstatedir@
mandir = @mandir@
mkdir_p = @mkdir_p@
oldincludedir = @oldincludedir@
pdfdir = @pdfdir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
subdirs = @subdirs@
sysconfdir = @sysconfdir@
target_alias = @target_alias@
top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
# common flags used in openocd build
AM_CPPFLAGS = -I$(top_srcdir)/src -I$(top_builddir)/src \
-I$(top_srcdir)/src/helper -DPKGDATADIR=\"$(pkgdatadir)\" \
-DPKGLIBDIR=\"$(pkglibdir)\" $(am__append_1)
@OOCD_TRACE_FALSE@OOCD_TRACE_FILES =
@OOCD_TRACE_TRUE@OOCD_TRACE_FILES = oocd_trace.c
BIN2C = $(top_builddir)/src/helper/bin2char$(EXEEXT_FOR_BUILD)
DEBUG_HANDLER = $(srcdir)/xscale/debug_handler.bin
EXTRA_DIST = \
startup.tcl \
$(DEBUG_HANDLER)
DEBUG_HEADER = xscale_debug.h
BUILT_SOURCES = $(DEBUG_HEADER)
CLEANFILES = $(DEBUG_HEADER)
METASOURCES = AUTO
noinst_LTLIBRARIES = libtarget.la
libtarget_la_SOURCES = \
$(TARGET_CORE_SRC) \
$(ARM_DEBUG_SRC) \
$(ARMV4_5_SRC) \
$(ARMV6_SRC) \
$(ARMV7_SRC) \
$(ARM_MISC_SRC) \
$(AVR32_SRC) \
$(MIPS32_SRC) \
avrt.c \
dsp563xx.c \
dsp563xx_once.c \
dsp5680xx.c \
hla_target.c
TARGET_CORE_SRC = \
algorithm.c \
register.c \
image.c \
breakpoints.c \
target.c \
target_request.c \
testee.c \
smp.c
ARMV4_5_SRC = \
armv4_5.c \
armv4_5_mmu.c \
armv4_5_cache.c \
$(ARM7_9_SRC)
ARM7_9_SRC = \
arm7_9_common.c \
arm7tdmi.c \
arm720t.c \
arm9tdmi.c \
arm920t.c \
arm966e.c \
arm946e.c \
arm926ejs.c \
feroceon.c
ARM_MISC_SRC = \
fa526.c \
xscale.c
ARMV6_SRC = \
arm11.c \
arm11_dbgtap.c
ARMV7_SRC = \
armv7m.c \
cortex_m.c \
armv7a.c \
cortex_a.c
ARM_DEBUG_SRC = \
arm_dpm.c \
arm_jtag.c \
arm_disassembler.c \
arm_simulator.c \
arm_semihosting.c \
arm_adi_v5.c \
adi_v5_jtag.c \
adi_v5_swd.c \
embeddedice.c \
trace.c \
etb.c \
etm.c \
$(OOCD_TRACE_FILES) \
etm_dummy.c
AVR32_SRC = \
avr32_ap7k.c \
avr32_jtag.c \
avr32_mem.c \
avr32_regs.c
MIPS32_SRC = \
mips32.c \
mips_m4k.c \
mips32_pracc.c \
mips32_dmaacc.c \
mips_ejtag.c
noinst_HEADERS = \
algorithm.h \
arm.h \
arm_dpm.h \
arm_jtag.h \
arm_adi_v5.h \
arm_disassembler.h \
arm_opcodes.h \
arm_simulator.h \
arm_semihosting.h \
arm7_9_common.h \
arm7tdmi.h \
arm720t.h \
arm9tdmi.h \
arm920t.h \
arm926ejs.h \
arm966e.h \
arm946e.h \
arm11.h \
arm11_dbgtap.h \
armv4_5.h \
armv4_5_mmu.h \
armv4_5_cache.h \
armv7a.h \
armv7m.h \
avrt.h \
dsp563xx.h \
dsp563xx_once.h \
dsp5680xx.h \
breakpoints.h \
cortex_m.h \
cortex_a.h \
embeddedice.h \
etb.h \
etm.h \
etm_dummy.h \
image.h \
mips32.h \
mips_m4k.h \
mips_ejtag.h \
mips32_pracc.h \
mips32_dmaacc.h \
oocd_trace.h \
register.h \
target.h \
target_type.h \
trace.h \
target_request.h \
trace.h \
xscale.h \
smp.h \
avr32_ap7k.h \
avr32_jtag.h \
avr32_mem.h \
avr32_regs.h
ocddatadir = $(pkglibdir)
nobase_dist_ocddata_DATA =
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
all: $(BUILT_SOURCES)
$(MAKE) $(AM_MAKEFLAGS) all-am
.SUFFIXES:
.SUFFIXES: .c .lo .o .obj
$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(top_srcdir)/common.mk $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
&& { if test -f $@; then exit 0; else break; fi; }; \
exit 1;; \
esac; \
done; \
echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/target/Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --gnu src/target/Makefile
.PRECIOUS: Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
*) \
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
esac;
$(top_srcdir)/common.mk:
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(am__aclocal_m4_deps):
clean-noinstLTLIBRARIES:
-test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
@list='$(noinst_LTLIBRARIES)'; \
locs=`for p in $$list; do echo $$p; done | \
sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
sort -u`; \
test -z "$$locs" || { \
echo rm -f $${locs}; \
rm -f $${locs}; \
}
libtarget.la: $(libtarget_la_OBJECTS) $(libtarget_la_DEPENDENCIES) $(EXTRA_libtarget_la_DEPENDENCIES)
$(AM_V_CCLD)$(LINK) $(libtarget_la_OBJECTS) $(libtarget_la_LIBADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/adi_v5_jtag.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/adi_v5_swd.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/algorithm.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/arm11.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/arm11_dbgtap.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/arm720t.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/arm7_9_common.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/arm7tdmi.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/arm920t.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/arm926ejs.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/arm946e.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/arm966e.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/arm9tdmi.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/arm_adi_v5.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/arm_disassembler.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/arm_dpm.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/arm_jtag.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/arm_semihosting.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/arm_simulator.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/armv4_5.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/armv4_5_cache.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/armv4_5_mmu.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/armv7a.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/armv7m.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/avr32_ap7k.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/avr32_jtag.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/avr32_mem.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/avr32_regs.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/avrt.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/breakpoints.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cortex_a.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cortex_m.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dsp563xx.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dsp563xx_once.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dsp5680xx.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/embeddedice.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/etb.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/etm.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/etm_dummy.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fa526.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/feroceon.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hla_target.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/image.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mips32.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mips32_dmaacc.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mips32_pracc.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mips_ejtag.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mips_m4k.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/oocd_trace.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/register.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/smp.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/target.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/target_request.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testee.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/trace.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xscale.Plo@am__quote@
.c.o:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $<
.c.obj:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
.c.lo:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
mostlyclean-libtool:
-rm -f *.lo
clean-libtool:
-rm -rf .libs _libs
install-nobase_dist_ocddataDATA: $(nobase_dist_ocddata_DATA)
@$(NORMAL_INSTALL)
@list='$(nobase_dist_ocddata_DATA)'; test -n "$(ocddatadir)" || list=; \
if test -n "$$list"; then \
echo " $(MKDIR_P) '$(DESTDIR)$(ocddatadir)'"; \
$(MKDIR_P) "$(DESTDIR)$(ocddatadir)" || exit 1; \
fi; \
$(am__nobase_list) | while read dir files; do \
xfiles=; for file in $$files; do \
if test -f "$$file"; then xfiles="$$xfiles $$file"; \
else xfiles="$$xfiles $(srcdir)/$$file"; fi; done; \
test -z "$$xfiles" || { \
test "x$$dir" = x. || { \
echo " $(MKDIR_P) '$(DESTDIR)$(ocddatadir)/$$dir'"; \
$(MKDIR_P) "$(DESTDIR)$(ocddatadir)/$$dir"; }; \
echo " $(INSTALL_DATA) $$xfiles '$(DESTDIR)$(ocddatadir)/$$dir'"; \
$(INSTALL_DATA) $$xfiles "$(DESTDIR)$(ocddatadir)/$$dir" || exit $$?; }; \
done
uninstall-nobase_dist_ocddataDATA:
@$(NORMAL_UNINSTALL)
@list='$(nobase_dist_ocddata_DATA)'; test -n "$(ocddatadir)" || list=; \
$(am__nobase_strip_setup); files=`$(am__nobase_strip)`; \
dir='$(DESTDIR)$(ocddatadir)'; $(am__uninstall_files_from_dir)
ID: $(am__tagged_files)
$(am__define_uniq_tagged_files); mkid -fID $$unique
tags: tags-am
TAGS: tags
tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
set x; \
here=`pwd`; \
$(am__define_uniq_tagged_files); \
shift; \
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
test -n "$$unique" || unique=$$empty_fix; \
if test $$# -gt 0; then \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
"$$@" $$unique; \
else \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
$$unique; \
fi; \
fi
ctags: ctags-am
CTAGS: ctags
ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
$(am__define_uniq_tagged_files); \
test -z "$(CTAGS_ARGS)$$unique" \
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
$$unique
GTAGS:
here=`$(am__cd) $(top_builddir) && pwd` \
&& $(am__cd) $(top_srcdir) \
&& gtags -i $(GTAGS_ARGS) "$$here"
cscopelist: cscopelist-am
cscopelist-am: $(am__tagged_files)
list='$(am__tagged_files)'; \
case "$(srcdir)" in \
[\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
*) sdir=$(subdir)/$(srcdir) ;; \
esac; \
for i in $$list; do \
if test -f "$$i"; then \
echo "$(subdir)/$$i"; \
else \
echo "$$sdir/$$i"; \
fi; \
done >> $(top_builddir)/cscope.files
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
distdir: $(DISTFILES)
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
list='$(DISTFILES)'; \
dist_files=`for file in $$list; do echo $$file; done | \
sed -e "s|^$$srcdirstrip/||;t" \
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
case $$dist_files in \
*/*) $(MKDIR_P) `echo "$$dist_files" | \
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
sort -u` ;; \
esac; \
for file in $$dist_files; do \
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
if test -d $$d/$$file; then \
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
if test -d "$(distdir)/$$file"; then \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
else \
test -f "$(distdir)/$$file" \
|| cp -p $$d/$$file "$(distdir)/$$file" \
|| exit 1; \
fi; \
done
check-am: all-am
check: $(BUILT_SOURCES)
$(MAKE) $(AM_MAKEFLAGS) check-am
all-am: Makefile $(LTLIBRARIES) $(DATA) $(HEADERS)
installdirs:
for dir in "$(DESTDIR)$(ocddatadir)"; do \
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
done
install: $(BUILT_SOURCES)
$(MAKE) $(AM_MAKEFLAGS) install-am
install-exec: install-exec-am
install-data: install-data-am
uninstall: uninstall-am
install-am: all-am
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
installcheck: installcheck-am
install-strip:
if test -z '$(STRIP)'; then \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
install; \
else \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
fi
mostlyclean-generic:
clean-generic:
-test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
distclean-generic:
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@echo "it deletes files that may require special tools to rebuild."
-test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
-test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
clean: clean-am
clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
mostlyclean-am
distclean: distclean-am
-rm -rf ./$(DEPDIR)
-rm -f Makefile
distclean-am: clean-am distclean-compile distclean-generic \
distclean-tags
dvi: dvi-am
dvi-am:
html: html-am
html-am:
info: info-am
info-am:
install-data-am: install-nobase_dist_ocddataDATA
install-dvi: install-dvi-am
install-dvi-am:
install-exec-am:
install-html: install-html-am
install-html-am:
install-info: install-info-am
install-info-am:
install-man:
install-pdf: install-pdf-am
install-pdf-am:
install-ps: install-ps-am
install-ps-am:
installcheck-am:
maintainer-clean: maintainer-clean-am
-rm -rf ./$(DEPDIR)
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
mostlyclean: mostlyclean-am
mostlyclean-am: mostlyclean-compile mostlyclean-generic \
mostlyclean-libtool
pdf: pdf-am
pdf-am:
ps: ps-am
ps-am:
uninstall-am: uninstall-nobase_dist_ocddataDATA
.MAKE: all check install install-am install-strip
.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
clean-libtool clean-noinstLTLIBRARIES cscopelist-am ctags \
ctags-am distclean distclean-compile distclean-generic \
distclean-libtool distclean-tags distdir dvi dvi-am html \
html-am info info-am install install-am install-data \
install-data-am install-dvi install-dvi-am install-exec \
install-exec-am install-html install-html-am install-info \
install-info-am install-man install-nobase_dist_ocddataDATA \
install-pdf install-pdf-am install-ps install-ps-am \
install-strip installcheck installcheck-am installdirs \
maintainer-clean maintainer-clean-generic mostlyclean \
mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am \
uninstall-nobase_dist_ocddataDATA
$(DEBUG_HEADER): $(BIN2C) $(DEBUG_HANDLER)
$(BIN2C) < $(DEBUG_HANDLER) xscale_debug_handler > xscale_debug.h
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:

View File

@ -0,0 +1,530 @@
/***************************************************************************
* Copyright (C) 2006 by Magnus Lundin
* lundin@mlu.mine.nu
*
* Copyright (C) 2008 by Spencer Oliver
* spen@spen-soft.co.uk
*
* Copyright (C) 2009 by Oyvind Harboe
* oyvind.harboe@zylin.com
*
* Copyright (C) 2009-2010 by David Brownell
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
***************************************************************************/
/**
* @file
* This file implements JTAG transport support for cores implementing
the ARM Debug Interface version 5 (ADIv5).
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "arm.h"
#include "arm_adi_v5.h"
#include <helper/time_support.h>
/* JTAG instructions/registers for JTAG-DP and SWJ-DP */
#define JTAG_DP_ABORT 0x8
#define JTAG_DP_DPACC 0xA
#define JTAG_DP_APACC 0xB
#define JTAG_DP_IDCODE 0xE
/* three-bit ACK values for DPACC and APACC reads */
#define JTAG_ACK_OK_FAULT 0x2
#define JTAG_ACK_WAIT 0x1
static int jtag_ap_q_abort(struct adiv5_dap *dap, uint8_t *ack);
/***************************************************************************
*
* DPACC and APACC scanchain access through JTAG-DP (or SWJ-DP)
*
***************************************************************************/
/**
* Scan DPACC or APACC using target ordered uint8_t buffers. No endianness
* conversions are performed. See section 4.4.3 of the ADIv5 spec, which
* discusses operations which access these registers.
*
* Note that only one scan is performed. If RnW is set, a separate scan
* will be needed to collect the data which was read; the "invalue" collects
* the posted result of a preceding operation, not the current one.
*
* @param dap the DAP
* @param instr JTAG_DP_APACC (AP access) or JTAG_DP_DPACC (DP access)
* @param reg_addr two significant bits; A[3:2]; for APACC access, the
* SELECT register has more addressing bits.
* @param RnW false iff outvalue will be written to the DP or AP
* @param outvalue points to a 32-bit (little-endian) integer
* @param invalue NULL, or points to a 32-bit (little-endian) integer
* @param ack points to where the three bit JTAG_ACK_* code will be stored
*/
static int adi_jtag_dp_scan(struct adiv5_dap *dap,
uint8_t instr, uint8_t reg_addr, uint8_t RnW,
uint8_t *outvalue, uint8_t *invalue, uint8_t *ack)
{
struct arm_jtag *jtag_info = dap->jtag_info;
struct scan_field fields[2];
uint8_t out_addr_buf;
int retval;
retval = arm_jtag_set_instr(jtag_info, instr, NULL, TAP_IDLE);
if (retval != ERROR_OK)
return retval;
/* Scan out a read or write operation using some DP or AP register.
* For APACC access with any sticky error flag set, this is discarded.
*/
fields[0].num_bits = 3;
buf_set_u32(&out_addr_buf, 0, 3, ((reg_addr >> 1) & 0x6) | (RnW & 0x1));
fields[0].out_value = &out_addr_buf;
fields[0].in_value = ack;
/* NOTE: if we receive JTAG_ACK_WAIT, the previous operation did not
* complete; data we write is discarded, data we read is unpredictable.
* When overrun detect is active, STICKYORUN is set.
*/
fields[1].num_bits = 32;
fields[1].out_value = outvalue;
fields[1].in_value = invalue;
jtag_add_dr_scan(jtag_info->tap, 2, fields, TAP_IDLE);
/* Add specified number of tck clocks after starting memory bus
* access, giving the hardware time to complete the access.
* They provide more time for the (MEM) AP to complete the read ...
* See "Minimum Response Time" for JTAG-DP, in the ADIv5 spec.
*/
if ((instr == JTAG_DP_APACC)
&& ((reg_addr == AP_REG_DRW)
|| ((reg_addr & 0xF0) == AP_REG_BD0))
&& (dap->memaccess_tck != 0))
jtag_add_runtest(dap->memaccess_tck,
TAP_IDLE);
return ERROR_OK;
}
/**
* Scan DPACC or APACC out and in from host ordered uint32_t buffers.
* This is exactly like adi_jtag_dp_scan(), except that endianness
* conversions are performed (so the types of invalue and outvalue
* must be different).
*/
static int adi_jtag_dp_scan_u32(struct adiv5_dap *dap,
uint8_t instr, uint8_t reg_addr, uint8_t RnW,
uint32_t outvalue, uint32_t *invalue, uint8_t *ack)
{
uint8_t out_value_buf[4];
int retval;
buf_set_u32(out_value_buf, 0, 32, outvalue);
retval = adi_jtag_dp_scan(dap, instr, reg_addr, RnW,
out_value_buf, (uint8_t *)invalue, ack);
if (retval != ERROR_OK)
return retval;
if (invalue)
jtag_add_callback(arm_le_to_h_u32,
(jtag_callback_data_t) invalue);
return retval;
}
/**
* Utility to write AP registers.
*/
static inline int adi_jtag_ap_write_check(struct adiv5_dap *dap,
uint8_t reg_addr, uint8_t *outvalue)
{
return adi_jtag_dp_scan(dap, JTAG_DP_APACC, reg_addr, DPAP_WRITE,
outvalue, NULL, NULL);
}
static int adi_jtag_scan_inout_check_u32(struct adiv5_dap *dap,
uint8_t instr, uint8_t reg_addr, uint8_t RnW,
uint32_t outvalue, uint32_t *invalue)
{
int retval;
/* Issue the read or write */
retval = adi_jtag_dp_scan_u32(dap, instr, reg_addr,
RnW, outvalue, NULL, NULL);
if (retval != ERROR_OK)
return retval;
/* For reads, collect posted value; RDBUFF has no other effect.
* Assumes read gets acked with OK/FAULT, and CTRL_STAT says "OK".
*/
if ((RnW == DPAP_READ) && (invalue != NULL))
retval = adi_jtag_dp_scan_u32(dap, JTAG_DP_DPACC,
DP_RDBUFF, DPAP_READ, 0, invalue, &dap->ack);
return retval;
}
static int jtagdp_transaction_endcheck(struct adiv5_dap *dap)
{
int retval;
uint32_t ctrlstat;
/* too expensive to call keep_alive() here */
/* Here be dragons!
*
* It is easy to be in a JTAG clock range where the target
* is not operating in a stable fashion. This happens
* for a few reasons:
*
* - the user may construct a simple test case to try to see
* if a higher JTAG clock works to eke out more performance.
* This simple case may pass, but more complex situations can
* fail.
*
* - The mostly works JTAG clock rate and the complete failure
* JTAG clock rate may be as much as 2-4x apart. This seems
* to be especially true on RC oscillator driven parts.
*
* So: even if calling adi_jtag_scan_inout_check_u32() multiple
* times here seems to "make things better here", it is just
* hiding problems with too high a JTAG clock.
*
* Note that even if some parts have RCLK/RTCK, that doesn't
* mean that RCLK/RTCK is the *correct* rate to run the JTAG
* interface at, i.e. RCLK/RTCK rates can be "too high", especially
* before the RC oscillator phase is not yet complete.
*/
/* Post CTRL/STAT read; discard any previous posted read value
* but collect its ACK status.
*/
retval = adi_jtag_scan_inout_check_u32(dap, JTAG_DP_DPACC,
DP_CTRL_STAT, DPAP_READ, 0, &ctrlstat);
if (retval != ERROR_OK)
return retval;
retval = jtag_execute_queue();
if (retval != ERROR_OK)
return retval;
dap->ack = dap->ack & 0x7;
/* common code path avoids calling timeval_ms() */
if (dap->ack != JTAG_ACK_OK_FAULT) {
long long then = timeval_ms();
while (dap->ack != JTAG_ACK_OK_FAULT) {
if (dap->ack == JTAG_ACK_WAIT) {
if ((timeval_ms()-then) > 1000) {
LOG_WARNING("Timeout (1000ms) waiting "
"for ACK=OK/FAULT "
"in JTAG-DP transaction - aborting");
uint8_t ack;
int abort_ret = jtag_ap_q_abort(dap, &ack);
if (abort_ret != 0)
LOG_WARNING("Abort failed : return=%d ack=%d", abort_ret, ack);
return ERROR_JTAG_DEVICE_ERROR;
}
} else {
LOG_WARNING("Invalid ACK %#x "
"in JTAG-DP transaction",
dap->ack);
return ERROR_JTAG_DEVICE_ERROR;
}
retval = adi_jtag_scan_inout_check_u32(dap, JTAG_DP_DPACC,
DP_CTRL_STAT, DPAP_READ, 0, &ctrlstat);
if (retval != ERROR_OK)
return retval;
retval = jtag_execute_queue();
if (retval != ERROR_OK)
return retval;
dap->ack = dap->ack & 0x7;
}
}
/* REVISIT also STICKYCMP, for pushed comparisons (nyet used) */
/* Check for STICKYERR and STICKYORUN */
if (ctrlstat & (SSTICKYORUN | SSTICKYERR)) {
LOG_DEBUG("jtag-dp: CTRL/STAT error, 0x%" PRIx32, ctrlstat);
/* Check power to debug regions */
if ((ctrlstat & 0xf0000000) != 0xf0000000) {
retval = ahbap_debugport_init(dap);
if (retval != ERROR_OK)
return retval;
} else {
uint32_t mem_ap_csw, mem_ap_tar;
/* Maybe print information about last intended
* MEM-AP access; but not if autoincrementing.
* *Real* CSW and TAR values are always shown.
*/
if (dap->ap_tar_value != (uint32_t) -1)
LOG_DEBUG("MEM-AP Cached values: "
"ap_bank 0x%" PRIx32
", ap_csw 0x%" PRIx32
", ap_tar 0x%" PRIx32,
dap->ap_bank_value,
dap->ap_csw_value,
dap->ap_tar_value);
if (ctrlstat & SSTICKYORUN)
LOG_ERROR("JTAG-DP OVERRUN - check clock, "
"memaccess, or reduce jtag speed");
if (ctrlstat & SSTICKYERR)
LOG_ERROR("JTAG-DP STICKY ERROR");
/* Clear Sticky Error Bits */
retval = adi_jtag_scan_inout_check_u32(dap, JTAG_DP_DPACC,
DP_CTRL_STAT, DPAP_WRITE,
dap->dp_ctrl_stat | SSTICKYORUN
| SSTICKYERR, NULL);
if (retval != ERROR_OK)
return retval;
retval = adi_jtag_scan_inout_check_u32(dap, JTAG_DP_DPACC,
DP_CTRL_STAT, DPAP_READ, 0, &ctrlstat);
if (retval != ERROR_OK)
return retval;
retval = jtag_execute_queue();
if (retval != ERROR_OK)
return retval;
LOG_DEBUG("jtag-dp: CTRL/STAT 0x%" PRIx32, ctrlstat);
retval = dap_queue_ap_read(dap,
AP_REG_CSW, &mem_ap_csw);
if (retval != ERROR_OK)
return retval;
retval = dap_queue_ap_read(dap,
AP_REG_TAR, &mem_ap_tar);
if (retval != ERROR_OK)
return retval;
retval = jtag_execute_queue();
if (retval != ERROR_OK)
return retval;
LOG_ERROR("MEM_AP_CSW 0x%" PRIx32 ", MEM_AP_TAR 0x%"
PRIx32, mem_ap_csw, mem_ap_tar);
}
retval = jtag_execute_queue();
if (retval != ERROR_OK)
return retval;
return ERROR_JTAG_DEVICE_ERROR;
}
return ERROR_OK;
}
/*--------------------------------------------------------------------------*/
static int jtag_idcode_q_read(struct adiv5_dap *dap,
uint8_t *ack, uint32_t *data)
{
struct arm_jtag *jtag_info = dap->jtag_info;
int retval;
struct scan_field fields[1];
/* This is a standard JTAG operation -- no DAP tweakage */
retval = arm_jtag_set_instr(jtag_info, JTAG_DP_IDCODE, NULL, TAP_IDLE);
if (retval != ERROR_OK)
return retval;
fields[0].num_bits = 32;
fields[0].out_value = NULL;
fields[0].in_value = (void *) data;
jtag_add_dr_scan(jtag_info->tap, 1, fields, TAP_IDLE);
jtag_add_callback(arm_le_to_h_u32,
(jtag_callback_data_t) data);
return ERROR_OK;
}
static int jtag_dp_q_read(struct adiv5_dap *dap, unsigned reg,
uint32_t *data)
{
return adi_jtag_scan_inout_check_u32(dap, JTAG_DP_DPACC,
reg, DPAP_READ, 0, data);
}
static int jtag_dp_q_write(struct adiv5_dap *dap, unsigned reg,
uint32_t data)
{
return adi_jtag_scan_inout_check_u32(dap, JTAG_DP_DPACC,
reg, DPAP_WRITE, data, NULL);
}
/** Select the AP register bank matching bits 7:4 of reg. */
static int jtag_ap_q_bankselect(struct adiv5_dap *dap, unsigned reg)
{
uint32_t select_ap_bank = reg & 0x000000F0;
if (select_ap_bank == dap->ap_bank_value)
return ERROR_OK;
dap->ap_bank_value = select_ap_bank;
select_ap_bank |= dap->ap_current;
return jtag_dp_q_write(dap, DP_SELECT, select_ap_bank);
}
static int jtag_ap_q_read(struct adiv5_dap *dap, unsigned reg,
uint32_t *data)
{
int retval = jtag_ap_q_bankselect(dap, reg);
if (retval != ERROR_OK)
return retval;
return adi_jtag_scan_inout_check_u32(dap, JTAG_DP_APACC, reg,
DPAP_READ, 0, data);
}
static int jtag_ap_q_write(struct adiv5_dap *dap, unsigned reg,
uint32_t data)
{
uint8_t out_value_buf[4];
int retval = jtag_ap_q_bankselect(dap, reg);
if (retval != ERROR_OK)
return retval;
buf_set_u32(out_value_buf, 0, 32, data);
return adi_jtag_ap_write_check(dap, reg, out_value_buf);
}
static int jtag_ap_q_read_block(struct adiv5_dap *dap, unsigned reg,
uint32_t blocksize, uint8_t *buffer)
{
uint32_t readcount;
int retval = ERROR_OK;
/* Scan out first read */
retval = adi_jtag_dp_scan(dap, JTAG_DP_APACC, reg,
DPAP_READ, 0, NULL, NULL);
if (retval != ERROR_OK)
return retval;
for (readcount = 0; readcount < blocksize - 1; readcount++) {
/* Scan out next read; scan in posted value for the
* previous one. Assumes read is acked "OK/FAULT",
* and CTRL_STAT says that meant "OK".
*/
retval = adi_jtag_dp_scan(dap, JTAG_DP_APACC, reg,
DPAP_READ, 0, buffer + 4 * readcount,
&dap->ack);
if (retval != ERROR_OK)
return retval;
}
/* Scan in last posted value; RDBUFF has no other effect,
* assuming ack is OK/FAULT and CTRL_STAT says "OK".
*/
retval = adi_jtag_dp_scan(dap, JTAG_DP_DPACC, DP_RDBUFF,
DPAP_READ, 0, buffer + 4 * readcount,
&dap->ack);
return retval;
}
static int jtag_ap_q_abort(struct adiv5_dap *dap, uint8_t *ack)
{
/* for JTAG, this is the only valid ABORT register operation */
return adi_jtag_dp_scan_u32(dap, JTAG_DP_ABORT,
0, DPAP_WRITE, 1, NULL, ack);
}
static int jtag_dp_run(struct adiv5_dap *dap)
{
return jtagdp_transaction_endcheck(dap);
}
/* FIXME don't export ... just initialize as
* part of DAP setup
*/
const struct dap_ops jtag_dp_ops = {
.queue_idcode_read = jtag_idcode_q_read,
.queue_dp_read = jtag_dp_q_read,
.queue_dp_write = jtag_dp_q_write,
.queue_ap_read = jtag_ap_q_read,
.queue_ap_write = jtag_ap_q_write,
.queue_ap_read_block = jtag_ap_q_read_block,
.queue_ap_abort = jtag_ap_q_abort,
.run = jtag_dp_run,
};
static const uint8_t swd2jtag_bitseq[] = {
/* More than 50 TCK/SWCLK cycles with TMS/SWDIO high,
* putting both JTAG and SWD logic into reset state.
*/
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
/* Switching equence disables SWD and enables JTAG
* NOTE: bits in the DP's IDCODE can expose the need for
* the old/deprecated sequence (0xae 0xde).
*/
0x3c, 0xe7,
/* At least 50 TCK/SWCLK cycles with TMS/SWDIO high,
* putting both JTAG and SWD logic into reset state.
* NOTE: some docs say "at least 5".
*/
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
};
/** Put the debug link into JTAG mode, if the target supports it.
* The link's initial mode may be either SWD or JTAG.
*
* @param target Enters JTAG mode (if possible).
*
* Note that targets implemented with SW-DP do not support JTAG, and
* that some targets which could otherwise support it may have been
* configured to disable JTAG signaling
*
* @return ERROR_OK or else a fault code.
*/
int dap_to_jtag(struct target *target)
{
int retval;
LOG_DEBUG("Enter JTAG mode");
/* REVISIT it's nasty to need to make calls to a "jtag"
* subsystem if the link isn't in JTAG mode...
*/
retval = jtag_add_tms_seq(8 * sizeof(swd2jtag_bitseq),
swd2jtag_bitseq, TAP_RESET);
if (retval == ERROR_OK)
retval = jtag_execute_queue();
/* REVISIT set up the DAP's ops vector for JTAG mode. */
return retval;
}

View File

@ -0,0 +1,357 @@
/***************************************************************************
*
* Copyright (C) 2010 by David Brownell
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
***************************************************************************/
/**
* @file
* Utilities to support ARM "Serial Wire Debug" (SWD), a low pin-count debug
* link protocol used in cases where JTAG is not wanted. This is coupled to
* recent versions of ARM's "CoreSight" debug framework. This specific code
* is a transport level interface, with "target/arm_adi_v5.[hc]" code
* understanding operation semantics, shared with the JTAG transport.
*
* Single-DAP support only.
*
* for details, see "ARM IHI 0031A"
* ARM Debug Interface v5 Architecture Specification
* especially section 5.3 for SWD protocol
*
* On many chips (most current Cortex-M3 parts) SWD is a run-time alternative
* to JTAG. Boards may support one or both. There are also SWD-only chips,
* (using SW-DP not SWJ-DP).
*
* Even boards that also support JTAG can benefit from SWD support, because
* usually there's no way to access the SWO trace view mechanism in JTAG mode.
* That is, trace access may require SWD support.
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "arm.h"
#include "arm_adi_v5.h"
#include <helper/time_support.h>
#include <transport/transport.h>
#include <jtag/interface.h>
#include <jtag/swd.h>
static int swd_queue_dp_read(struct adiv5_dap *dap, unsigned reg,
uint32_t *data)
{
/* REVISIT status return vs ack ... */
return swd->read_reg(swd_cmd(true, false, reg), data);
}
static int swd_queue_idcode_read(struct adiv5_dap *dap,
uint8_t *ack, uint32_t *data)
{
int status = swd_queue_dp_read(dap, DP_IDCODE, data);
if (status < 0)
return status;
*ack = status;
/* ?? */
return ERROR_OK;
}
static int (swd_queue_dp_write)(struct adiv5_dap *dap, unsigned reg,
uint32_t data)
{
/* REVISIT status return vs ack ... */
return swd->write_reg(swd_cmd(false, false, reg), data);
}
static int (swd_queue_ap_read)(struct adiv5_dap *dap, unsigned reg,
uint32_t *data)
{
/* REVISIT APSEL ... */
/* REVISIT status return ... */
return swd->read_reg(swd_cmd(true, true, reg), data);
}
static int (swd_queue_ap_write)(struct adiv5_dap *dap, unsigned reg,
uint32_t data)
{
/* REVISIT APSEL ... */
/* REVISIT status return ... */
return swd->write_reg(swd_cmd(false, true, reg), data);
}
static int (swd_queue_ap_abort)(struct adiv5_dap *dap, uint8_t *ack)
{
return ERROR_FAIL;
}
/** Executes all queued DAP operations. */
static int swd_run(struct adiv5_dap *dap)
{
/* for now the SWD interface hard-wires a zero-size queue. */
/* FIXME but we still need to check and scrub
* any hardware errors ...
*/
return ERROR_OK;
}
const struct dap_ops swd_dap_ops = {
.is_swd = true,
.queue_idcode_read = swd_queue_idcode_read,
.queue_dp_read = swd_queue_dp_read,
.queue_dp_write = swd_queue_dp_write,
.queue_ap_read = swd_queue_ap_read,
.queue_ap_write = swd_queue_ap_write,
.queue_ap_abort = swd_queue_ap_abort,
.run = swd_run,
};
/*
* This represents the bits which must be sent out on TMS/SWDIO to
* switch a DAP implemented using an SWJ-DP module into SWD mode.
* These bits are stored (and transmitted) LSB-first.
*
* See the DAP-Lite specification, section 2.2.5 for information
* about making the debug link select SWD or JTAG. (Similar info
* is in a few other ARM documents.)
*/
static const uint8_t jtag2swd_bitseq[] = {
/* More than 50 TCK/SWCLK cycles with TMS/SWDIO high,
* putting both JTAG and SWD logic into reset state.
*/
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
/* Switching sequence enables SWD and disables JTAG
* NOTE: bits in the DP's IDCODE may expose the need for
* an old/obsolete/deprecated sequence (0xb6 0xed).
*/
0x9e, 0xe7,
/* More than 50 TCK/SWCLK cycles with TMS/SWDIO high,
* putting both JTAG and SWD logic into reset state.
*/
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
};
/**
* Put the debug link into SWD mode, if the target supports it.
* The link's initial mode may be either JTAG (for example,
* with SWJ-DP after reset) or SWD.
*
* @param target Enters SWD mode (if possible).
*
* Note that targets using the JTAG-DP do not support SWD, and that
* some targets which could otherwise support it may have have been
* configured to disable SWD signaling
*
* @return ERROR_OK or else a fault code.
*/
int dap_to_swd(struct target *target)
{
struct arm *arm = target_to_arm(target);
int retval;
LOG_DEBUG("Enter SWD mode");
/* REVISIT it's ugly to need to make calls to a "jtag"
* subsystem if the link may not be in JTAG mode...
*/
retval = jtag_add_tms_seq(8 * sizeof(jtag2swd_bitseq),
jtag2swd_bitseq, TAP_INVALID);
if (retval == ERROR_OK)
retval = jtag_execute_queue();
/* set up the DAP's ops vector for SWD mode. */
arm->dap->ops = &swd_dap_ops;
return retval;
}
COMMAND_HANDLER(handle_swd_wcr)
{
int retval;
struct target *target = get_current_target(CMD_CTX);
struct arm *arm = target_to_arm(target);
struct adiv5_dap *dap = arm->dap;
uint32_t wcr;
unsigned trn, scale = 0;
switch (CMD_ARGC) {
/* no-args: just dump state */
case 0:
/*retval = swd_queue_dp_read(dap, DP_WCR, &wcr); */
retval = dap_queue_dp_read(dap, DP_WCR, &wcr);
if (retval == ERROR_OK)
dap->ops->run(dap);
if (retval != ERROR_OK) {
LOG_ERROR("can't read WCR?");
return retval;
}
command_print(CMD_CTX,
"turnaround=%d, prescale=%d",
WCR_TO_TRN(wcr),
WCR_TO_PRESCALE(wcr));
return ERROR_OK;
case 2: /* TRN and prescale */
COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], scale);
if (scale > 7) {
LOG_ERROR("prescale %d is too big", scale);
return ERROR_FAIL;
}
/* FALL THROUGH */
case 1: /* TRN only */
COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], trn);
if (trn < 1 || trn > 4) {
LOG_ERROR("turnaround %d is invalid", trn);
return ERROR_FAIL;
}
wcr = ((trn - 1) << 8) | scale;
/* FIXME
* write WCR ...
* then, re-init adapter with new TRN
*/
LOG_ERROR("can't yet modify WCR");
return ERROR_FAIL;
default: /* too many arguments */
return ERROR_COMMAND_SYNTAX_ERROR;
}
}
static const struct command_registration swd_commands[] = {
{
/*
* Set up SWD and JTAG targets identically, unless/until
* infrastructure improves ... meanwhile, ignore all
* JTAG-specific stuff like IR length for SWD.
*
* REVISIT can we verify "just one SWD DAP" here/early?
*/
.name = "newdap",
.jim_handler = jim_jtag_newtap,
.mode = COMMAND_CONFIG,
.help = "declare a new SWD DAP"
},
{
.name = "wcr",
.handler = handle_swd_wcr,
.mode = COMMAND_ANY,
.help = "display or update DAP's WCR register",
.usage = "turnaround (1..4), prescale (0..7)",
},
/* REVISIT -- add a command for SWV trace on/off */
COMMAND_REGISTRATION_DONE
};
static const struct command_registration swd_handlers[] = {
{
.name = "swd",
.mode = COMMAND_ANY,
.help = "SWD command group",
.chain = swd_commands,
},
COMMAND_REGISTRATION_DONE
};
static int swd_select(struct command_context *ctx)
{
struct target *target = get_current_target(ctx);
int retval;
retval = register_commands(ctx, NULL, swd_handlers);
if (retval != ERROR_OK)
return retval;
/* be sure driver is in SWD mode; start
* with hardware default TRN (1), it can be changed later
*/
if (!swd || !swd->read_reg || !swd->write_reg || !swd->init) {
LOG_DEBUG("no SWD driver?");
return ERROR_FAIL;
}
retval = swd->init(1);
if (retval != ERROR_OK) {
LOG_DEBUG("can't init SWD driver");
return retval;
}
/* force DAP into SWD mode (not JTAG) */
retval = dap_to_swd(target);
return retval;
}
static int swd_init(struct command_context *ctx)
{
struct target *target = get_current_target(ctx);
struct arm *arm = target_to_arm(target);
struct adiv5_dap *dap = arm->dap;
uint32_t idcode;
int status;
/* FIXME validate transport config ... is the
* configured DAP present (check IDCODE)?
* Is *only* one DAP configured?
*
* MUST READ IDCODE
*/
/* Note, debugport_init() does setup too */
uint8_t ack;
status = swd_queue_idcode_read(dap, &ack, &idcode);
if (status == ERROR_OK)
LOG_INFO("SWD IDCODE %#8.8x", idcode);
return status;
}
static struct transport swd_transport = {
.name = "swd",
.select = swd_select,
.init = swd_init,
};
static void swd_constructor(void) __attribute__((constructor));
static void swd_constructor(void)
{
transport_register(&swd_transport);
}
/** Returns true if the current debug session
* is using SWD as its transport.
*/
bool transport_is_swd(void)
{
return get_current_transport() == &swd_transport;
}

View File

@ -0,0 +1,54 @@
/***************************************************************************
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "algorithm.h"
#include <helper/binarybuffer.h>
void init_mem_param(struct mem_param *param, uint32_t address, uint32_t size, enum param_direction direction)
{
param->address = address;
param->size = size;
param->value = malloc(size);
param->direction = direction;
}
void destroy_mem_param(struct mem_param *param)
{
free(param->value);
param->value = NULL;
}
void init_reg_param(struct reg_param *param, char *reg_name, uint32_t size, enum param_direction direction)
{
param->reg_name = reg_name;
param->size = size;
param->value = malloc(DIV_ROUND_UP(size, 8));
param->direction = direction;
}
void destroy_reg_param(struct reg_param *param)
{
free(param->value);
param->value = NULL;
}

View File

@ -0,0 +1,52 @@
/***************************************************************************
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef ALGORITHM_H
#define ALGORITHM_H
enum param_direction {
PARAM_IN,
PARAM_OUT,
PARAM_IN_OUT
};
struct mem_param {
uint32_t address;
uint32_t size;
uint8_t *value;
enum param_direction direction;
};
struct reg_param {
const char *reg_name;
uint32_t size;
uint8_t *value;
enum param_direction direction;
};
void init_mem_param(struct mem_param *param,
uint32_t address, uint32_t size, enum param_direction dir);
void destroy_mem_param(struct mem_param *param);
void init_reg_param(struct reg_param *param,
char *reg_name, uint32_t size, enum param_direction dir);
void destroy_reg_param(struct reg_param *param);
#endif /* ALGORITHM_H */

View File

@ -0,0 +1,243 @@
/*
* Copyright (C) 2005 by Dominic Rath
* Dominic.Rath@gmx.de
*
* Copyright (C) 2008 by Spencer Oliver
* spen@spen-soft.co.uk
*
* Copyright (C) 2009 by Øyvind Harboe
* oyvind.harboe@zylin.com
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef ARM_H
#define ARM_H
#include <helper/command.h>
#include "target.h"
/**
* @file
* Holds the interface to ARM cores.
*
* At this writing, only "classic ARM" cores built on the ARMv4 register
* and mode model are supported. The Thumb2-only microcontroller profile
* support has not yet been integrated, affecting Cortex-M parts.
*/
/**
* Represent state of an ARM core.
*
* Most numbers match the five low bits of the *PSR registers on
* "classic ARM" processors, which build on the ARMv4 processor
* modes and register set.
*
* ARM_MODE_ANY is a magic value, often used as a wildcard.
*
* Only the microcontroller cores (ARMv6-M, ARMv7-M) support ARM_MODE_THREAD,
* ARM_MODE_USER_THREAD, and ARM_MODE_HANDLER. Those are the only modes
* they support.
*/
enum arm_mode {
ARM_MODE_USR = 16,
ARM_MODE_FIQ = 17,
ARM_MODE_IRQ = 18,
ARM_MODE_SVC = 19,
ARM_MODE_ABT = 23,
ARM_MODE_MON = 26,
ARM_MODE_UND = 27,
ARM_MODE_SYS = 31,
ARM_MODE_THREAD = 0,
ARM_MODE_USER_THREAD = 1,
ARM_MODE_HANDLER = 2,
ARM_MODE_ANY = -1
};
const char *arm_mode_name(unsigned psr_mode);
bool is_arm_mode(unsigned psr_mode);
/** The PSR "T" and "J" bits define the mode of "classic ARM" cores. */
enum arm_state {
ARM_STATE_ARM,
ARM_STATE_THUMB,
ARM_STATE_JAZELLE,
ARM_STATE_THUMB_EE,
};
#define ARM_COMMON_MAGIC 0x0A450A45
/**
* Represents a generic ARM core, with standard application registers.
*
* There are sixteen application registers (including PC, SP, LR) and a PSR.
* Cortex-M series cores do not support as many core states or shadowed
* registers as traditional ARM cores, and only support Thumb2 instructions.
*/
struct arm {
int common_magic;
struct reg_cache *core_cache;
/** Handle to the PC; valid in all core modes. */
struct reg *pc;
/** Handle to the CPSR; valid in all core modes. */
struct reg *cpsr;
/** Handle to the SPSR; valid only in core modes with an SPSR. */
struct reg *spsr;
/** Support for arm_reg_current() */
const int *map;
/**
* Indicates what registers are in the ARM state core register set.
* ARM_MODE_ANY indicates the standard set of 37 registers,
* seen on for example ARM7TDMI cores. ARM_MODE_MON indicates three
* more registers are shadowed, for "Secure Monitor" mode.
* ARM_MODE_THREAD indicates a microcontroller profile core,
* which only shadows SP.
*/
enum arm_mode core_type;
/** Record the current core mode: SVC, USR, or some other mode. */
enum arm_mode core_mode;
/** Record the current core state: ARM, Thumb, or otherwise. */
enum arm_state core_state;
/** Flag reporting unavailability of the BKPT instruction. */
bool is_armv4;
/** Flag reporting armv6m based core. */
bool is_armv6m;
/** Flag reporting whether semihosting is active. */
bool is_semihosting;
/** Value to be returned by semihosting SYS_ERRNO request. */
int semihosting_errno;
int (*setup_semihosting)(struct target *target, int enable);
/** Backpointer to the target. */
struct target *target;
/** Handle for the debug module, if one is present. */
struct arm_dpm *dpm;
/** Handle for the Embedded Trace Module, if one is present. */
struct etm_context *etm;
/* FIXME all these methods should take "struct arm *" not target */
/** Retrieve all core registers, for display. */
int (*full_context)(struct target *target);
/** Retrieve a single core register. */
int (*read_core_reg)(struct target *target, struct reg *reg,
int num, enum arm_mode mode);
int (*write_core_reg)(struct target *target, struct reg *reg,
int num, enum arm_mode mode, uint32_t value);
/** Read coprocessor register. */
int (*mrc)(struct target *target, int cpnum,
uint32_t op1, uint32_t op2,
uint32_t CRn, uint32_t CRm,
uint32_t *value);
/** Write coprocessor register. */
int (*mcr)(struct target *target, int cpnum,
uint32_t op1, uint32_t op2,
uint32_t CRn, uint32_t CRm,
uint32_t value);
void *arch_info;
/** For targets conforming to ARM Debug Interface v5,
* this handle references the Debug Access Port (DAP)
* used to make requests to the target.
*/
struct adiv5_dap *dap;
};
/** Convert target handle to generic ARM target state handle. */
static inline struct arm *target_to_arm(struct target *target)
{
assert(target != NULL);
return target->arch_info;
}
static inline bool is_arm(struct arm *arm)
{
assert(arm != NULL);
return arm->common_magic == ARM_COMMON_MAGIC;
}
struct arm_algorithm {
int common_magic;
enum arm_mode core_mode;
enum arm_state core_state;
};
struct arm_reg {
int num;
enum arm_mode mode;
struct target *target;
struct arm *arm;
uint32_t value;
};
struct reg_cache *arm_build_reg_cache(struct target *target, struct arm *arm);
extern const struct command_registration arm_command_handlers[];
int arm_arch_state(struct target *target);
int arm_get_gdb_reg_list(struct target *target,
struct reg **reg_list[], int *reg_list_size);
int arm_init_arch_info(struct target *target, struct arm *arm);
/* REVISIT rename this once it's usable by ARMv7-M */
int armv4_5_run_algorithm(struct target *target,
int num_mem_params, struct mem_param *mem_params,
int num_reg_params, struct reg_param *reg_params,
uint32_t entry_point, uint32_t exit_point,
int timeout_ms, void *arch_info);
int armv4_5_run_algorithm_inner(struct target *target,
int num_mem_params, struct mem_param *mem_params,
int num_reg_params, struct reg_param *reg_params,
uint32_t entry_point, uint32_t exit_point,
int timeout_ms, void *arch_info,
int (*run_it)(struct target *target, uint32_t exit_point,
int timeout_ms, void *arch_info));
int arm_checksum_memory(struct target *target,
uint32_t address, uint32_t count, uint32_t *checksum);
int arm_blank_check_memory(struct target *target,
uint32_t address, uint32_t count, uint32_t *blank);
void arm_set_cpsr(struct arm *arm, uint32_t cpsr);
struct reg *arm_reg_current(struct arm *arm, unsigned regnum);
extern struct reg arm_gdb_dummy_fp_reg;
extern struct reg arm_gdb_dummy_fps_reg;
#endif /* ARM_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,116 @@
/***************************************************************************
* Copyright (C) 2008 digenius technology GmbH. *
* Michael Bruck *
* *
* Copyright (C) 2008 Georg Acher <acher@in.tum.de> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef ARM11_H
#define ARM11_H
#include "arm.h"
#include "arm_dpm.h"
#define ARM11_TAP_DEFAULT TAP_INVALID
#define CHECK_RETVAL(action) \
do { \
int __retval = (action); \
if (__retval != ERROR_OK) { \
LOG_DEBUG("error while calling \"%s\"", \
# action); \
return __retval; \
} \
} while (0)
/* bits from ARMv7 DIDR */
enum arm11_debug_version {
ARM11_DEBUG_V6 = 0x01,
ARM11_DEBUG_V61 = 0x02,
ARM11_DEBUG_V7 = 0x03,
ARM11_DEBUG_V7_CP14 = 0x04,
};
struct arm11_common {
struct arm arm;
/** Debug module state. */
struct arm_dpm dpm;
struct arm11_sc7_action *bpwp_actions;
unsigned bpwp_n;
size_t brp; /**< Number of Breakpoint Register Pairs from DIDR */
size_t free_brps; /**< Number of breakpoints allocated */
uint32_t dscr; /**< Last retrieved DSCR value. */
uint32_t saved_rdtr;
uint32_t saved_wdtr;
bool is_rdtr_saved;
bool is_wdtr_saved;
bool simulate_reset_on_next_halt; /**< Perform cleanups of the ARM state on next halt **/
/* Per-core configurable options.
* NOTE that several of these boolean options should not exist
* once the relevant code is known to work correctly.
*/
bool memwrite_burst;
bool memwrite_error_fatal;
bool step_irq_enable;
bool hardware_step;
/** Configured Vector Catch Register settings. */
uint32_t vcr;
struct arm_jtag jtag_info;
};
static inline struct arm11_common *target_to_arm11(struct target *target)
{
return container_of(target->arch_info, struct arm11_common, arm);
}
/**
* ARM11 DBGTAP instructions
*
* http://infocenter.arm.com/help/topic/com.arm.doc.ddi0301f/I1006229.html
*/
enum arm11_instructions {
ARM11_EXTEST = 0x00,
ARM11_SCAN_N = 0x02,
ARM11_RESTART = 0x04,
ARM11_HALT = 0x08,
ARM11_INTEST = 0x0C,
ARM11_ITRSEL = 0x1D,
ARM11_IDCODE = 0x1E,
ARM11_BYPASS = 0x1F,
};
enum arm11_sc7 {
ARM11_SC7_NULL = 0,
ARM11_SC7_VCR = 7,
ARM11_SC7_PC = 8,
ARM11_SC7_BVR0 = 64,
ARM11_SC7_BCR0 = 80,
ARM11_SC7_WVR0 = 96,
ARM11_SC7_WCR0 = 112,
};
#endif /* ARM11_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,85 @@
/***************************************************************************
* Copyright (C) 2008 digenius technology GmbH. *
* Michael Bruck *
* *
* Copyright (C) 2008,2009 Oyvind Harboe oyvind.harboe@zylin.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef ARM11_DBGTAP_H
#define ARM11_DBGTAP_H
#include "arm11.h"
/* ARM11 internals */
void arm11_setup_field(struct arm11_common *arm11, int num_bits,
void *in_data, void *out_data, struct scan_field *field);
void arm11_add_IR(struct arm11_common *arm11,
uint8_t instr, tap_state_t state);
int arm11_add_debug_SCAN_N(struct arm11_common *arm11,
uint8_t chain, tap_state_t state);
int arm11_read_DSCR(struct arm11_common *arm11);
int arm11_write_DSCR(struct arm11_common *arm11, uint32_t dscr);
int arm11_run_instr_data_prepare(struct arm11_common *arm11);
int arm11_run_instr_data_finish(struct arm11_common *arm11);
int arm11_run_instr_no_data1(struct arm11_common *arm11, uint32_t opcode);
int arm11_run_instr_data_to_core(struct arm11_common *arm11,
uint32_t opcode, uint32_t *data, size_t count);
int arm11_run_instr_data_to_core_noack(struct arm11_common *arm11,
uint32_t opcode, uint32_t *data, size_t count);
int arm11_run_instr_data_to_core1(struct arm11_common *arm11,
uint32_t opcode, uint32_t data);
int arm11_run_instr_data_from_core(struct arm11_common *arm11,
uint32_t opcode, uint32_t *data, size_t count);
int arm11_run_instr_data_from_core_via_r0(struct arm11_common *arm11,
uint32_t opcode, uint32_t *data);
int arm11_run_instr_data_to_core_via_r0(struct arm11_common *arm11,
uint32_t opcode, uint32_t data);
void arm11_add_dr_scan_vc(struct jtag_tap *tap, int num_fields, struct scan_field *fields,
tap_state_t state);
/**
* Used with arm11_sc7_run to make a list of read/write commands for
* scan chain 7
*/
struct arm11_sc7_action {
bool write; /**< Access mode: true for write, false for read. */
uint8_t address;/**< Register address mode. Use enum #arm11_sc7 */
/**
* If write then set this to value to be written. In read mode
* this receives the read value when the function returns.
*/
uint32_t value;
};
int arm11_sc7_run(struct arm11_common *arm11,
struct arm11_sc7_action *actions, size_t count);
/* Mid-level helper functions */
int arm11_sc7_clear_vbw(struct arm11_common *arm11);
int arm11_sc7_set_vcr(struct arm11_common *arm11, uint32_t value);
int arm11_read_memory_word(struct arm11_common *arm11,
uint32_t address, uint32_t *result);
int arm11_dpm_init(struct arm11_common *arm11, uint32_t didr);
int arm11_bpwp_flush(struct arm11_common *arm11);
#endif /* ARM11_DBGTAP_H */

View File

@ -0,0 +1,591 @@
/***************************************************************************
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* Copyright (C) 2009 by Øyvind Harboe *
* oyvind.harboe@zylin.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "arm720t.h"
#include <helper/time_support.h>
#include "target_type.h"
#include "register.h"
#include "arm_opcodes.h"
/*
* ARM720 is an ARM7TDMI-S with MMU and ETM7. For information, see
* ARM DDI 0229C especially Chapter 9 about debug support.
*/
#if 0
#define _DEBUG_INSTRUCTION_EXECUTION_
#endif
static int arm720t_scan_cp15(struct target *target,
uint32_t out, uint32_t *in, int instruction, int clock_arg)
{
int retval;
struct arm720t_common *arm720t = target_to_arm720(target);
struct arm_jtag *jtag_info;
struct scan_field fields[2];
uint8_t out_buf[4];
uint8_t instruction_buf = instruction;
jtag_info = &arm720t->arm7_9_common.jtag_info;
buf_set_u32(out_buf, 0, 32, flip_u32(out, 32));
retval = arm_jtag_scann(jtag_info, 0xf, TAP_DRPAUSE);
if (retval != ERROR_OK)
return retval;
retval = arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL, TAP_DRPAUSE);
if (retval != ERROR_OK)
return retval;
fields[0].num_bits = 1;
fields[0].out_value = &instruction_buf;
fields[0].in_value = NULL;
fields[1].num_bits = 32;
fields[1].out_value = out_buf;
fields[1].in_value = NULL;
if (in) {
fields[1].in_value = (uint8_t *)in;
jtag_add_dr_scan(jtag_info->tap, 2, fields, TAP_DRPAUSE);
jtag_add_callback(arm7flip32, (jtag_callback_data_t)in);
} else
jtag_add_dr_scan(jtag_info->tap, 2, fields, TAP_DRPAUSE);
if (clock_arg)
jtag_add_runtest(0, TAP_DRPAUSE);
#ifdef _DEBUG_INSTRUCTION_EXECUTION_
retval = jtag_execute_queue();
if (retval != ERROR_OK)
return retval;
if (in)
LOG_DEBUG("out: %8.8x, in: %8.8x, instruction: %i, clock: %i", out, *in, instruction, clock);
else
LOG_DEBUG("out: %8.8x, instruction: %i, clock: %i", out, instruction, clock_arg);
#else
LOG_DEBUG("out: %8.8" PRIx32 ", instruction: %i, clock: %i", out, instruction, clock_arg);
#endif
return ERROR_OK;
}
static int arm720t_read_cp15(struct target *target, uint32_t opcode, uint32_t *value)
{
/* fetch CP15 opcode */
arm720t_scan_cp15(target, opcode, NULL, 1, 1);
/* "DECODE" stage */
arm720t_scan_cp15(target, ARMV4_5_NOP, NULL, 1, 1);
/* "EXECUTE" stage (1) */
arm720t_scan_cp15(target, ARMV4_5_NOP, NULL, 1, 0);
arm720t_scan_cp15(target, 0x0, NULL, 0, 1);
/* "EXECUTE" stage (2) */
arm720t_scan_cp15(target, 0x0, NULL, 0, 1);
/* "EXECUTE" stage (3), CDATA is read */
arm720t_scan_cp15(target, ARMV4_5_NOP, value, 1, 1);
return ERROR_OK;
}
static int arm720t_write_cp15(struct target *target, uint32_t opcode, uint32_t value)
{
/* fetch CP15 opcode */
arm720t_scan_cp15(target, opcode, NULL, 1, 1);
/* "DECODE" stage */
arm720t_scan_cp15(target, ARMV4_5_NOP, NULL, 1, 1);
/* "EXECUTE" stage (1) */
arm720t_scan_cp15(target, ARMV4_5_NOP, NULL, 1, 0);
arm720t_scan_cp15(target, 0x0, NULL, 0, 1);
/* "EXECUTE" stage (2) */
arm720t_scan_cp15(target, value, NULL, 0, 1);
arm720t_scan_cp15(target, ARMV4_5_NOP, NULL, 1, 1);
return ERROR_OK;
}
static int arm720t_get_ttb(struct target *target, uint32_t *result)
{
uint32_t ttb = 0x0;
int retval;
retval = arm720t_read_cp15(target, 0xee120f10, &ttb);
if (retval != ERROR_OK)
return retval;
retval = jtag_execute_queue();
if (retval != ERROR_OK)
return retval;
ttb &= 0xffffc000;
*result = ttb;
return ERROR_OK;
}
static int arm720t_disable_mmu_caches(struct target *target,
int mmu, int d_u_cache, int i_cache)
{
uint32_t cp15_control;
int retval;
/* read cp15 control register */
retval = arm720t_read_cp15(target, 0xee110f10, &cp15_control);
if (retval != ERROR_OK)
return retval;
retval = jtag_execute_queue();
if (retval != ERROR_OK)
return retval;
if (mmu)
cp15_control &= ~0x1U;
if (d_u_cache || i_cache)
cp15_control &= ~0x4U;
retval = arm720t_write_cp15(target, 0xee010f10, cp15_control);
return retval;
}
static int arm720t_enable_mmu_caches(struct target *target,
int mmu, int d_u_cache, int i_cache)
{
uint32_t cp15_control;
int retval;
/* read cp15 control register */
retval = arm720t_read_cp15(target, 0xee110f10, &cp15_control);
if (retval != ERROR_OK)
return retval;
retval = jtag_execute_queue();
if (retval != ERROR_OK)
return retval;
if (mmu)
cp15_control |= 0x1U;
if (d_u_cache || i_cache)
cp15_control |= 0x4U;
retval = arm720t_write_cp15(target, 0xee010f10, cp15_control);
return retval;
}
static int arm720t_post_debug_entry(struct target *target)
{
struct arm720t_common *arm720t = target_to_arm720(target);
int retval;
/* examine cp15 control reg */
retval = arm720t_read_cp15(target, 0xee110f10, &arm720t->cp15_control_reg);
if (retval != ERROR_OK)
return retval;
retval = jtag_execute_queue();
if (retval != ERROR_OK)
return retval;
LOG_DEBUG("cp15_control_reg: %8.8" PRIx32 "", arm720t->cp15_control_reg);
arm720t->armv4_5_mmu.mmu_enabled = (arm720t->cp15_control_reg & 0x1U) ? 1 : 0;
arm720t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = (arm720t->cp15_control_reg & 0x4U) ? 1 : 0;
arm720t->armv4_5_mmu.armv4_5_cache.i_cache_enabled = 0;
/* save i/d fault status and address register */
retval = arm720t_read_cp15(target, 0xee150f10, &arm720t->fsr_reg);
if (retval != ERROR_OK)
return retval;
retval = arm720t_read_cp15(target, 0xee160f10, &arm720t->far_reg);
if (retval != ERROR_OK)
return retval;
retval = jtag_execute_queue();
return retval;
}
static void arm720t_pre_restore_context(struct target *target)
{
struct arm720t_common *arm720t = target_to_arm720(target);
/* restore i/d fault status and address register */
arm720t_write_cp15(target, 0xee050f10, arm720t->fsr_reg);
arm720t_write_cp15(target, 0xee060f10, arm720t->far_reg);
}
static int arm720t_verify_pointer(struct command_context *cmd_ctx,
struct arm720t_common *arm720t)
{
if (arm720t->common_magic != ARM720T_COMMON_MAGIC) {
command_print(cmd_ctx, "target is not an ARM720");
return ERROR_TARGET_INVALID;
}
return ERROR_OK;
}
static int arm720t_arch_state(struct target *target)
{
struct arm720t_common *arm720t = target_to_arm720(target);
static const char *state[] = {
"disabled", "enabled"
};
arm_arch_state(target);
LOG_USER("MMU: %s, Cache: %s",
state[arm720t->armv4_5_mmu.mmu_enabled],
state[arm720t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled]);
return ERROR_OK;
}
static int arm720_mmu(struct target *target, int *enabled)
{
if (target->state != TARGET_HALTED) {
LOG_ERROR("%s: target not halted", __func__);
return ERROR_TARGET_INVALID;
}
*enabled = target_to_arm720(target)->armv4_5_mmu.mmu_enabled;
return ERROR_OK;
}
static int arm720_virt2phys(struct target *target,
uint32_t virtual, uint32_t *physical)
{
uint32_t cb;
struct arm720t_common *arm720t = target_to_arm720(target);
uint32_t ret;
int retval = armv4_5_mmu_translate_va(target,
&arm720t->armv4_5_mmu, virtual, &cb, &ret);
if (retval != ERROR_OK)
return retval;
*physical = ret;
return ERROR_OK;
}
static int arm720t_read_memory(struct target *target,
uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer)
{
int retval;
struct arm720t_common *arm720t = target_to_arm720(target);
/* disable cache, but leave MMU enabled */
if (arm720t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled) {
retval = arm720t_disable_mmu_caches(target, 0, 1, 0);
if (retval != ERROR_OK)
return retval;
}
retval = arm7_9_read_memory(target, address, size, count, buffer);
if (arm720t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled) {
retval = arm720t_enable_mmu_caches(target, 0, 1, 0);
if (retval != ERROR_OK)
return retval;
}
return retval;
}
static int arm720t_read_phys_memory(struct target *target,
uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer)
{
struct arm720t_common *arm720t = target_to_arm720(target);
return armv4_5_mmu_read_physical(target, &arm720t->armv4_5_mmu, address, size, count, buffer);
}
static int arm720t_write_phys_memory(struct target *target,
uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer)
{
struct arm720t_common *arm720t = target_to_arm720(target);
return armv4_5_mmu_write_physical(target, &arm720t->armv4_5_mmu, address, size, count, buffer);
}
static int arm720t_soft_reset_halt(struct target *target)
{
int retval = ERROR_OK;
struct arm720t_common *arm720t = target_to_arm720(target);
struct reg *dbg_stat = &arm720t->arm7_9_common
.eice_cache->reg_list[EICE_DBG_STAT];
struct arm *arm = &arm720t->arm7_9_common.arm;
retval = target_halt(target);
if (retval != ERROR_OK)
return retval;
long long then = timeval_ms();
int timeout;
while (!(timeout = ((timeval_ms()-then) > 1000))) {
if (buf_get_u32(dbg_stat->value, EICE_DBG_STATUS_DBGACK, 1) == 0) {
embeddedice_read_reg(dbg_stat);
retval = jtag_execute_queue();
if (retval != ERROR_OK)
return retval;
} else
break;
if (debug_level >= 3)
alive_sleep(100);
else
keep_alive();
}
if (timeout) {
LOG_ERROR("Failed to halt CPU after 1 sec");
return ERROR_TARGET_TIMEOUT;
}
target->state = TARGET_HALTED;
/* SVC, ARM state, IRQ and FIQ disabled */
uint32_t cpsr;
cpsr = buf_get_u32(arm->cpsr->value, 0, 32);
cpsr &= ~0xff;
cpsr |= 0xd3;
arm_set_cpsr(arm, cpsr);
arm->cpsr->dirty = 1;
/* start fetching from 0x0 */
buf_set_u32(arm->pc->value, 0, 32, 0x0);
arm->pc->dirty = 1;
arm->pc->valid = 1;
retval = arm720t_disable_mmu_caches(target, 1, 1, 1);
if (retval != ERROR_OK)
return retval;
arm720t->armv4_5_mmu.mmu_enabled = 0;
arm720t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = 0;
arm720t->armv4_5_mmu.armv4_5_cache.i_cache_enabled = 0;
retval = target_call_event_callbacks(target, TARGET_EVENT_HALTED);
if (retval != ERROR_OK)
return retval;
return ERROR_OK;
}
static int arm720t_init_target(struct command_context *cmd_ctx, struct target *target)
{
return arm7tdmi_init_target(cmd_ctx, target);
}
/* FIXME remove forward decls */
static int arm720t_mrc(struct target *target, int cpnum,
uint32_t op1, uint32_t op2,
uint32_t CRn, uint32_t CRm,
uint32_t *value);
static int arm720t_mcr(struct target *target, int cpnum,
uint32_t op1, uint32_t op2,
uint32_t CRn, uint32_t CRm,
uint32_t value);
static int arm720t_init_arch_info(struct target *target,
struct arm720t_common *arm720t, struct jtag_tap *tap)
{
struct arm7_9_common *arm7_9 = &arm720t->arm7_9_common;
arm7_9->arm.mrc = arm720t_mrc;
arm7_9->arm.mcr = arm720t_mcr;
arm7tdmi_init_arch_info(target, arm7_9, tap);
arm720t->common_magic = ARM720T_COMMON_MAGIC;
arm7_9->post_debug_entry = arm720t_post_debug_entry;
arm7_9->pre_restore_context = arm720t_pre_restore_context;
arm720t->armv4_5_mmu.armv4_5_cache.ctype = -1;
arm720t->armv4_5_mmu.get_ttb = arm720t_get_ttb;
arm720t->armv4_5_mmu.read_memory = arm7_9_read_memory;
arm720t->armv4_5_mmu.write_memory = arm7_9_write_memory;
arm720t->armv4_5_mmu.disable_mmu_caches = arm720t_disable_mmu_caches;
arm720t->armv4_5_mmu.enable_mmu_caches = arm720t_enable_mmu_caches;
arm720t->armv4_5_mmu.has_tiny_pages = 0;
arm720t->armv4_5_mmu.mmu_enabled = 0;
return ERROR_OK;
}
static int arm720t_target_create(struct target *target, Jim_Interp *interp)
{
struct arm720t_common *arm720t = calloc(1, sizeof(*arm720t));
arm720t->arm7_9_common.arm.is_armv4 = true;
return arm720t_init_arch_info(target, arm720t, target->tap);
}
COMMAND_HANDLER(arm720t_handle_cp15_command)
{
int retval;
struct target *target = get_current_target(CMD_CTX);
struct arm720t_common *arm720t = target_to_arm720(target);
retval = arm720t_verify_pointer(CMD_CTX, arm720t);
if (retval != ERROR_OK)
return retval;
if (target->state != TARGET_HALTED) {
command_print(CMD_CTX, "target must be stopped for \"%s\" command", CMD_NAME);
return ERROR_OK;
}
/* one or more argument, access a single register (write if second argument is given */
if (CMD_ARGC >= 1) {
uint32_t opcode;
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], opcode);
if (CMD_ARGC == 1) {
uint32_t value;
retval = arm720t_read_cp15(target, opcode, &value);
if (retval != ERROR_OK) {
command_print(CMD_CTX, "couldn't access cp15 with opcode 0x%8.8" PRIx32 "", opcode);
return ERROR_OK;
}
retval = jtag_execute_queue();
if (retval != ERROR_OK)
return retval;
command_print(CMD_CTX, "0x%8.8" PRIx32 ": 0x%8.8" PRIx32 "", opcode, value);
} else if (CMD_ARGC == 2) {
uint32_t value;
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value);
retval = arm720t_write_cp15(target, opcode, value);
if (retval != ERROR_OK) {
command_print(CMD_CTX, "couldn't access cp15 with opcode 0x%8.8" PRIx32 "", opcode);
return ERROR_OK;
}
command_print(CMD_CTX, "0x%8.8" PRIx32 ": 0x%8.8" PRIx32 "", opcode, value);
}
}
return ERROR_OK;
}
static int arm720t_mrc(struct target *target, int cpnum,
uint32_t op1, uint32_t op2,
uint32_t CRn, uint32_t CRm,
uint32_t *value)
{
if (cpnum != 15) {
LOG_ERROR("Only cp15 is supported");
return ERROR_FAIL;
}
/* read "to" r0 */
return arm720t_read_cp15(target,
ARMV4_5_MRC(cpnum, op1, 0, CRn, CRm, op2),
value);
}
static int arm720t_mcr(struct target *target, int cpnum,
uint32_t op1, uint32_t op2,
uint32_t CRn, uint32_t CRm,
uint32_t value)
{
if (cpnum != 15) {
LOG_ERROR("Only cp15 is supported");
return ERROR_FAIL;
}
/* write "from" r0 */
return arm720t_write_cp15(target,
ARMV4_5_MCR(cpnum, op1, 0, CRn, CRm, op2),
value);
}
static const struct command_registration arm720t_exec_command_handlers[] = {
{
.name = "cp15",
.handler = arm720t_handle_cp15_command,
.mode = COMMAND_EXEC,
/* prefer using less error-prone "arm mcr" or "arm mrc" */
.help = "display/modify cp15 register using ARM opcode"
" (DEPRECATED)",
.usage = "instruction [value]",
},
COMMAND_REGISTRATION_DONE
};
static const struct command_registration arm720t_command_handlers[] = {
{
.chain = arm7_9_command_handlers,
},
{
.name = "arm720t",
.mode = COMMAND_ANY,
.help = "arm720t command group",
.usage = "",
.chain = arm720t_exec_command_handlers,
},
COMMAND_REGISTRATION_DONE
};
/** Holds methods for ARM720 targets. */
struct target_type arm720t_target = {
.name = "arm720t",
.poll = arm7_9_poll,
.arch_state = arm720t_arch_state,
.halt = arm7_9_halt,
.resume = arm7_9_resume,
.step = arm7_9_step,
.assert_reset = arm7_9_assert_reset,
.deassert_reset = arm7_9_deassert_reset,
.soft_reset_halt = arm720t_soft_reset_halt,
.get_gdb_reg_list = arm_get_gdb_reg_list,
.read_memory = arm720t_read_memory,
.write_memory = arm7_9_write_memory,
.read_phys_memory = arm720t_read_phys_memory,
.write_phys_memory = arm720t_write_phys_memory,
.mmu = arm720_mmu,
.virt2phys = arm720_virt2phys,
.bulk_write_memory = arm7_9_bulk_write_memory,
.checksum_memory = arm_checksum_memory,
.blank_check_memory = arm_blank_check_memory,
.run_algorithm = armv4_5_run_algorithm,
.add_breakpoint = arm7_9_add_breakpoint,
.remove_breakpoint = arm7_9_remove_breakpoint,
.add_watchpoint = arm7_9_add_watchpoint,
.remove_watchpoint = arm7_9_remove_watchpoint,
.commands = arm720t_command_handlers,
.target_create = arm720t_target_create,
.init_target = arm720t_init_target,
.examine = arm7_9_examine,
.check_reset = arm7_9_check_reset,
};

View File

@ -0,0 +1,43 @@
/***************************************************************************
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef ARM720T_H
#define ARM720T_H
#include "arm7tdmi.h"
#include "armv4_5_mmu.h"
#define ARM720T_COMMON_MAGIC 0xa720a720
struct arm720t_common {
struct arm7_9_common arm7_9_common;
uint32_t common_magic;
struct armv4_5_mmu_common armv4_5_mmu;
uint32_t cp15_control_reg;
uint32_t fsr_reg;
uint32_t far_reg;
};
static inline struct arm720t_common *target_to_arm720(struct target *target)
{
return container_of(target->arch_info, struct arm720t_common, arm7_9_common.arm);
}
#endif /* ARM720T_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,179 @@
/***************************************************************************
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* Copyright (C) 2007,2008 Øyvind Harboe *
* oyvind.harboe@zylin.com *
* *
* Copyright (C) 2008 by Spencer Oliver *
* spen@spen-soft.co.uk *
* *
* Copyright (C) 2008 by Hongtao Zheng *
* hontor@126.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef ARM7_9_COMMON_H
#define ARM7_9_COMMON_H
#include "arm.h"
#include "arm_jtag.h"
#define ARM7_9_COMMON_MAGIC 0x0a790a79 /**< */
/**
* Structure for items that are common between both ARM7 and ARM9 targets.
*/
struct arm7_9_common {
struct arm arm;
uint32_t common_magic;
struct arm_jtag jtag_info; /**< JTAG information for target */
struct reg_cache *eice_cache; /**< Embedded ICE register cache */
uint32_t arm_bkpt; /**< ARM breakpoint instruction */
uint16_t thumb_bkpt; /**< Thumb breakpoint instruction */
int sw_breakpoints_added; /**< Specifies which watchpoint software breakpoints are setup on */
int sw_breakpoint_count; /**< keep track of number of software breakpoints we have set */
int breakpoint_count; /**< Current number of set breakpoints */
int wp_available; /**< Current number of available watchpoint units */
int wp_available_max; /**< Maximum number of available watchpoint units */
int wp0_used; /**< Specifies if and how watchpoint unit 0 is used */
int wp1_used; /**< Specifies if and how watchpoint unit 1 is used */
int wp1_used_default; /**< Specifies if and how watchpoint unit 1 is used by default */
int dbgreq_adjust_pc; /**< Amount of PC adjustment caused by a DBGREQ */
bool use_dbgrq; /**< Specifies if DBGRQ should be used to halt the target */
bool need_bypass_before_restart; /**< Specifies if there should be a bypass before a JTAG restart */
bool has_single_step;
bool has_monitor_mode;
bool has_vector_catch; /**< Specifies if the target has a reset vector catch */
bool debug_entry_from_reset; /**< Specifies if debug entry was from a reset */
bool fast_memory_access;
bool dcc_downloads;
struct working_area *dcc_working_area;
int (*examine_debug_reason)(struct target *target);
/**< Function for determining why debug state was entered */
void (*change_to_arm)(struct target *target, uint32_t *r0, uint32_t *pc);
/**< Function for changing from Thumb to ARM mode */
void (*read_core_regs)(struct target *target, uint32_t mask, uint32_t *core_regs[16]);
/**< Function for reading the core registers */
void (*read_core_regs_target_buffer)(struct target *target, uint32_t mask,
void *buffer, int size);
void (*read_xpsr)(struct target *target, uint32_t *xpsr, int spsr);
/**< Function for reading CPSR or SPSR */
void (*write_xpsr)(struct target *target, uint32_t xpsr, int spsr);
/**< Function for writing to CPSR or SPSR */
void (*write_xpsr_im8)(struct target *target, uint8_t xpsr_im, int rot, int spsr);
/**< Function for writing an immediate value to CPSR or SPSR */
void (*write_core_regs)(struct target *target, uint32_t mask, uint32_t core_regs[16]);
void (*load_word_regs)(struct target *target, uint32_t mask);
void (*load_hword_reg)(struct target *target, int num);
void (*load_byte_reg)(struct target *target, int num);
void (*store_word_regs)(struct target *target, uint32_t mask);
void (*store_hword_reg)(struct target *target, int num);
void (*store_byte_reg)(struct target *target, int num);
void (*write_pc)(struct target *target, uint32_t pc);
/**< Function for writing to the program counter */
void (*branch_resume)(struct target *target);
void (*branch_resume_thumb)(struct target *target);
void (*enable_single_step)(struct target *target, uint32_t next_pc);
void (*disable_single_step)(struct target *target);
void (*set_special_dbgrq)(struct target *target);
/**< Function for setting DBGRQ if the normal way won't work */
int (*post_debug_entry)(struct target *target);
/**< Callback function called after entering debug mode */
void (*pre_restore_context)(struct target *target);
/**< Callback function called before restoring the processor context */
};
static inline struct arm7_9_common *target_to_arm7_9(struct target *target)
{
return container_of(target->arch_info, struct arm7_9_common, arm);
}
static inline bool is_arm7_9(struct arm7_9_common *arm7_9)
{
return arm7_9->common_magic == ARM7_9_COMMON_MAGIC;
}
extern const struct command_registration arm7_9_command_handlers[];
int arm7_9_poll(struct target *target);
int arm7_9_target_request_data(struct target *target, uint32_t size, uint8_t *buffer);
int arm7_9_assert_reset(struct target *target);
int arm7_9_deassert_reset(struct target *target);
int arm7_9_reset_request_halt(struct target *target);
int arm7_9_early_halt(struct target *target);
int arm7_9_soft_reset_halt(struct target *target);
int arm7_9_halt(struct target *target);
int arm7_9_resume(struct target *target, int current, uint32_t address,
int handle_breakpoints, int debug_execution);
int arm7_9_step(struct target *target, int current, uint32_t address,
int handle_breakpoints);
int arm7_9_read_memory(struct target *target, uint32_t address,
uint32_t size, uint32_t count, uint8_t *buffer);
int arm7_9_write_memory(struct target *target, uint32_t address,
uint32_t size, uint32_t count, const uint8_t *buffer);
int arm7_9_bulk_write_memory(struct target *target, uint32_t address,
uint32_t count, const uint8_t *buffer);
int arm7_9_run_algorithm(struct target *target, int num_mem_params,
struct mem_param *mem_params, int num_reg_prams,
struct reg_param *reg_param, uint32_t entry_point, void *arch_info);
int arm7_9_add_breakpoint(struct target *target, struct breakpoint *breakpoint);
int arm7_9_remove_breakpoint(struct target *target, struct breakpoint *breakpoint);
int arm7_9_add_watchpoint(struct target *target, struct watchpoint *watchpoint);
int arm7_9_remove_watchpoint(struct target *target, struct watchpoint *watchpoint);
void arm7_9_enable_eice_step(struct target *target, uint32_t next_pc);
void arm7_9_disable_eice_step(struct target *target);
int arm7_9_execute_sys_speed(struct target *target);
int arm7_9_init_arch_info(struct target *target, struct arm7_9_common *arm7_9);
int arm7_9_examine(struct target *target);
int arm7_9_check_reset(struct target *target);
int arm7_9_endianness_callback(jtag_callback_data_t pu8_in,
jtag_callback_data_t i_size, jtag_callback_data_t i_be,
jtag_callback_data_t i_flip);
#endif /* ARM7_9_COMMON_H */

View File

@ -0,0 +1,715 @@
/***************************************************************************
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* Copyright (C) 2008 by Spencer Oliver *
* spen@spen-soft.co.uk *
* *
* Copyright (C) 2007,2008 Øyvind Harboe *
* oyvind.harboe@zylin.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "arm7tdmi.h"
#include "target_type.h"
#include "register.h"
#include "arm_opcodes.h"
/*
* For information about ARM7TDMI, see ARM DDI 0210C (r4p1)
* or ARM DDI 0029G (r3). "Debug In Depth", Appendix B,
* covers JTAG support.
*/
#if 0
#define _DEBUG_INSTRUCTION_EXECUTION_
#endif
static int arm7tdmi_examine_debug_reason(struct target *target)
{
int retval = ERROR_OK;
struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
/* only check the debug reason if we don't know it already */
if ((target->debug_reason != DBG_REASON_DBGRQ)
&& (target->debug_reason != DBG_REASON_SINGLESTEP)) {
struct scan_field fields[2];
uint8_t databus[4];
uint8_t breakpoint;
fields[0].num_bits = 1;
fields[0].out_value = NULL;
fields[0].in_value = &breakpoint;
fields[1].num_bits = 32;
fields[1].out_value = NULL;
fields[1].in_value = databus;
retval = arm_jtag_scann(&arm7_9->jtag_info, 0x1, TAP_DRPAUSE);
if (retval != ERROR_OK)
return retval;
retval = arm_jtag_set_instr(&arm7_9->jtag_info, arm7_9->jtag_info.intest_instr, NULL, TAP_DRPAUSE);
if (retval != ERROR_OK)
return retval;
jtag_add_dr_scan(arm7_9->jtag_info.tap, 2, fields, TAP_DRPAUSE);
retval = jtag_execute_queue();
if (retval != ERROR_OK)
return retval;
fields[0].in_value = NULL;
fields[0].out_value = &breakpoint;
fields[1].in_value = NULL;
fields[1].out_value = databus;
jtag_add_dr_scan(arm7_9->jtag_info.tap, 2, fields, TAP_DRPAUSE);
if (breakpoint & 1)
target->debug_reason = DBG_REASON_WATCHPOINT;
else
target->debug_reason = DBG_REASON_BREAKPOINT;
}
return ERROR_OK;
}
static const int arm7tdmi_num_bits[] = {1, 32};
static inline int arm7tdmi_clock_out_inner(struct arm_jtag *jtag_info, uint32_t out, int breakpoint)
{
uint32_t values[2] = {breakpoint, flip_u32(out, 32)};
jtag_add_dr_out(jtag_info->tap,
2,
arm7tdmi_num_bits,
values,
TAP_DRPAUSE);
jtag_add_runtest(0, TAP_DRPAUSE);
return ERROR_OK;
}
/* put an instruction in the ARM7TDMI pipeline or write the data bus,
* and optionally read data
*
* FIXME remove the unused "deprecated" parameter
*/
static inline int arm7tdmi_clock_out(struct arm_jtag *jtag_info,
uint32_t out, uint32_t *deprecated, int breakpoint)
{
int retval;
retval = arm_jtag_scann(jtag_info, 0x1, TAP_DRPAUSE);
if (retval != ERROR_OK)
return retval;
retval = arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL, TAP_DRPAUSE);
if (retval != ERROR_OK)
return retval;
return arm7tdmi_clock_out_inner(jtag_info, out, breakpoint);
}
/* clock the target, reading the databus */
static int arm7tdmi_clock_data_in(struct arm_jtag *jtag_info, uint32_t *in)
{
int retval = ERROR_OK;
struct scan_field fields[2];
retval = arm_jtag_scann(jtag_info, 0x1, TAP_DRPAUSE);
if (retval != ERROR_OK)
return retval;
retval = arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL, TAP_DRPAUSE);
if (retval != ERROR_OK)
return retval;
fields[0].num_bits = 1;
fields[0].out_value = NULL;
fields[0].in_value = NULL;
fields[1].num_bits = 32;
fields[1].out_value = NULL;
fields[1].in_value = (uint8_t *)in;
jtag_add_dr_scan(jtag_info->tap, 2, fields, TAP_DRPAUSE);
jtag_add_callback(arm7flip32, (jtag_callback_data_t)in);
jtag_add_runtest(0, TAP_DRPAUSE);
#ifdef _DEBUG_INSTRUCTION_EXECUTION_
retval = jtag_execute_queue();
if (retval != ERROR_OK)
return retval;
if (in)
LOG_DEBUG("in: 0x%8.8x", *in);
else
LOG_ERROR("BUG: called with in == NULL");
#endif
return ERROR_OK;
}
/* clock the target, and read the databus
* the *in pointer points to a buffer where elements of 'size' bytes
* are stored in big (be == 1) or little (be == 0) endianness
*/
static int arm7tdmi_clock_data_in_endianness(struct arm_jtag *jtag_info,
void *in, int size, int be)
{
int retval = ERROR_OK;
struct scan_field fields[3];
retval = arm_jtag_scann(jtag_info, 0x1, TAP_DRPAUSE);
if (retval != ERROR_OK)
return retval;
retval = arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL, TAP_DRPAUSE);
if (retval != ERROR_OK)
return retval;
fields[0].num_bits = 1;
fields[0].out_value = NULL;
fields[0].in_value = NULL;
if (size == 4) {
fields[1].num_bits = 32;
fields[1].out_value = NULL;
fields[1].in_value = in;
} else {
/* Discard irrelevant bits of the scan, making sure we don't write more
* than size bytes to in */
fields[1].num_bits = 32 - size * 8;
fields[1].out_value = NULL;
fields[1].in_value = NULL;
fields[2].num_bits = size * 8;
fields[2].out_value = NULL;
fields[2].in_value = in;
}
jtag_add_dr_scan(jtag_info->tap, size == 4 ? 2 : 3, fields, TAP_DRPAUSE);
jtag_add_callback4(arm7_9_endianness_callback,
(jtag_callback_data_t)in,
(jtag_callback_data_t)size,
(jtag_callback_data_t)be,
(jtag_callback_data_t)1);
jtag_add_runtest(0, TAP_DRPAUSE);
#ifdef _DEBUG_INSTRUCTION_EXECUTION_
{
retval = jtag_execute_queue();
if (retval != ERROR_OK)
return retval;
if (in)
LOG_DEBUG("in: 0x%8.8x", *(uint32_t *)in);
else
LOG_ERROR("BUG: called with in == NULL");
}
#endif
return ERROR_OK;
}
static void arm7tdmi_change_to_arm(struct target *target,
uint32_t *r0, uint32_t *pc)
{
struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
struct arm_jtag *jtag_info = &arm7_9->jtag_info;
/* save r0 before using it and put system in ARM state
* to allow common handling of ARM and THUMB debugging */
/* fetch STR r0, [r0] */
arm7tdmi_clock_out(jtag_info, ARMV4_5_T_STR(0, 0), NULL, 0);
arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
/* nothing fetched, STR r0, [r0] in Execute (2) */
arm7tdmi_clock_data_in(jtag_info, r0);
/* MOV r0, r15 fetched, STR in Decode */
arm7tdmi_clock_out(jtag_info, ARMV4_5_T_MOV(0, 15), NULL, 0);
arm7tdmi_clock_out(jtag_info, ARMV4_5_T_STR(0, 0), NULL, 0);
arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
/* nothing fetched, STR r0, [r0] in Execute (2) */
arm7tdmi_clock_data_in(jtag_info, pc);
/* use pc-relative LDR to clear r0[1:0] (for switch to ARM mode) */
arm7tdmi_clock_out(jtag_info, ARMV4_5_T_LDR_PCREL(0), NULL, 0);
arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
/* nothing fetched, data for LDR r0, [PC, #0] */
arm7tdmi_clock_out(jtag_info, 0x0, NULL, 0);
/* nothing fetched, data from previous cycle is written to register */
arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
/* fetch BX */
arm7tdmi_clock_out(jtag_info, ARMV4_5_T_BX(0), NULL, 0);
/* NOP fetched, BX in Decode, MOV in Execute */
arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
/* NOP fetched, BX in Execute (1) */
arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
jtag_execute_queue();
/* fix program counter:
* MOV r0, r15 was the 4th instruction (+6)
* reading PC in Thumb state gives address of instruction + 4
*/
*pc -= 0xa;
}
/* FIX!!! is this a potential performance bottleneck w.r.t. requiring too many
* roundtrips when jtag_execute_queue() has a large overhead(e.g. for USB)s?
*
* The solution is to arrange for a large out/in scan in this loop and
* and convert data afterwards.
*/
static void arm7tdmi_read_core_regs(struct target *target,
uint32_t mask, uint32_t *core_regs[16])
{
int i;
struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
struct arm_jtag *jtag_info = &arm7_9->jtag_info;
/* STMIA r0-15, [r0] at debug speed
* register values will start to appear on 4th DCLK
*/
arm7tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask & 0xffff, 0, 0), NULL, 0);
/* fetch NOP, STM in DECODE stage */
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
/* fetch NOP, STM in EXECUTE stage (1st cycle) */
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
for (i = 0; i <= 15; i++) {
if (mask & (1 << i))
/* nothing fetched, STM still in EXECUTE (1 + i cycle) */
arm7tdmi_clock_data_in(jtag_info, core_regs[i]);
}
}
static void arm7tdmi_read_core_regs_target_buffer(struct target *target,
uint32_t mask, void *buffer, int size)
{
int i;
struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
struct arm_jtag *jtag_info = &arm7_9->jtag_info;
int be = (target->endianness == TARGET_BIG_ENDIAN) ? 1 : 0;
uint32_t *buf_u32 = buffer;
uint16_t *buf_u16 = buffer;
uint8_t *buf_u8 = buffer;
/* STMIA r0-15, [r0] at debug speed
* register values will start to appear on 4th DCLK
*/
arm7tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask & 0xffff, 0, 0), NULL, 0);
/* fetch NOP, STM in DECODE stage */
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
/* fetch NOP, STM in EXECUTE stage (1st cycle) */
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
for (i = 0; i <= 15; i++) {
/* nothing fetched, STM still in EXECUTE (1 + i cycle), read databus */
if (mask & (1 << i)) {
switch (size) {
case 4:
arm7tdmi_clock_data_in_endianness(jtag_info, buf_u32++, 4, be);
break;
case 2:
arm7tdmi_clock_data_in_endianness(jtag_info, buf_u16++, 2, be);
break;
case 1:
arm7tdmi_clock_data_in_endianness(jtag_info, buf_u8++, 1, be);
break;
}
}
}
}
static void arm7tdmi_read_xpsr(struct target *target, uint32_t *xpsr, int spsr)
{
struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
struct arm_jtag *jtag_info = &arm7_9->jtag_info;
/* MRS r0, cpsr */
arm7tdmi_clock_out(jtag_info, ARMV4_5_MRS(0, spsr & 1), NULL, 0);
/* STR r0, [r15] */
arm7tdmi_clock_out(jtag_info, ARMV4_5_STR(0, 15), NULL, 0);
/* fetch NOP, STR in DECODE stage */
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
/* fetch NOP, STR in EXECUTE stage (1st cycle) */
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
/* nothing fetched, STR still in EXECUTE (2nd cycle) */
arm7tdmi_clock_data_in(jtag_info, xpsr);
}
static void arm7tdmi_write_xpsr(struct target *target, uint32_t xpsr, int spsr)
{
struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
struct arm_jtag *jtag_info = &arm7_9->jtag_info;
LOG_DEBUG("xpsr: %8.8" PRIx32 ", spsr: %i", xpsr, spsr);
/* MSR1 fetched */
arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM(xpsr & 0xff, 0, 1, spsr), NULL, 0);
/* MSR2 fetched, MSR1 in DECODE */
arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff00) >> 8, 0xc, 2, spsr), NULL, 0);
/* MSR3 fetched, MSR1 in EXECUTE (1), MSR2 in DECODE */
arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff0000) >> 16, 0x8, 4, spsr), NULL, 0);
/* nothing fetched, MSR1 in EXECUTE (2) */
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
/* MSR4 fetched, MSR2 in EXECUTE (1), MSR3 in DECODE */
arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff000000) >> 24, 0x4, 8, spsr), NULL, 0);
/* nothing fetched, MSR2 in EXECUTE (2) */
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
/* NOP fetched, MSR3 in EXECUTE (1), MSR4 in DECODE */
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
/* nothing fetched, MSR3 in EXECUTE (2) */
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
/* NOP fetched, MSR4 in EXECUTE (1) */
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
/* nothing fetched, MSR4 in EXECUTE (2) */
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
}
static void arm7tdmi_write_xpsr_im8(struct target *target,
uint8_t xpsr_im, int rot, int spsr)
{
struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
struct arm_jtag *jtag_info = &arm7_9->jtag_info;
LOG_DEBUG("xpsr_im: %2.2x, rot: %i, spsr: %i", xpsr_im, rot, spsr);
/* MSR fetched */
arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM(xpsr_im, rot, 1, spsr), NULL, 0);
/* NOP fetched, MSR in DECODE */
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
/* NOP fetched, MSR in EXECUTE (1) */
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
/* nothing fetched, MSR in EXECUTE (2) */
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
}
static void arm7tdmi_write_core_regs(struct target *target,
uint32_t mask, uint32_t core_regs[16])
{
int i;
struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
struct arm_jtag *jtag_info = &arm7_9->jtag_info;
/* LDMIA r0-15, [r0] at debug speed
* register values will start to appear on 4th DCLK
*/
arm7tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, mask & 0xffff, 0, 0), NULL, 0);
/* fetch NOP, LDM in DECODE stage */
arm7tdmi_clock_out_inner(jtag_info, ARMV4_5_NOP, 0);
/* fetch NOP, LDM in EXECUTE stage (1st cycle) */
arm7tdmi_clock_out_inner(jtag_info, ARMV4_5_NOP, 0);
for (i = 0; i <= 15; i++) {
if (mask & (1 << i))
/* nothing fetched, LDM still in EXECUTE (1 + i cycle) */
arm7tdmi_clock_out_inner(jtag_info, core_regs[i], 0);
}
arm7tdmi_clock_out_inner(jtag_info, ARMV4_5_NOP, 0);
}
static void arm7tdmi_load_word_regs(struct target *target, uint32_t mask)
{
struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
struct arm_jtag *jtag_info = &arm7_9->jtag_info;
/* put system-speed load-multiple into the pipeline */
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1);
arm7tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, mask & 0xffff, 0, 1), NULL, 0);
}
static void arm7tdmi_load_hword_reg(struct target *target, int num)
{
struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
struct arm_jtag *jtag_info = &arm7_9->jtag_info;
/* put system-speed load half-word into the pipeline */
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1);
arm7tdmi_clock_out(jtag_info, ARMV4_5_LDRH_IP(num, 0), NULL, 0);
}
static void arm7tdmi_load_byte_reg(struct target *target, int num)
{
struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
struct arm_jtag *jtag_info = &arm7_9->jtag_info;
/* put system-speed load byte into the pipeline */
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1);
arm7tdmi_clock_out(jtag_info, ARMV4_5_LDRB_IP(num, 0), NULL, 0);
}
static void arm7tdmi_store_word_regs(struct target *target, uint32_t mask)
{
struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
struct arm_jtag *jtag_info = &arm7_9->jtag_info;
/* put system-speed store-multiple into the pipeline */
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1);
arm7tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask, 0, 1), NULL, 0);
}
static void arm7tdmi_store_hword_reg(struct target *target, int num)
{
struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
struct arm_jtag *jtag_info = &arm7_9->jtag_info;
/* put system-speed store half-word into the pipeline */
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1);
arm7tdmi_clock_out(jtag_info, ARMV4_5_STRH_IP(num, 0), NULL, 0);
}
static void arm7tdmi_store_byte_reg(struct target *target, int num)
{
struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
struct arm_jtag *jtag_info = &arm7_9->jtag_info;
/* put system-speed store byte into the pipeline */
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1);
arm7tdmi_clock_out(jtag_info, ARMV4_5_STRB_IP(num, 0), NULL, 0);
}
static void arm7tdmi_write_pc(struct target *target, uint32_t pc)
{
struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
struct arm_jtag *jtag_info = &arm7_9->jtag_info;
/* LDMIA r0-15, [r0] at debug speed
* register values will start to appear on 4th DCLK
*/
arm7tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, 0x8000, 0, 0), NULL, 0);
/* fetch NOP, LDM in DECODE stage */
arm7tdmi_clock_out_inner(jtag_info, ARMV4_5_NOP, 0);
/* fetch NOP, LDM in EXECUTE stage (1st cycle) */
arm7tdmi_clock_out_inner(jtag_info, ARMV4_5_NOP, 0);
/* nothing fetched, LDM in EXECUTE stage (1st cycle) load register */
arm7tdmi_clock_out_inner(jtag_info, pc, 0);
/* nothing fetched, LDM in EXECUTE stage (2nd cycle) load register */
arm7tdmi_clock_out_inner(jtag_info, ARMV4_5_NOP, 0);
/* nothing fetched, LDM in EXECUTE stage (3rd cycle) load register */
arm7tdmi_clock_out_inner(jtag_info, ARMV4_5_NOP, 0);
/* fetch NOP, LDM in EXECUTE stage (4th cycle) */
arm7tdmi_clock_out_inner(jtag_info, ARMV4_5_NOP, 0);
/* fetch NOP, LDM in EXECUTE stage (5th cycle) */
arm7tdmi_clock_out_inner(jtag_info, ARMV4_5_NOP, 0);
}
static void arm7tdmi_branch_resume(struct target *target)
{
struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
struct arm_jtag *jtag_info = &arm7_9->jtag_info;
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1);
arm7tdmi_clock_out_inner(jtag_info, ARMV4_5_B(0xfffffa, 0), 0);
}
static void arm7tdmi_branch_resume_thumb(struct target *target)
{
struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
struct arm *arm = &arm7_9->arm;
struct arm_jtag *jtag_info = &arm7_9->jtag_info;
struct reg *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT];
LOG_DEBUG("-");
/* LDMIA r0, [r0] at debug speed
* register values will start to appear on 4th DCLK
*/
arm7tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, 0x1, 0, 0), NULL, 0);
/* fetch NOP, LDM in DECODE stage */
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
/* fetch NOP, LDM in EXECUTE stage (1st cycle) */
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
/* nothing fetched, LDM in EXECUTE stage (2nd cycle) */
arm7tdmi_clock_out(jtag_info,
buf_get_u32(arm->pc->value, 0, 32) | 1, NULL, 0);
/* nothing fetched, LDM in EXECUTE stage (3rd cycle) */
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
/* Branch and eXchange */
arm7tdmi_clock_out(jtag_info, ARMV4_5_BX(0), NULL, 0);
embeddedice_read_reg(dbg_stat);
/* fetch NOP, BX in DECODE stage */
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
/* target is now in Thumb state */
embeddedice_read_reg(dbg_stat);
/* fetch NOP, BX in EXECUTE stage (1st cycle) */
arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
/* target is now in Thumb state */
embeddedice_read_reg(dbg_stat);
/* load r0 value */
arm7tdmi_clock_out(jtag_info, ARMV4_5_T_LDR_PCREL(0), NULL, 0);
/* fetch NOP, LDR in Decode */
arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
/* fetch NOP, LDR in Execute */
arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
/* nothing fetched, LDR in EXECUTE stage (2nd cycle) */
arm7tdmi_clock_out(jtag_info, buf_get_u32(arm->core_cache->reg_list[0].value, 0, 32), NULL, 0);
/* nothing fetched, LDR in EXECUTE stage (3rd cycle) */
arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
embeddedice_read_reg(dbg_stat);
arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 1);
arm7tdmi_clock_out(jtag_info, ARMV4_5_T_B(0x7f8), NULL, 0);
}
static void arm7tdmi_build_reg_cache(struct target *target)
{
struct reg_cache **cache_p = register_get_last_cache_p(&target->reg_cache);
struct arm *arm = target_to_arm(target);
(*cache_p) = arm_build_reg_cache(target, arm);
}
int arm7tdmi_init_target(struct command_context *cmd_ctx, struct target *target)
{
arm7tdmi_build_reg_cache(target);
return ERROR_OK;
}
int arm7tdmi_init_arch_info(struct target *target,
struct arm7_9_common *arm7_9, struct jtag_tap *tap)
{
/* prepare JTAG information for the new target */
arm7_9->jtag_info.tap = tap;
arm7_9->jtag_info.scann_size = 4;
/* register arch-specific functions */
arm7_9->examine_debug_reason = arm7tdmi_examine_debug_reason;
arm7_9->change_to_arm = arm7tdmi_change_to_arm;
arm7_9->read_core_regs = arm7tdmi_read_core_regs;
arm7_9->read_core_regs_target_buffer = arm7tdmi_read_core_regs_target_buffer;
arm7_9->read_xpsr = arm7tdmi_read_xpsr;
arm7_9->write_xpsr = arm7tdmi_write_xpsr;
arm7_9->write_xpsr_im8 = arm7tdmi_write_xpsr_im8;
arm7_9->write_core_regs = arm7tdmi_write_core_regs;
arm7_9->load_word_regs = arm7tdmi_load_word_regs;
arm7_9->load_hword_reg = arm7tdmi_load_hword_reg;
arm7_9->load_byte_reg = arm7tdmi_load_byte_reg;
arm7_9->store_word_regs = arm7tdmi_store_word_regs;
arm7_9->store_hword_reg = arm7tdmi_store_hword_reg;
arm7_9->store_byte_reg = arm7tdmi_store_byte_reg;
arm7_9->write_pc = arm7tdmi_write_pc;
arm7_9->branch_resume = arm7tdmi_branch_resume;
arm7_9->branch_resume_thumb = arm7tdmi_branch_resume_thumb;
arm7_9->enable_single_step = arm7_9_enable_eice_step;
arm7_9->disable_single_step = arm7_9_disable_eice_step;
arm7_9->post_debug_entry = NULL;
arm7_9->pre_restore_context = NULL;
/* initialize arch-specific breakpoint handling */
arm7_9->arm_bkpt = 0xdeeedeee;
arm7_9->thumb_bkpt = 0xdeee;
arm7_9->dbgreq_adjust_pc = 2;
arm7_9_init_arch_info(target, arm7_9);
return ERROR_OK;
}
static int arm7tdmi_target_create(struct target *target, Jim_Interp *interp)
{
struct arm7_9_common *arm7_9;
arm7_9 = calloc(1, sizeof(struct arm7_9_common));
arm7tdmi_init_arch_info(target, arm7_9, target->tap);
arm7_9->arm.is_armv4 = true;
return ERROR_OK;
}
/** Holds methods for ARM7TDMI targets. */
struct target_type arm7tdmi_target = {
.name = "arm7tdmi",
.poll = arm7_9_poll,
.arch_state = arm_arch_state,
.target_request_data = arm7_9_target_request_data,
.halt = arm7_9_halt,
.resume = arm7_9_resume,
.step = arm7_9_step,
.assert_reset = arm7_9_assert_reset,
.deassert_reset = arm7_9_deassert_reset,
.soft_reset_halt = arm7_9_soft_reset_halt,
.get_gdb_reg_list = arm_get_gdb_reg_list,
.read_memory = arm7_9_read_memory,
.write_memory = arm7_9_write_memory,
.bulk_write_memory = arm7_9_bulk_write_memory,
.checksum_memory = arm_checksum_memory,
.blank_check_memory = arm_blank_check_memory,
.run_algorithm = armv4_5_run_algorithm,
.add_breakpoint = arm7_9_add_breakpoint,
.remove_breakpoint = arm7_9_remove_breakpoint,
.add_watchpoint = arm7_9_add_watchpoint,
.remove_watchpoint = arm7_9_remove_watchpoint,
.commands = arm7_9_command_handlers,
.target_create = arm7tdmi_target_create,
.init_target = arm7tdmi_init_target,
.examine = arm7_9_examine,
.check_reset = arm7_9_check_reset,
};

View File

@ -0,0 +1,34 @@
/***************************************************************************
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* Copyright (C) 2008 by Spencer Oliver *
* spen@spen-soft.co.uk *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef ARM7TDMI_H
#define ARM7TDMI_H
#include "embeddedice.h"
int arm7tdmi_init_arch_info(struct target *target,
struct arm7_9_common *arm7_9, struct jtag_tap *tap);
int arm7tdmi_init_target(struct command_context *cmd_ctx,
struct target *target);
#endif /* ARM7TDMI_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,73 @@
/***************************************************************************
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef ARM920T_H
#define ARM920T_H
#include "arm9tdmi.h"
#include "armv4_5_mmu.h"
#define ARM920T_COMMON_MAGIC 0xa920a920
struct arm920t_common {
struct arm7_9_common arm7_9_common;
uint32_t common_magic;
struct armv4_5_mmu_common armv4_5_mmu;
uint32_t cp15_control_reg;
uint32_t d_fsr;
uint32_t i_fsr;
uint32_t d_far;
uint32_t i_far;
int preserve_cache;
};
static inline struct arm920t_common *target_to_arm920(struct target *target)
{
return container_of(target->arch_info, struct arm920t_common, arm7_9_common.arm);
}
struct arm920t_cache_line {
uint32_t cam;
uint32_t data[8];
};
struct arm920t_tlb_entry {
uint32_t cam;
uint32_t ram1;
uint32_t ram2;
};
int arm920t_arch_state(struct target *target);
int arm920t_soft_reset_halt(struct target *target);
int arm920t_read_memory(struct target *target,
uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer);
int arm920t_write_memory(struct target *target,
uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer);
int arm920t_post_debug_entry(struct target *target);
void arm920t_pre_restore_context(struct target *target);
int arm920t_get_ttb(struct target *target, uint32_t *result);
int arm920t_disable_mmu_caches(struct target *target,
int mmu, int d_u_cache, int i_cache);
int arm920t_enable_mmu_caches(struct target *target,
int mmu, int d_u_cache, int i_cache);
extern const struct command_registration arm920t_command_handlers[];
#endif /* ARM920T_H */

View File

@ -0,0 +1,834 @@
/***************************************************************************
* Copyright (C) 2007 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* Copyright (C) 2007,2008,2009 by Øyvind Harboe *
* oyvind.harboe@zylin.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "arm926ejs.h"
#include <helper/time_support.h>
#include "target_type.h"
#include "register.h"
#include "arm_opcodes.h"
/*
* The ARM926 is built around the ARM9EJ-S core, and most JTAG docs
* are in the ARM9EJ-S Technical Reference Manual (ARM DDI 0222B) not
* the ARM926 manual (ARM DDI 0198E). The scan chains are:
*
* 1 ... core debugging
* 2 ... EmbeddedICE
* 3 ... external boundary scan (SoC-specific, unused here)
* 6 ... ETM
* 15 ... coprocessor 15
*/
#if 0
#define _DEBUG_INSTRUCTION_EXECUTION_
#endif
#define ARM926EJS_CP15_ADDR(opcode_1, opcode_2, CRn, CRm) ((opcode_1 << 11) | (opcode_2 << 8) | (CRn << 4) | (CRm << 0))
static int arm926ejs_cp15_read(struct target *target, uint32_t op1, uint32_t op2,
uint32_t CRn, uint32_t CRm, uint32_t *value)
{
int retval = ERROR_OK;
struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
struct arm_jtag *jtag_info = &arm7_9->jtag_info;
uint32_t address = ARM926EJS_CP15_ADDR(op1, op2, CRn, CRm);
struct scan_field fields[4];
uint8_t address_buf[2] = {0, 0};
uint8_t nr_w_buf = 0;
uint8_t access_t = 1;
buf_set_u32(address_buf, 0, 14, address);
retval = arm_jtag_scann(jtag_info, 0xf, TAP_IDLE);
if (retval != ERROR_OK)
return retval;
retval = arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL, TAP_IDLE);
if (retval != ERROR_OK)
return retval;
fields[0].num_bits = 32;
fields[0].out_value = NULL;
fields[0].in_value = (uint8_t *)value;
fields[1].num_bits = 1;
fields[1].out_value = &access_t;
fields[1].in_value = &access_t;
fields[2].num_bits = 14;
fields[2].out_value = address_buf;
fields[2].in_value = NULL;
fields[3].num_bits = 1;
fields[3].out_value = &nr_w_buf;
fields[3].in_value = NULL;
jtag_add_dr_scan(jtag_info->tap, 4, fields, TAP_IDLE);
long long then = timeval_ms();
for (;;) {
/* rescan with NOP, to wait for the access to complete */
access_t = 0;
nr_w_buf = 0;
jtag_add_dr_scan(jtag_info->tap, 4, fields, TAP_IDLE);
jtag_add_callback(arm_le_to_h_u32, (jtag_callback_data_t)value);
retval = jtag_execute_queue();
if (retval != ERROR_OK)
return retval;
if (buf_get_u32(&access_t, 0, 1) == 1)
break;
/* 10ms timeout */
if ((timeval_ms()-then) > 10) {
LOG_ERROR("cp15 read operation timed out");
return ERROR_FAIL;
}
}
#ifdef _DEBUG_INSTRUCTION_EXECUTION_
LOG_DEBUG("addr: 0x%x value: %8.8x", address, *value);
#endif
retval = arm_jtag_set_instr(jtag_info, 0xc, NULL, TAP_IDLE);
if (retval != ERROR_OK)
return retval;
return ERROR_OK;
}
static int arm926ejs_mrc(struct target *target, int cpnum, uint32_t op1,
uint32_t op2, uint32_t CRn, uint32_t CRm, uint32_t *value)
{
if (cpnum != 15) {
LOG_ERROR("Only cp15 is supported");
return ERROR_FAIL;
}
return arm926ejs_cp15_read(target, op1, op2, CRn, CRm, value);
}
static int arm926ejs_cp15_write(struct target *target, uint32_t op1, uint32_t op2,
uint32_t CRn, uint32_t CRm, uint32_t value)
{
int retval = ERROR_OK;
struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
struct arm_jtag *jtag_info = &arm7_9->jtag_info;
uint32_t address = ARM926EJS_CP15_ADDR(op1, op2, CRn, CRm);
struct scan_field fields[4];
uint8_t value_buf[4];
uint8_t address_buf[2] = {0, 0};
uint8_t nr_w_buf = 1;
uint8_t access_t = 1;
buf_set_u32(address_buf, 0, 14, address);
buf_set_u32(value_buf, 0, 32, value);
retval = arm_jtag_scann(jtag_info, 0xf, TAP_IDLE);
if (retval != ERROR_OK)
return retval;
retval = arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL, TAP_IDLE);
if (retval != ERROR_OK)
return retval;
fields[0].num_bits = 32;
fields[0].out_value = value_buf;
fields[0].in_value = NULL;
fields[1].num_bits = 1;
fields[1].out_value = &access_t;
fields[1].in_value = &access_t;
fields[2].num_bits = 14;
fields[2].out_value = address_buf;
fields[2].in_value = NULL;
fields[3].num_bits = 1;
fields[3].out_value = &nr_w_buf;
fields[3].in_value = NULL;
jtag_add_dr_scan(jtag_info->tap, 4, fields, TAP_IDLE);
long long then = timeval_ms();
for (;;) {
/* rescan with NOP, to wait for the access to complete */
access_t = 0;
nr_w_buf = 0;
jtag_add_dr_scan(jtag_info->tap, 4, fields, TAP_IDLE);
retval = jtag_execute_queue();
if (retval != ERROR_OK)
return retval;
if (buf_get_u32(&access_t, 0, 1) == 1)
break;
/* 10ms timeout */
if ((timeval_ms()-then) > 10) {
LOG_ERROR("cp15 write operation timed out");
return ERROR_FAIL;
}
}
#ifdef _DEBUG_INSTRUCTION_EXECUTION_
LOG_DEBUG("addr: 0x%x value: %8.8x", address, value);
#endif
retval = arm_jtag_set_instr(jtag_info, 0xf, NULL, TAP_IDLE);
if (retval != ERROR_OK)
return retval;
return ERROR_OK;
}
static int arm926ejs_mcr(struct target *target, int cpnum, uint32_t op1,
uint32_t op2, uint32_t CRn, uint32_t CRm, uint32_t value)
{
if (cpnum != 15) {
LOG_ERROR("Only cp15 is supported");
return ERROR_FAIL;
}
return arm926ejs_cp15_write(target, op1, op2, CRn, CRm, value);
}
static int arm926ejs_examine_debug_reason(struct target *target)
{
struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
struct reg *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT];
int debug_reason;
int retval;
embeddedice_read_reg(dbg_stat);
retval = jtag_execute_queue();
if (retval != ERROR_OK)
return retval;
/* Method-Of-Entry (MOE) field */
debug_reason = buf_get_u32(dbg_stat->value, 6, 4);
switch (debug_reason) {
case 0:
LOG_DEBUG("no *NEW* debug entry (?missed one?)");
/* ... since last restart or debug reset ... */
target->debug_reason = DBG_REASON_DBGRQ;
break;
case 1:
LOG_DEBUG("breakpoint from EICE unit 0");
target->debug_reason = DBG_REASON_BREAKPOINT;
break;
case 2:
LOG_DEBUG("breakpoint from EICE unit 1");
target->debug_reason = DBG_REASON_BREAKPOINT;
break;
case 3:
LOG_DEBUG("soft breakpoint (BKPT instruction)");
target->debug_reason = DBG_REASON_BREAKPOINT;
break;
case 4:
LOG_DEBUG("vector catch breakpoint");
target->debug_reason = DBG_REASON_BREAKPOINT;
break;
case 5:
LOG_DEBUG("external breakpoint");
target->debug_reason = DBG_REASON_BREAKPOINT;
break;
case 6:
LOG_DEBUG("watchpoint from EICE unit 0");
target->debug_reason = DBG_REASON_WATCHPOINT;
break;
case 7:
LOG_DEBUG("watchpoint from EICE unit 1");
target->debug_reason = DBG_REASON_WATCHPOINT;
break;
case 8:
LOG_DEBUG("external watchpoint");
target->debug_reason = DBG_REASON_WATCHPOINT;
break;
case 9:
LOG_DEBUG("internal debug request");
target->debug_reason = DBG_REASON_DBGRQ;
break;
case 10:
LOG_DEBUG("external debug request");
target->debug_reason = DBG_REASON_DBGRQ;
break;
case 11:
LOG_DEBUG("debug re-entry from system speed access");
/* This is normal when connecting to something that's
* already halted, or in some related code paths, but
* otherwise is surprising (and presumably wrong).
*/
switch (target->debug_reason) {
case DBG_REASON_DBGRQ:
break;
default:
LOG_ERROR("unexpected -- debug re-entry");
/* FALLTHROUGH */
case DBG_REASON_UNDEFINED:
target->debug_reason = DBG_REASON_DBGRQ;
break;
}
break;
case 12:
/* FIX!!!! here be dragons!!! We need to fail here so
* the target will interpreted as halted but we won't
* try to talk to it right now... a resume + halt seems
* to sync things up again. Please send an email to
* openocd development mailing list if you have hardware
* to donate to look into this problem....
*/
LOG_WARNING("WARNING: mystery debug reason MOE = 0xc. Try issuing a resume + halt.");
target->debug_reason = DBG_REASON_DBGRQ;
break;
default:
LOG_WARNING("WARNING: unknown debug reason: 0x%x", debug_reason);
/* Oh agony! should we interpret this as a halt request or
* that the target stopped on it's own accord?
*/
target->debug_reason = DBG_REASON_DBGRQ;
/* if we fail here, we won't talk to the target and it will
* be reported to be in the halted state */
break;
}
return ERROR_OK;
}
static int arm926ejs_get_ttb(struct target *target, uint32_t *result)
{
struct arm926ejs_common *arm926ejs = target_to_arm926(target);
int retval;
uint32_t ttb = 0x0;
retval = arm926ejs->read_cp15(target, 0, 0, 2, 0, &ttb);
if (retval != ERROR_OK)
return retval;
*result = ttb;
return ERROR_OK;
}
static int arm926ejs_disable_mmu_caches(struct target *target, int mmu,
int d_u_cache, int i_cache)
{
struct arm926ejs_common *arm926ejs = target_to_arm926(target);
uint32_t cp15_control;
int retval;
/* read cp15 control register */
retval = arm926ejs->read_cp15(target, 0, 0, 1, 0, &cp15_control);
if (retval != ERROR_OK)
return retval;
retval = jtag_execute_queue();
if (retval != ERROR_OK)
return retval;
if (mmu) {
/* invalidate TLB */
retval = arm926ejs->write_cp15(target, 0, 0, 8, 7, 0x0);
if (retval != ERROR_OK)
return retval;
cp15_control &= ~0x1U;
}
if (d_u_cache) {
uint32_t debug_override;
/* read-modify-write CP15 debug override register
* to enable "test and clean all" */
retval = arm926ejs->read_cp15(target, 0, 0, 15, 0, &debug_override);
if (retval != ERROR_OK)
return retval;
debug_override |= 0x80000;
retval = arm926ejs->write_cp15(target, 0, 0, 15, 0, debug_override);
if (retval != ERROR_OK)
return retval;
/* clean and invalidate DCache */
retval = arm926ejs->write_cp15(target, 0, 0, 7, 5, 0x0);
if (retval != ERROR_OK)
return retval;
/* write CP15 debug override register
* to disable "test and clean all" */
debug_override &= ~0x80000;
retval = arm926ejs->write_cp15(target, 0, 0, 15, 0, debug_override);
if (retval != ERROR_OK)
return retval;
cp15_control &= ~0x4U;
}
if (i_cache) {
/* invalidate ICache */
retval = arm926ejs->write_cp15(target, 0, 0, 7, 5, 0x0);
if (retval != ERROR_OK)
return retval;
cp15_control &= ~0x1000U;
}
retval = arm926ejs->write_cp15(target, 0, 0, 1, 0, cp15_control);
return retval;
}
static int arm926ejs_enable_mmu_caches(struct target *target, int mmu,
int d_u_cache, int i_cache)
{
struct arm926ejs_common *arm926ejs = target_to_arm926(target);
uint32_t cp15_control;
int retval;
/* read cp15 control register */
retval = arm926ejs->read_cp15(target, 0, 0, 1, 0, &cp15_control);
if (retval != ERROR_OK)
return retval;
retval = jtag_execute_queue();
if (retval != ERROR_OK)
return retval;
if (mmu)
cp15_control |= 0x1U;
if (d_u_cache)
cp15_control |= 0x4U;
if (i_cache)
cp15_control |= 0x1000U;
retval = arm926ejs->write_cp15(target, 0, 0, 1, 0, cp15_control);
return retval;
}
static int arm926ejs_post_debug_entry(struct target *target)
{
struct arm926ejs_common *arm926ejs = target_to_arm926(target);
int retval;
/* examine cp15 control reg */
retval = arm926ejs->read_cp15(target, 0, 0, 1, 0, &arm926ejs->cp15_control_reg);
if (retval != ERROR_OK)
return retval;
retval = jtag_execute_queue();
if (retval != ERROR_OK)
return retval;
LOG_DEBUG("cp15_control_reg: %8.8" PRIx32 "", arm926ejs->cp15_control_reg);
if (arm926ejs->armv4_5_mmu.armv4_5_cache.ctype == -1) {
uint32_t cache_type_reg;
/* identify caches */
retval = arm926ejs->read_cp15(target, 0, 1, 0, 0, &cache_type_reg);
if (retval != ERROR_OK)
return retval;
retval = jtag_execute_queue();
if (retval != ERROR_OK)
return retval;
armv4_5_identify_cache(cache_type_reg, &arm926ejs->armv4_5_mmu.armv4_5_cache);
}
arm926ejs->armv4_5_mmu.mmu_enabled = (arm926ejs->cp15_control_reg & 0x1U) ? 1 : 0;
arm926ejs->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = (arm926ejs->cp15_control_reg & 0x4U) ? 1 : 0;
arm926ejs->armv4_5_mmu.armv4_5_cache.i_cache_enabled = (arm926ejs->cp15_control_reg & 0x1000U) ? 1 : 0;
/* save i/d fault status and address register */
retval = arm926ejs->read_cp15(target, 0, 0, 5, 0, &arm926ejs->d_fsr);
if (retval != ERROR_OK)
return retval;
retval = arm926ejs->read_cp15(target, 0, 1, 5, 0, &arm926ejs->i_fsr);
if (retval != ERROR_OK)
return retval;
retval = arm926ejs->read_cp15(target, 0, 0, 6, 0, &arm926ejs->d_far);
if (retval != ERROR_OK)
return retval;
LOG_DEBUG("D FSR: 0x%8.8" PRIx32 ", D FAR: 0x%8.8" PRIx32 ", I FSR: 0x%8.8" PRIx32 "",
arm926ejs->d_fsr, arm926ejs->d_far, arm926ejs->i_fsr);
uint32_t cache_dbg_ctrl;
/* read-modify-write CP15 cache debug control register
* to disable I/D-cache linefills and force WT */
retval = arm926ejs->read_cp15(target, 7, 0, 15, 0, &cache_dbg_ctrl);
if (retval != ERROR_OK)
return retval;
cache_dbg_ctrl |= 0x7;
retval = arm926ejs->write_cp15(target, 7, 0, 15, 0, cache_dbg_ctrl);
return retval;
}
static void arm926ejs_pre_restore_context(struct target *target)
{
struct arm926ejs_common *arm926ejs = target_to_arm926(target);
/* restore i/d fault status and address register */
arm926ejs->write_cp15(target, 0, 0, 5, 0, arm926ejs->d_fsr);
arm926ejs->write_cp15(target, 0, 1, 5, 0, arm926ejs->i_fsr);
arm926ejs->write_cp15(target, 0, 0, 6, 0, arm926ejs->d_far);
uint32_t cache_dbg_ctrl;
/* read-modify-write CP15 cache debug control register
* to reenable I/D-cache linefills and disable WT */
arm926ejs->read_cp15(target, 7, 0, 15, 0, &cache_dbg_ctrl);
cache_dbg_ctrl &= ~0x7;
arm926ejs->write_cp15(target, 7, 0, 15, 0, cache_dbg_ctrl);
}
static const char arm926_not[] = "target is not an ARM926";
static int arm926ejs_verify_pointer(struct command_context *cmd_ctx,
struct arm926ejs_common *arm926)
{
if (arm926->common_magic != ARM926EJS_COMMON_MAGIC) {
command_print(cmd_ctx, arm926_not);
return ERROR_TARGET_INVALID;
}
return ERROR_OK;
}
/** Logs summary of ARM926 state for a halted target. */
int arm926ejs_arch_state(struct target *target)
{
static const char *state[] = {
"disabled", "enabled"
};
struct arm926ejs_common *arm926ejs = target_to_arm926(target);
if (arm926ejs->common_magic != ARM926EJS_COMMON_MAGIC) {
LOG_ERROR("BUG: %s", arm926_not);
return ERROR_TARGET_INVALID;
}
arm_arch_state(target);
LOG_USER("MMU: %s, D-Cache: %s, I-Cache: %s",
state[arm926ejs->armv4_5_mmu.mmu_enabled],
state[arm926ejs->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled],
state[arm926ejs->armv4_5_mmu.armv4_5_cache.i_cache_enabled]);
return ERROR_OK;
}
int arm926ejs_soft_reset_halt(struct target *target)
{
int retval = ERROR_OK;
struct arm926ejs_common *arm926ejs = target_to_arm926(target);
struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
struct arm *arm = &arm7_9->arm;
struct reg *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT];
retval = target_halt(target);
if (retval != ERROR_OK)
return retval;
long long then = timeval_ms();
int timeout;
while (!(timeout = ((timeval_ms()-then) > 1000))) {
if (buf_get_u32(dbg_stat->value, EICE_DBG_STATUS_DBGACK, 1) == 0) {
embeddedice_read_reg(dbg_stat);
retval = jtag_execute_queue();
if (retval != ERROR_OK)
return retval;
} else
break;
if (debug_level >= 1) {
/* do not eat all CPU, time out after 1 se*/
alive_sleep(100);
} else
keep_alive();
}
if (timeout) {
LOG_ERROR("Failed to halt CPU after 1 sec");
return ERROR_TARGET_TIMEOUT;
}
target->state = TARGET_HALTED;
/* SVC, ARM state, IRQ and FIQ disabled */
uint32_t cpsr;
cpsr = buf_get_u32(arm->cpsr->value, 0, 32);
cpsr &= ~0xff;
cpsr |= 0xd3;
arm_set_cpsr(arm, cpsr);
arm->cpsr->dirty = 1;
/* start fetching from 0x0 */
buf_set_u32(arm->pc->value, 0, 32, 0x0);
arm->pc->dirty = 1;
arm->pc->valid = 1;
retval = arm926ejs_disable_mmu_caches(target, 1, 1, 1);
if (retval != ERROR_OK)
return retval;
arm926ejs->armv4_5_mmu.mmu_enabled = 0;
arm926ejs->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = 0;
arm926ejs->armv4_5_mmu.armv4_5_cache.i_cache_enabled = 0;
return target_call_event_callbacks(target, TARGET_EVENT_HALTED);
}
/** Writes a buffer, in the specified word size, with current MMU settings. */
int arm926ejs_write_memory(struct target *target, uint32_t address,
uint32_t size, uint32_t count, const uint8_t *buffer)
{
int retval;
struct arm926ejs_common *arm926ejs = target_to_arm926(target);
/* FIX!!!! this should be cleaned up and made much more general. The
* plan is to write up and test on arm926ejs specifically and
* then generalize and clean up afterwards.
*
*
* Also it should be moved to the callbacks that handle breakpoints
* specifically and not the generic memory write fn's. See XScale code.
**/
if (arm926ejs->armv4_5_mmu.mmu_enabled && (count == 1) && ((size == 2) || (size == 4))) {
/* special case the handling of single word writes to bypass MMU
* to allow implementation of breakpoints in memory marked read only
* by MMU */
if (arm926ejs->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled) {
/* flush and invalidate data cache
*
* MCR p15,0,p,c7,c10,1 - clean cache line using virtual address
*
*/
retval = arm926ejs->write_cp15(target, 0, 1, 7, 10, address&~0x3);
if (retval != ERROR_OK)
return retval;
}
uint32_t pa;
retval = target->type->virt2phys(target, address, &pa);
if (retval != ERROR_OK)
return retval;
/* write directly to physical memory bypassing any read only MMU bits, etc. */
retval = armv4_5_mmu_write_physical(target, &arm926ejs->armv4_5_mmu, pa, size, count, buffer);
if (retval != ERROR_OK)
return retval;
} else {
retval = arm7_9_write_memory(target, address, size, count, buffer);
if (retval != ERROR_OK)
return retval;
}
/* If ICache is enabled, we have to invalidate affected ICache lines
* the DCache is forced to write-through, so we don't have to clean it here
*/
if (arm926ejs->armv4_5_mmu.armv4_5_cache.i_cache_enabled) {
if (count <= 1) {
/* invalidate ICache single entry with MVA */
arm926ejs->write_cp15(target, 0, 1, 7, 5, address);
} else {
/* invalidate ICache */
arm926ejs->write_cp15(target, 0, 0, 7, 5, address);
}
}
return retval;
}
static int arm926ejs_write_phys_memory(struct target *target,
uint32_t address, uint32_t size,
uint32_t count, const uint8_t *buffer)
{
struct arm926ejs_common *arm926ejs = target_to_arm926(target);
return armv4_5_mmu_write_physical(target, &arm926ejs->armv4_5_mmu,
address, size, count, buffer);
}
static int arm926ejs_read_phys_memory(struct target *target,
uint32_t address, uint32_t size,
uint32_t count, uint8_t *buffer)
{
struct arm926ejs_common *arm926ejs = target_to_arm926(target);
return armv4_5_mmu_read_physical(target, &arm926ejs->armv4_5_mmu,
address, size, count, buffer);
}
int arm926ejs_init_arch_info(struct target *target, struct arm926ejs_common *arm926ejs,
struct jtag_tap *tap)
{
struct arm7_9_common *arm7_9 = &arm926ejs->arm7_9_common;
arm7_9->arm.mrc = arm926ejs_mrc;
arm7_9->arm.mcr = arm926ejs_mcr;
/* initialize arm7/arm9 specific info (including armv4_5) */
arm9tdmi_init_arch_info(target, arm7_9, tap);
arm926ejs->common_magic = ARM926EJS_COMMON_MAGIC;
arm7_9->post_debug_entry = arm926ejs_post_debug_entry;
arm7_9->pre_restore_context = arm926ejs_pre_restore_context;
arm926ejs->read_cp15 = arm926ejs_cp15_read;
arm926ejs->write_cp15 = arm926ejs_cp15_write;
arm926ejs->armv4_5_mmu.armv4_5_cache.ctype = -1;
arm926ejs->armv4_5_mmu.get_ttb = arm926ejs_get_ttb;
arm926ejs->armv4_5_mmu.read_memory = arm7_9_read_memory;
arm926ejs->armv4_5_mmu.write_memory = arm7_9_write_memory;
arm926ejs->armv4_5_mmu.disable_mmu_caches = arm926ejs_disable_mmu_caches;
arm926ejs->armv4_5_mmu.enable_mmu_caches = arm926ejs_enable_mmu_caches;
arm926ejs->armv4_5_mmu.has_tiny_pages = 1;
arm926ejs->armv4_5_mmu.mmu_enabled = 0;
arm7_9->examine_debug_reason = arm926ejs_examine_debug_reason;
/* The ARM926EJ-S implements the ARMv5TE architecture which
* has the BKPT instruction, so we don't have to use a watchpoint comparator
*/
arm7_9->arm_bkpt = ARMV5_BKPT(0x0);
arm7_9->thumb_bkpt = ARMV5_T_BKPT(0x0) & 0xffff;
return ERROR_OK;
}
static int arm926ejs_target_create(struct target *target, Jim_Interp *interp)
{
struct arm926ejs_common *arm926ejs = calloc(1, sizeof(struct arm926ejs_common));
/* ARM9EJ-S core always reports 0x1 in Capture-IR */
target->tap->ir_capture_mask = 0x0f;
return arm926ejs_init_arch_info(target, arm926ejs, target->tap);
}
COMMAND_HANDLER(arm926ejs_handle_cache_info_command)
{
int retval;
struct target *target = get_current_target(CMD_CTX);
struct arm926ejs_common *arm926ejs = target_to_arm926(target);
retval = arm926ejs_verify_pointer(CMD_CTX, arm926ejs);
if (retval != ERROR_OK)
return retval;
return armv4_5_handle_cache_info_command(CMD_CTX, &arm926ejs->armv4_5_mmu.armv4_5_cache);
}
static int arm926ejs_virt2phys(struct target *target, uint32_t virtual, uint32_t *physical)
{
uint32_t cb;
struct arm926ejs_common *arm926ejs = target_to_arm926(target);
uint32_t ret;
int retval = armv4_5_mmu_translate_va(target, &arm926ejs->armv4_5_mmu,
virtual, &cb, &ret);
if (retval != ERROR_OK)
return retval;
*physical = ret;
return ERROR_OK;
}
static int arm926ejs_mmu(struct target *target, int *enabled)
{
struct arm926ejs_common *arm926ejs = target_to_arm926(target);
if (target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_INVALID;
}
*enabled = arm926ejs->armv4_5_mmu.mmu_enabled;
return ERROR_OK;
}
static const struct command_registration arm926ejs_exec_command_handlers[] = {
{
.name = "cache_info",
.handler = arm926ejs_handle_cache_info_command,
.mode = COMMAND_EXEC,
.usage = "",
.help = "display information about target caches",
},
COMMAND_REGISTRATION_DONE
};
const struct command_registration arm926ejs_command_handlers[] = {
{
.chain = arm9tdmi_command_handlers,
},
{
.name = "arm926ejs",
.mode = COMMAND_ANY,
.help = "arm926ejs command group",
.usage = "",
.chain = arm926ejs_exec_command_handlers,
},
COMMAND_REGISTRATION_DONE
};
/** Holds methods for ARM926 targets. */
struct target_type arm926ejs_target = {
.name = "arm926ejs",
.poll = arm7_9_poll,
.arch_state = arm926ejs_arch_state,
.target_request_data = arm7_9_target_request_data,
.halt = arm7_9_halt,
.resume = arm7_9_resume,
.step = arm7_9_step,
.assert_reset = arm7_9_assert_reset,
.deassert_reset = arm7_9_deassert_reset,
.soft_reset_halt = arm926ejs_soft_reset_halt,
.get_gdb_reg_list = arm_get_gdb_reg_list,
.read_memory = arm7_9_read_memory,
.write_memory = arm926ejs_write_memory,
.bulk_write_memory = arm7_9_bulk_write_memory,
.checksum_memory = arm_checksum_memory,
.blank_check_memory = arm_blank_check_memory,
.run_algorithm = armv4_5_run_algorithm,
.add_breakpoint = arm7_9_add_breakpoint,
.remove_breakpoint = arm7_9_remove_breakpoint,
.add_watchpoint = arm7_9_add_watchpoint,
.remove_watchpoint = arm7_9_remove_watchpoint,
.commands = arm926ejs_command_handlers,
.target_create = arm926ejs_target_create,
.init_target = arm9tdmi_init_target,
.examine = arm7_9_examine,
.check_reset = arm7_9_check_reset,
.virt2phys = arm926ejs_virt2phys,
.mmu = arm926ejs_mmu,
.read_phys_memory = arm926ejs_read_phys_memory,
.write_phys_memory = arm926ejs_write_phys_memory,
};

View File

@ -0,0 +1,57 @@
/***************************************************************************
* Copyright (C) 2007 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef ARM926EJS_H
#define ARM926EJS_H
#include "arm9tdmi.h"
#include "armv4_5_mmu.h"
#define ARM926EJS_COMMON_MAGIC 0xa926a926
struct arm926ejs_common {
struct arm7_9_common arm7_9_common;
uint32_t common_magic;
struct armv4_5_mmu_common armv4_5_mmu;
int (*read_cp15)(struct target *target, uint32_t op1, uint32_t op2,
uint32_t CRn, uint32_t CRm, uint32_t *value);
int (*write_cp15)(struct target *target, uint32_t op1, uint32_t op2,
uint32_t CRn, uint32_t CRm, uint32_t value);
uint32_t cp15_control_reg;
uint32_t d_fsr;
uint32_t i_fsr;
uint32_t d_far;
};
static inline struct arm926ejs_common *target_to_arm926(struct target *target)
{
return container_of(target->arch_info, struct arm926ejs_common, arm7_9_common.arm);
}
int arm926ejs_init_arch_info(struct target *target,
struct arm926ejs_common *arm926ejs, struct jtag_tap *tap);
int arm926ejs_arch_state(struct target *target);
int arm926ejs_write_memory(struct target *target,
uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer);
int arm926ejs_soft_reset_halt(struct target *target);
extern const struct command_registration arm926ejs_command_handlers[];
#endif /* ARM926EJS_H */

View File

@ -0,0 +1,787 @@
/***************************************************************************
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* Copyright (C) 2008 by Spencer Oliver *
* spen@spen-soft.co.uk *
* *
* Copyright (C) 2010 by Drasko DRASKOVIC *
* drasko.draskovic@gmail.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "arm946e.h"
#include "target_type.h"
#include "arm_opcodes.h"
#include "breakpoints.h"
#if 0
#define _DEBUG_INSTRUCTION_EXECUTION_
#endif
#define NB_CACHE_WAYS 4
#define CP15_CTL 0x02
#define CP15_CTL_DCACHE (1<<2)
#define CP15_CTL_ICACHE (1<<12)
/**
* flag to give info about cache manipulation during debug :
* "0" - cache lines are invalidated "on the fly", for affected addresses.
* This is prefered from performance point of view.
* "1" - cache is invalidated and switched off on debug_entry, and switched back on on restore.
* It is kept off during debugging.
*/
static uint8_t arm946e_preserve_cache;
int arm946e_post_debug_entry(struct target *target);
void arm946e_pre_restore_context(struct target *target);
static int arm946e_read_cp15(struct target *target, int reg_addr, uint32_t *value);
int arm946e_init_arch_info(struct target *target,
struct arm946e_common *arm946e,
struct jtag_tap *tap)
{
struct arm7_9_common *arm7_9 = &arm946e->arm7_9_common;
/* initialize arm7/arm9 specific info (including armv4_5) */
arm9tdmi_init_arch_info(target, arm7_9, tap);
arm946e->common_magic = ARM946E_COMMON_MAGIC;
/**
* The ARM946E-S implements the ARMv5TE architecture which
* has the BKPT instruction, so we don't have to use a watchpoint comparator
*/
arm7_9->arm_bkpt = ARMV5_BKPT(0x0);
arm7_9->thumb_bkpt = ARMV5_T_BKPT(0x0) & 0xffff;
arm7_9->post_debug_entry = arm946e_post_debug_entry;
arm7_9->pre_restore_context = arm946e_pre_restore_context;
/**
* disabling linefills leads to lockups, so keep them enabled for now
* this doesn't affect correctness, but might affect timing issues, if
* important data is evicted from the cache during the debug session
*/
arm946e_preserve_cache = 0;
/* override hw single-step capability from ARM9TDMI */
/* arm7_9->has_single_step = 1; */
return ERROR_OK;
}
static int arm946e_target_create(struct target *target, Jim_Interp *interp)
{
struct arm946e_common *arm946e = calloc(1, sizeof(struct arm946e_common));
arm946e_init_arch_info(target, arm946e, target->tap);
return ERROR_OK;
}
static int arm946e_verify_pointer(struct command_context *cmd_ctx,
struct arm946e_common *arm946e)
{
if (arm946e->common_magic != ARM946E_COMMON_MAGIC) {
command_print(cmd_ctx, "target is not an ARM946");
return ERROR_TARGET_INVALID;
}
return ERROR_OK;
}
/*
* Update cp15_control_reg, saved on debug_entry.
*/
static void arm946e_update_cp15_caches(struct target *target, uint32_t value)
{
struct arm946e_common *arm946e = target_to_arm946(target);
arm946e->cp15_control_reg = (arm946e->cp15_control_reg & ~(CP15_CTL_DCACHE|CP15_CTL_ICACHE))
| (value & (CP15_CTL_DCACHE|CP15_CTL_ICACHE));
}
/*
* REVISIT: The "read_cp15" and "write_cp15" commands could hook up
* to eventual mrc() and mcr() routines ... the reg_addr values being
* constructed (for CP15 only) from Opcode_1, Opcode_2, and CRn values.
* See section 7.3 of the ARM946E-S TRM.
*/
static int arm946e_read_cp15(struct target *target, int reg_addr, uint32_t *value)
{
int retval = ERROR_OK;
struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
struct arm_jtag *jtag_info = &arm7_9->jtag_info;
struct scan_field fields[3];
uint8_t reg_addr_buf = reg_addr & 0x3f;
uint8_t nr_w_buf = 0;
retval = arm_jtag_scann(jtag_info, 0xf, TAP_IDLE);
if (retval != ERROR_OK)
return retval;
retval = arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL, TAP_IDLE);
if (retval != ERROR_OK)
return retval;
fields[0].num_bits = 32;
/* REVISIT: table 7-2 shows that bits 31-31 need to be
* specified for accessing BIST registers ...
*/
fields[0].out_value = NULL;
fields[0].in_value = NULL;
fields[1].num_bits = 6;
fields[1].out_value = &reg_addr_buf;
fields[1].in_value = NULL;
fields[2].num_bits = 1;
fields[2].out_value = &nr_w_buf;
fields[2].in_value = NULL;
jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE);
fields[0].in_value = (uint8_t *)value;
jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE);
jtag_add_callback(arm_le_to_h_u32, (jtag_callback_data_t)value);
#ifdef _DEBUG_INSTRUCTION_EXECUTION_
LOG_DEBUG("addr: 0x%x value: %8.8x", reg_addr, *value);
#endif
retval = jtag_execute_queue();
if (retval != ERROR_OK)
return retval;
return ERROR_OK;
}
int arm946e_write_cp15(struct target *target, int reg_addr, uint32_t value)
{
int retval = ERROR_OK;
struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
struct arm_jtag *jtag_info = &arm7_9->jtag_info;
struct scan_field fields[3];
uint8_t reg_addr_buf = reg_addr & 0x3f;
uint8_t nr_w_buf = 1;
uint8_t value_buf[4];
buf_set_u32(value_buf, 0, 32, value);
retval = arm_jtag_scann(jtag_info, 0xf, TAP_IDLE);
if (retval != ERROR_OK)
return retval;
retval = arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL, TAP_IDLE);
if (retval != ERROR_OK)
return retval;
fields[0].num_bits = 32;
fields[0].out_value = value_buf;
fields[0].in_value = NULL;
fields[1].num_bits = 6;
fields[1].out_value = &reg_addr_buf;
fields[1].in_value = NULL;
fields[2].num_bits = 1;
fields[2].out_value = &nr_w_buf;
fields[2].in_value = NULL;
jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE);
#ifdef _DEBUG_INSTRUCTION_EXECUTION_
LOG_DEBUG("addr: 0x%x value: %8.8x", reg_addr, value);
#endif
retval = jtag_execute_queue();
if (retval != ERROR_OK)
return retval;
return ERROR_OK;
}
#define GET_ICACHE_SIZE 6
#define GET_DCACHE_SIZE 18
/*
* \param target struct target pointer
* \param idsel select GET_ICACHE_SIZE or GET_DCACHE_SIZE
* \returns cache size, given in bytes
*/
static uint32_t arm946e_cp15_get_csize(struct target *target, int idsel)
{
struct arm946e_common *arm946e = target_to_arm946(target);
uint32_t csize = arm946e->cp15_cache_info;
if (csize == 0) {
if (arm946e_read_cp15(target, 0x01, &csize) == ERROR_OK)
arm946e->cp15_cache_info = csize;
}
if (csize & (1<<(idsel-4))) /* cache absent */
return 0;
csize = (csize >> idsel) & 0x0F;
return csize ? 1 << (12 + (csize-3)) : 0;
}
uint32_t arm946e_invalidate_whole_dcache(struct target *target)
{
uint32_t csize = arm946e_cp15_get_csize(target, GET_DCACHE_SIZE);
if (csize == 0)
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
/* One line (index) is 32 bytes (8 words) long, 4-way assoc
* ARM DDI 0201D, Section 3.3.5
*/
int nb_idx = (csize / (4*8*NB_CACHE_WAYS)); /* gives nb of lines (indexes) in the cache */
/* Loop for all segmentde (i.e. ways) */
uint32_t seg;
for (seg = 0; seg < NB_CACHE_WAYS; seg++) {
/* Loop for all indexes */
int idx;
for (idx = 0; idx < nb_idx; idx++) {
/* Form and write cp15 index (segment + line idx) */
uint32_t cp15_idx = seg << 30 | idx << 5;
int retval = arm946e_write_cp15(target, 0x3a, cp15_idx);
if (retval != ERROR_OK) {
LOG_DEBUG("ERROR writing index");
return retval;
}
/* Read dtag */
uint32_t dtag;
arm946e_read_cp15(target, 0x16, (uint32_t *) &dtag);
/* Check cache line VALID bit */
if (!(dtag >> 4 & 0x1))
continue;
/* Clean data cache line */
retval = arm946e_write_cp15(target, 0x35, 0x1);
if (retval != ERROR_OK) {
LOG_DEBUG("ERROR cleaning cache line");
return retval;
}
/* Flush data cache line */
retval = arm946e_write_cp15(target, 0x1a, 0x1);
if (retval != ERROR_OK) {
LOG_DEBUG("ERROR flushing cache line");
return retval;
}
}
}
return ERROR_OK;
}
uint32_t arm946e_invalidate_whole_icache(struct target *target)
{
/* Check cache presence before flushing - avoid undefined behavior */
uint32_t csize = arm946e_cp15_get_csize(target, GET_ICACHE_SIZE);
if (csize == 0)
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
LOG_DEBUG("FLUSHING I$");
/**
* Invalidate (flush) I$
* mcr 15, 0, r0, cr7, cr5, {0}
*/
int retval = arm946e_write_cp15(target, 0x0f, 0x1);
if (retval != ERROR_OK) {
LOG_DEBUG("ERROR flushing I$");
return retval;
}
return ERROR_OK;
}
int arm946e_post_debug_entry(struct target *target)
{
uint32_t ctr_reg = 0x0;
uint32_t retval = ERROR_OK;
struct arm946e_common *arm946e = target_to_arm946(target);
/* See if CACHES are enabled, and save that info
* in the context bits, so that arm946e_pre_restore_context() can use them */
arm946e_read_cp15(target, CP15_CTL, (uint32_t *) &ctr_reg);
/* Save control reg in the context */
arm946e->cp15_control_reg = ctr_reg;
if (arm946e_preserve_cache) {
if (ctr_reg & CP15_CTL_DCACHE) {
/* Clean and flush D$ */
arm946e_invalidate_whole_dcache(target);
/* Disable D$ */
ctr_reg &= ~CP15_CTL_DCACHE;
}
if (ctr_reg & CP15_CTL_ICACHE) {
/* Flush I$ */
arm946e_invalidate_whole_icache(target);
/* Disable I$ */
ctr_reg &= ~CP15_CTL_ICACHE;
}
/* Write the new configuration */
retval = arm946e_write_cp15(target, CP15_CTL, ctr_reg);
if (retval != ERROR_OK) {
LOG_DEBUG("ERROR disabling cache");
return retval;
}
} /* if preserve_cache */
return ERROR_OK;
}
void arm946e_pre_restore_context(struct target *target)
{
uint32_t ctr_reg = 0x0;
uint32_t retval;
if (arm946e_preserve_cache) {
struct arm946e_common *arm946e = target_to_arm946(target);
/* Get the contents of the CTR reg */
arm946e_read_cp15(target, CP15_CTL, (uint32_t *) &ctr_reg);
/**
* Read-modify-write CP15 control
* to reenable I/D-cache operation
* NOTE: It is not possible to disable cache by CP15.
* if arm946e_preserve_cache debugging flag enabled.
*/
ctr_reg |= arm946e->cp15_control_reg & (CP15_CTL_DCACHE|CP15_CTL_ICACHE);
/* Write the new configuration */
retval = arm946e_write_cp15(target, CP15_CTL, ctr_reg);
if (retval != ERROR_OK)
LOG_DEBUG("ERROR enabling cache");
} /* if preserve_cache */
}
uint32_t arm946e_invalidate_dcache(struct target *target, uint32_t address,
uint32_t size, uint32_t count)
{
uint32_t cur_addr = 0x0;
uint32_t cp15_idx, set, way, dtag;
uint32_t i = 0;
int retval;
for (i = 0; i < count*size; i++) {
cur_addr = address + i;
set = (cur_addr >> 5) & 0xff; /* set field is 8 bits long */
for (way = 0; way < NB_CACHE_WAYS; way++) {
/**
* Find if the affected address is kept in the cache.
* Because JTAG Scan Chain 15 offers limited approach,
* we have to loop through all cache ways (segments) and
* read cache tags, then compare them with with address.
*/
/* Form and write cp15 index (segment + line idx) */
cp15_idx = way << 30 | set << 5;
retval = arm946e_write_cp15(target, 0x3a, cp15_idx);
if (retval != ERROR_OK) {
LOG_DEBUG("ERROR writing index");
return retval;
}
/* Read dtag */
arm946e_read_cp15(target, 0x16, (uint32_t *) &dtag);
/* Check cache line VALID bit */
if (!(dtag >> 4 & 0x1))
continue;
/* If line is valid and corresponds to affected address - invalidate it */
if (dtag >> 5 == cur_addr >> 5) {
/* Clean data cache line */
retval = arm946e_write_cp15(target, 0x35, 0x1);
if (retval != ERROR_OK) {
LOG_DEBUG("ERROR cleaning cache line");
return retval;
}
/* Flush data cache line */
retval = arm946e_write_cp15(target, 0x1c, 0x1);
if (retval != ERROR_OK) {
LOG_DEBUG("ERROR flushing cache line");
return retval;
}
break;
}
} /* loop through all 4 ways */
} /* loop through all addresses */
return ERROR_OK;
}
uint32_t arm946e_invalidate_icache(struct target *target, uint32_t address,
uint32_t size, uint32_t count)
{
uint32_t cur_addr = 0x0;
uint32_t cp15_idx, set, way, itag;
uint32_t i = 0;
int retval;
for (i = 0; i < count*size; i++) {
cur_addr = address + i;
set = (cur_addr >> 5) & 0xff; /* set field is 8 bits long */
for (way = 0; way < NB_CACHE_WAYS; way++) {
/* Form and write cp15 index (segment + line idx) */
cp15_idx = way << 30 | set << 5;
retval = arm946e_write_cp15(target, 0x3a, cp15_idx);
if (retval != ERROR_OK) {
LOG_DEBUG("ERROR writing index");
return retval;
}
/* Read itag */
arm946e_read_cp15(target, 0x17, (uint32_t *) &itag);
/* Check cache line VALID bit */
if (!(itag >> 4 & 0x1))
continue;
/* If line is valid and corresponds to affected address - invalidate it */
if (itag >> 5 == cur_addr >> 5) {
/* Flush I$ line */
retval = arm946e_write_cp15(target, 0x1d, 0x0);
if (retval != ERROR_OK) {
LOG_DEBUG("ERROR flushing cache line");
return retval;
}
break;
}
} /* way loop */
} /* addr loop */
return ERROR_OK;
}
/** Writes a buffer, in the specified word size, with current MMU settings. */
int arm946e_write_memory(struct target *target, uint32_t address,
uint32_t size, uint32_t count, const uint8_t *buffer)
{
int retval;
LOG_DEBUG("-");
struct arm946e_common *arm946e = target_to_arm946(target);
/* Invalidate D$ if it is ON */
if (!arm946e_preserve_cache && (arm946e->cp15_control_reg & CP15_CTL_DCACHE))
arm946e_invalidate_dcache(target, address, size, count);
/**
* Write memory
*/
retval = arm7_9_write_memory(target, address, size, count, buffer);
if (retval != ERROR_OK)
return retval;
/* *
* Invalidate I$ if it is ON.
*
* D$ has been cleaned and flushed before mem write thus forcing it to behave like write-through,
* because arm7_9_write_memory() has seen non-valid bit in D$
* and wrote data into physical RAM (without touching or allocating the cache line).
* From ARM946ES Technical Reference Manual we can see that it uses "allocate on read-miss"
* policy for both I$ and D$ (Chapter 3.2 and 3.3)
*
* Explanation :
* "ARM system developer's guide: designing and optimizing system software" by
* Andrew N. Sloss, Dominic Symes and Chris Wright,
* Chapter 12.3.3 Allocating Policy on a Cache Miss :
* A read allocate on cache miss policy allocates a cache line only during a read from main memory.
* If the victim cache line contains valid data, then it is written to main memory before the cache line
* is filled with new data.
* Under this strategy, a write of new data to memory does not update the contents of the cache memory
* unless a cache line was allocated on a previous read from main memory.
* If the cache line contains valid data, then the write updates the cache and may update the main memory if
* the cache write policy is write-through.
* If the data is not in the cache, the controller writes to main memory only.
*/
if (!arm946e_preserve_cache && (arm946e->cp15_control_reg & CP15_CTL_ICACHE))
arm946e_invalidate_icache(target, address, size, count);
return ERROR_OK;
}
int arm946e_read_memory(struct target *target, uint32_t address,
uint32_t size, uint32_t count, uint8_t *buffer)
{
int retval;
LOG_DEBUG("-");
retval = arm7_9_read_memory(target, address, size, count, buffer);
if (retval != ERROR_OK)
return retval;
return ERROR_OK;
}
static int jim_arm946e_cp15(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
{
/* one or two arguments, access a single register (write if second argument is given) */
if (argc < 2 || argc > 3) {
Jim_WrongNumArgs(interp, 1, argv, "addr [value]");
return JIM_ERR;
}
struct command_context *cmd_ctx = current_command_context(interp);
assert(cmd_ctx != NULL);
struct target *target = get_current_target(cmd_ctx);
if (target == NULL) {
LOG_ERROR("arm946e: no current target");
return JIM_ERR;
}
struct arm946e_common *arm946e = target_to_arm946(target);
int retval = arm946e_verify_pointer(cmd_ctx, arm946e);
if (retval != ERROR_OK)
return JIM_ERR;
if (target->state != TARGET_HALTED) {
command_print(cmd_ctx, "target %s must be stopped for \"cp15\" command", target_name(target));
return JIM_ERR;
}
long l;
uint32_t address;
retval = Jim_GetLong(interp, argv[1], &l);
address = l;
if (JIM_OK != retval)
return retval;
if (argc == 2) {
uint32_t value;
retval = arm946e_read_cp15(target, address, &value);
if (retval != ERROR_OK) {
command_print(cmd_ctx, "%s cp15 reg %" PRIi32 " access failed", target_name(target), address);
return JIM_ERR;
}
retval = jtag_execute_queue();
if (retval != ERROR_OK)
return JIM_ERR;
char buf[20];
sprintf(buf, "0x%08x", value);
/* Return value in hex format */
Jim_SetResultString(interp, buf, -1);
} else if (argc == 3) {
uint32_t value;
retval = Jim_GetLong(interp, argv[2], &l);
value = l;
if (JIM_OK != retval)
return retval;
retval = arm946e_write_cp15(target, address, value);
if (retval != ERROR_OK) {
command_print(cmd_ctx, "%s cp15 reg %" PRIi32 " access failed", target_name(target), address);
return JIM_ERR;
}
if (address == CP15_CTL)
arm946e_update_cp15_caches(target, value);
}
return JIM_OK;
}
COMMAND_HANDLER(arm946e_handle_idcache)
{
if (CMD_ARGC > 1)
return ERROR_COMMAND_SYNTAX_ERROR;
int retval;
struct target *target = get_current_target(CMD_CTX);
struct arm946e_common *arm946e = target_to_arm946(target);
retval = arm946e_verify_pointer(CMD_CTX, arm946e);
if (retval != ERROR_OK)
return retval;
if (target->state != TARGET_HALTED) {
command_print(CMD_CTX, "target must be stopped for \"%s\" command", CMD_NAME);
return ERROR_TARGET_NOT_HALTED;
}
bool icache = (strcmp(CMD_NAME, "icache") == 0);
uint32_t csize = arm946e_cp15_get_csize(target, icache ? GET_ICACHE_SIZE : GET_DCACHE_SIZE) / 1024;
if (CMD_ARGC == 0) {
bool bena = ((arm946e->cp15_control_reg & (icache ? CP15_CTL_ICACHE : CP15_CTL_DCACHE)) != 0)
&& (arm946e->cp15_control_reg & 0x1);
if (csize == 0)
command_print(CMD_CTX, "%s-cache absent", icache ? "I" : "D");
else
command_print(CMD_CTX, "%s-cache size: %dK, %s", icache ? "I" : "D", csize, bena ? "enabled" : "disabled");
return ERROR_OK;
}
bool flush = false;
bool enable = false;
retval = command_parse_bool_arg(CMD_ARGV[0], &enable);
if (retval == ERROR_COMMAND_SYNTAX_ERROR) {
if (strcmp(CMD_ARGV[0], "flush") == 0) {
flush = true;
retval = ERROR_OK;
} else
return retval;
}
/* Do not invalidate or change state, if cache is absent */
if (csize == 0) {
command_print(CMD_CTX, "%s-cache absent, '%s' operation undefined", icache ? "I" : "D", CMD_ARGV[0]);
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
}
/* NOTE: flushing entire cache will not preserve lock-down cache regions */
if (icache) {
if ((arm946e->cp15_control_reg & CP15_CTL_ICACHE) && !enable)
retval = arm946e_invalidate_whole_icache(target);
} else {
if ((arm946e->cp15_control_reg & CP15_CTL_DCACHE) && !enable)
retval = arm946e_invalidate_whole_dcache(target);
}
if (retval != ERROR_OK || flush)
return retval;
uint32_t value;
retval = arm946e_read_cp15(target, CP15_CTL, &value);
if (retval != ERROR_OK)
return retval;
uint32_t vnew = value;
uint32_t cmask = icache ? CP15_CTL_ICACHE : CP15_CTL_DCACHE;
if (enable) {
if ((value & 0x1) == 0)
LOG_WARNING("arm946e: MPU must be enabled for cache to operate");
vnew |= cmask;
} else
vnew &= ~cmask;
if (vnew == value)
return ERROR_OK;
retval = arm946e_write_cp15(target, CP15_CTL, vnew);
if (retval != ERROR_OK)
return retval;
arm946e_update_cp15_caches(target, vnew);
return ERROR_OK;
}
static const struct command_registration arm946e_exec_command_handlers[] = {
{
.name = "cp15",
.jim_handler = jim_arm946e_cp15,
.mode = COMMAND_EXEC,
.usage = "regnum [value]",
.help = "read/modify cp15 register",
},
{
.name = "icache",
.handler = arm946e_handle_idcache,
.mode = COMMAND_EXEC,
.usage = "['enable'|'disable'|'flush']",
.help = "I-cache info and operations",
},
{
.name = "dcache",
.handler = arm946e_handle_idcache,
.mode = COMMAND_EXEC,
.usage = "['enable'|'disable'|'flush']",
.help = "D-cache info and operations",
},
COMMAND_REGISTRATION_DONE
};
const struct command_registration arm946e_command_handlers[] = {
{
.chain = arm9tdmi_command_handlers,
},
{
.name = "arm946e",
.mode = COMMAND_ANY,
.help = "arm946e command group",
.usage = "",
.chain = arm946e_exec_command_handlers,
},
COMMAND_REGISTRATION_DONE
};
/** Holds methods for ARM946 targets. */
struct target_type arm946e_target = {
.name = "arm946e",
.poll = arm7_9_poll,
.arch_state = arm_arch_state,
.target_request_data = arm7_9_target_request_data,
.halt = arm7_9_halt,
.resume = arm7_9_resume,
.step = arm7_9_step,
.assert_reset = arm7_9_assert_reset,
.deassert_reset = arm7_9_deassert_reset,
.soft_reset_halt = arm7_9_soft_reset_halt,
.get_gdb_reg_list = arm_get_gdb_reg_list,
/* .read_memory = arm7_9_read_memory, */
/* .write_memory = arm7_9_write_memory, */
.read_memory = arm946e_read_memory,
.write_memory = arm946e_write_memory,
.bulk_write_memory = arm7_9_bulk_write_memory,
.checksum_memory = arm_checksum_memory,
.blank_check_memory = arm_blank_check_memory,
.run_algorithm = armv4_5_run_algorithm,
.add_breakpoint = arm7_9_add_breakpoint,
.remove_breakpoint = arm7_9_remove_breakpoint,
/* .add_breakpoint = arm946e_add_breakpoint, */
/* .remove_breakpoint = arm946e_remove_breakpoint, */
.add_watchpoint = arm7_9_add_watchpoint,
.remove_watchpoint = arm7_9_remove_watchpoint,
.commands = arm946e_command_handlers,
.target_create = arm946e_target_create,
.init_target = arm9tdmi_init_target,
.examine = arm7_9_examine,
.check_reset = arm7_9_check_reset,
};

View File

@ -0,0 +1,53 @@
/***************************************************************************
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* Copyright (C) 2008 by Spencer Oliver *
* spen@spen-soft.co.uk *
* *
* Copyright (C) 2010 by Drasko DRASKOVIC *
* drasko.draskovic@gmail.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef ARM946E_H
#define ARM946E_H
#include "arm9tdmi.h"
#define ARM946E_COMMON_MAGIC 0x20f920f9
struct arm946e_common {
struct arm7_9_common arm7_9_common;
int common_magic;
uint32_t cp15_control_reg;
uint32_t cp15_cache_info;
};
static inline struct arm946e_common *target_to_arm946(struct target *target)
{
return container_of(target->arch_info, struct arm946e_common,
arm7_9_common.arm);
}
int arm946e_init_arch_info(struct target *target,
struct arm946e_common *arm946e, struct jtag_tap *tap);
int arm946e_write_cp15(struct target *target, int reg_addr, uint32_t value);
extern const struct command_registration arm946e_command_handlers[];
#endif /* ARM946E_H */

View File

@ -0,0 +1,285 @@
/***************************************************************************
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* Copyright (C) 2008 by Spencer Oliver *
* spen@spen-soft.co.uk *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "arm966e.h"
#include "target_type.h"
#include "arm_opcodes.h"
#if 0
#define _DEBUG_INSTRUCTION_EXECUTION_
#endif
int arm966e_init_arch_info(struct target *target, struct arm966e_common *arm966e, struct jtag_tap *tap)
{
struct arm7_9_common *arm7_9 = &arm966e->arm7_9_common;
/* initialize arm7/arm9 specific info (including armv4_5) */
arm9tdmi_init_arch_info(target, arm7_9, tap);
arm966e->common_magic = ARM966E_COMMON_MAGIC;
/* The ARM966E-S implements the ARMv5TE architecture which
* has the BKPT instruction, so we don't have to use a watchpoint comparator
*/
arm7_9->arm_bkpt = ARMV5_BKPT(0x0);
arm7_9->thumb_bkpt = ARMV5_T_BKPT(0x0) & 0xffff;
return ERROR_OK;
}
static int arm966e_target_create(struct target *target, Jim_Interp *interp)
{
struct arm966e_common *arm966e = calloc(1, sizeof(struct arm966e_common));
return arm966e_init_arch_info(target, arm966e, target->tap);
}
static int arm966e_verify_pointer(struct command_context *cmd_ctx,
struct arm966e_common *arm966e)
{
if (arm966e->common_magic != ARM966E_COMMON_MAGIC) {
command_print(cmd_ctx, "target is not an ARM966");
return ERROR_TARGET_INVALID;
}
return ERROR_OK;
}
/*
* REVISIT: The "read_cp15" and "write_cp15" commands could hook up
* to eventual mrc() and mcr() routines ... the reg_addr values being
* constructed (for CP15 only) from Opcode_1, Opcode_2, and CRn values.
* See section 7.3 of the ARM966E-S TRM.
*/
static int arm966e_read_cp15(struct target *target, int reg_addr, uint32_t *value)
{
int retval = ERROR_OK;
struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
struct arm_jtag *jtag_info = &arm7_9->jtag_info;
struct scan_field fields[3];
uint8_t reg_addr_buf = reg_addr & 0x3f;
uint8_t nr_w_buf = 0;
retval = arm_jtag_scann(jtag_info, 0xf, TAP_IDLE);
if (retval != ERROR_OK)
return retval;
retval = arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL, TAP_IDLE);
if (retval != ERROR_OK)
return retval;
fields[0].num_bits = 32;
/* REVISIT: table 7-2 shows that bits 31-31 need to be
* specified for accessing BIST registers ...
*/
fields[0].out_value = NULL;
fields[0].in_value = NULL;
fields[1].num_bits = 6;
fields[1].out_value = &reg_addr_buf;
fields[1].in_value = NULL;
fields[2].num_bits = 1;
fields[2].out_value = &nr_w_buf;
fields[2].in_value = NULL;
jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE);
fields[1].in_value = (uint8_t *)value;
jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE);
jtag_add_callback(arm_le_to_h_u32, (jtag_callback_data_t)value);
#ifdef _DEBUG_INSTRUCTION_EXECUTION_
retval = jtag_execute_queue();
if (retval != ERROR_OK)
return retval;
LOG_DEBUG("addr: 0x%x value: %8.8x", reg_addr, *value);
#endif
return ERROR_OK;
}
/* EXPORTED to str9x (flash) */
int arm966e_write_cp15(struct target *target, int reg_addr, uint32_t value)
{
int retval = ERROR_OK;
struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
struct arm_jtag *jtag_info = &arm7_9->jtag_info;
struct scan_field fields[3];
uint8_t reg_addr_buf = reg_addr & 0x3f;
uint8_t nr_w_buf = 1;
uint8_t value_buf[4];
buf_set_u32(value_buf, 0, 32, value);
retval = arm_jtag_scann(jtag_info, 0xf, TAP_IDLE);
if (retval != ERROR_OK)
return retval;
retval = arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL, TAP_IDLE);
if (retval != ERROR_OK)
return retval;
fields[0].num_bits = 32;
fields[0].out_value = value_buf;
fields[0].in_value = NULL;
fields[1].num_bits = 6;
fields[1].out_value = &reg_addr_buf;
fields[1].in_value = NULL;
fields[2].num_bits = 1;
fields[2].out_value = &nr_w_buf;
fields[2].in_value = NULL;
jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE);
#ifdef _DEBUG_INSTRUCTION_EXECUTION_
LOG_DEBUG("addr: 0x%x value: %8.8x", reg_addr, value);
#endif
return ERROR_OK;
}
COMMAND_HANDLER(arm966e_handle_cp15_command)
{
int retval;
struct target *target = get_current_target(CMD_CTX);
struct arm966e_common *arm966e = target_to_arm966(target);
retval = arm966e_verify_pointer(CMD_CTX, arm966e);
if (retval != ERROR_OK)
return retval;
if (target->state != TARGET_HALTED) {
command_print(CMD_CTX, "target must be stopped for \"%s\" command", CMD_NAME);
return ERROR_OK;
}
/* one or more argument, access a single register (write if second argument is given */
if (CMD_ARGC >= 1) {
uint32_t address;
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address);
if (CMD_ARGC == 1) {
uint32_t value;
retval = arm966e_read_cp15(target, address, &value);
if (retval != ERROR_OK) {
command_print(CMD_CTX,
"couldn't access reg %" PRIi32,
address);
return ERROR_OK;
}
retval = jtag_execute_queue();
if (retval != ERROR_OK)
return retval;
command_print(CMD_CTX, "%" PRIi32 ": %8.8" PRIx32,
address, value);
} else if (CMD_ARGC == 2) {
uint32_t value;
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value);
retval = arm966e_write_cp15(target, address, value);
if (retval != ERROR_OK) {
command_print(CMD_CTX,
"couldn't access reg %" PRIi32,
address);
return ERROR_OK;
}
command_print(CMD_CTX, "%" PRIi32 ": %8.8" PRIx32,
address, value);
}
}
return ERROR_OK;
}
static const struct command_registration arm966e_exec_command_handlers[] = {
{
.name = "cp15",
.handler = arm966e_handle_cp15_command,
.mode = COMMAND_EXEC,
.usage = "regnum [value]",
.help = "display/modify cp15 register",
},
COMMAND_REGISTRATION_DONE
};
const struct command_registration arm966e_command_handlers[] = {
{
.chain = arm9tdmi_command_handlers,
},
{
.name = "arm966e",
.mode = COMMAND_ANY,
.help = "arm966e command group",
.usage = "",
.chain = arm966e_exec_command_handlers,
},
COMMAND_REGISTRATION_DONE
};
/** Holds methods for ARM966 targets. */
struct target_type arm966e_target = {
.name = "arm966e",
.poll = arm7_9_poll,
.arch_state = arm_arch_state,
.target_request_data = arm7_9_target_request_data,
.halt = arm7_9_halt,
.resume = arm7_9_resume,
.step = arm7_9_step,
.assert_reset = arm7_9_assert_reset,
.deassert_reset = arm7_9_deassert_reset,
.soft_reset_halt = arm7_9_soft_reset_halt,
.get_gdb_reg_list = arm_get_gdb_reg_list,
.read_memory = arm7_9_read_memory,
.write_memory = arm7_9_write_memory,
.bulk_write_memory = arm7_9_bulk_write_memory,
.checksum_memory = arm_checksum_memory,
.blank_check_memory = arm_blank_check_memory,
.run_algorithm = armv4_5_run_algorithm,
.add_breakpoint = arm7_9_add_breakpoint,
.remove_breakpoint = arm7_9_remove_breakpoint,
.add_watchpoint = arm7_9_add_watchpoint,
.remove_watchpoint = arm7_9_remove_watchpoint,
.commands = arm966e_command_handlers,
.target_create = arm966e_target_create,
.init_target = arm9tdmi_init_target,
.examine = arm7_9_examine,
.check_reset = arm7_9_check_reset,
};

View File

@ -0,0 +1,50 @@
/***************************************************************************
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* Copyright (C) 2008 by Spencer Oliver *
* spen@spen-soft.co.uk *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef ARM966E_H
#define ARM966E_H
#include "arm9tdmi.h"
#define ARM966E_COMMON_MAGIC 0x20f920f9
struct arm966e_common {
struct arm7_9_common arm7_9_common;
int common_magic;
uint32_t cp15_control_reg;
};
static inline struct arm966e_common *
target_to_arm966(struct target *target)
{
return container_of(target->arch_info, struct arm966e_common,
arm7_9_common.arm);
}
int arm966e_init_arch_info(struct target *target,
struct arm966e_common *arm966e, struct jtag_tap *tap);
int arm966e_write_cp15(struct target *target, int reg_addr, uint32_t value);
extern const struct command_registration arm966e_command_handlers[];
#endif /* ARM966E_H */

View File

@ -0,0 +1,923 @@
/***************************************************************************
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* Copyright (C) 2008 by Spencer Oliver *
* spen@spen-soft.co.uk *
* *
* Copyright (C) 2008 by Hongtao Zheng *
* hontor@126.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "arm9tdmi.h"
#include "target_type.h"
#include "register.h"
#include "arm_opcodes.h"
/*
* NOTE: this holds code that's used with multiple ARM9 processors:
* - ARM9TDMI (ARMv4T) ... in ARM920, ARM922, and ARM940 cores
* - ARM9E-S (ARMv5TE) ... in ARM946, ARM966, and ARM968 cores
* - ARM9EJS (ARMv5TEJ) ... in ARM926 core
*
* In short, the file name is a misnomer ... it is NOT specific to
* that first generation ARM9 processor, or cores using it.
*/
#if 0
#define _DEBUG_INSTRUCTION_EXECUTION_
#endif
enum arm9tdmi_vector_bit {
ARM9TDMI_RESET_VECTOR = 0x01,
ARM9TDMI_UNDEF_VECTOR = 0x02,
ARM9TDMI_SWI_VECTOR = 0x04,
ARM9TDMI_PABT_VECTOR = 0x08,
ARM9TDMI_DABT_VECTOR = 0x10,
/* BIT(5) reserved -- must be zero */
ARM9TDMI_IRQ_VECTOR = 0x40,
ARM9TDMI_FIQ_VECTOR = 0x80,
};
static const struct arm9tdmi_vector {
const char *name;
uint32_t value;
} arm9tdmi_vectors[] = {
{"reset", ARM9TDMI_RESET_VECTOR},
{"undef", ARM9TDMI_UNDEF_VECTOR},
{"swi", ARM9TDMI_SWI_VECTOR},
{"pabt", ARM9TDMI_PABT_VECTOR},
{"dabt", ARM9TDMI_DABT_VECTOR},
{"irq", ARM9TDMI_IRQ_VECTOR},
{"fiq", ARM9TDMI_FIQ_VECTOR},
{0, 0},
};
int arm9tdmi_examine_debug_reason(struct target *target)
{
int retval = ERROR_OK;
struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
/* only check the debug reason if we don't know it already */
if ((target->debug_reason != DBG_REASON_DBGRQ)
&& (target->debug_reason != DBG_REASON_SINGLESTEP)) {
struct scan_field fields[3];
uint8_t databus[4];
uint8_t instructionbus[4];
uint8_t debug_reason;
fields[0].num_bits = 32;
fields[0].out_value = NULL;
fields[0].in_value = databus;
fields[1].num_bits = 3;
fields[1].out_value = NULL;
fields[1].in_value = &debug_reason;
fields[2].num_bits = 32;
fields[2].out_value = NULL;
fields[2].in_value = instructionbus;
retval = arm_jtag_scann(&arm7_9->jtag_info, 0x1, TAP_DRPAUSE);
if (retval != ERROR_OK)
return retval;
retval = arm_jtag_set_instr(&arm7_9->jtag_info, arm7_9->jtag_info.intest_instr, NULL, TAP_DRPAUSE);
if (retval != ERROR_OK)
return retval;
jtag_add_dr_scan(arm7_9->jtag_info.tap, 3, fields, TAP_DRPAUSE);
retval = jtag_execute_queue();
if (retval != ERROR_OK)
return retval;
fields[0].in_value = NULL;
fields[0].out_value = databus;
fields[1].in_value = NULL;
fields[1].out_value = &debug_reason;
fields[2].in_value = NULL;
fields[2].out_value = instructionbus;
jtag_add_dr_scan(arm7_9->jtag_info.tap, 3, fields, TAP_DRPAUSE);
if (debug_reason & 0x4)
if (debug_reason & 0x2)
target->debug_reason = DBG_REASON_WPTANDBKPT;
else
target->debug_reason = DBG_REASON_WATCHPOINT;
else
target->debug_reason = DBG_REASON_BREAKPOINT;
}
return ERROR_OK;
}
/* put an instruction in the ARM9TDMI pipeline or write the data bus,
* and optionally read data
*/
int arm9tdmi_clock_out(struct arm_jtag *jtag_info, uint32_t instr,
uint32_t out, uint32_t *in, int sysspeed)
{
int retval = ERROR_OK;
struct scan_field fields[3];
uint8_t out_buf[4];
uint8_t instr_buf[4];
uint8_t sysspeed_buf = 0x0;
/* prepare buffer */
buf_set_u32(out_buf, 0, 32, out);
buf_set_u32(instr_buf, 0, 32, flip_u32(instr, 32));
if (sysspeed)
buf_set_u32(&sysspeed_buf, 2, 1, 1);
retval = arm_jtag_scann(jtag_info, 0x1, TAP_DRPAUSE);
if (retval != ERROR_OK)
return retval;
retval = arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL, TAP_DRPAUSE);
if (retval != ERROR_OK)
return retval;
fields[0].num_bits = 32;
fields[0].out_value = out_buf;
fields[0].in_value = NULL;
fields[1].num_bits = 3;
fields[1].out_value = &sysspeed_buf;
fields[1].in_value = NULL;
fields[2].num_bits = 32;
fields[2].out_value = instr_buf;
fields[2].in_value = NULL;
if (in) {
fields[0].in_value = (uint8_t *)in;
jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_DRPAUSE);
jtag_add_callback(arm_le_to_h_u32, (jtag_callback_data_t)in);
} else
jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_DRPAUSE);
jtag_add_runtest(0, TAP_DRPAUSE);
#ifdef _DEBUG_INSTRUCTION_EXECUTION_
{
retval = jtag_execute_queue();
if (retval != ERROR_OK)
return retval;
if (in)
LOG_DEBUG("instr: 0x%8.8x, out: 0x%8.8x, in: 0x%8.8x", instr, out, *in);
else
LOG_DEBUG("instr: 0x%8.8x, out: 0x%8.8x", instr, out);
}
#endif
return ERROR_OK;
}
/* just read data (instruction and data-out = don't care) */
int arm9tdmi_clock_data_in(struct arm_jtag *jtag_info, uint32_t *in)
{
int retval = ERROR_OK;
struct scan_field fields[3];
retval = arm_jtag_scann(jtag_info, 0x1, TAP_DRPAUSE);
if (retval != ERROR_OK)
return retval;
retval = arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL, TAP_DRPAUSE);
if (retval != ERROR_OK)
return retval;
fields[0].num_bits = 32;
fields[0].out_value = NULL;
fields[0].in_value = (uint8_t *)in;
fields[1].num_bits = 3;
fields[1].out_value = NULL;
fields[1].in_value = NULL;
fields[2].num_bits = 32;
fields[2].out_value = NULL;
fields[2].in_value = NULL;
jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_DRPAUSE);
jtag_add_callback(arm_le_to_h_u32, (jtag_callback_data_t)in);
jtag_add_runtest(0, TAP_DRPAUSE);
#ifdef _DEBUG_INSTRUCTION_EXECUTION_
{
retval = jtag_execute_queue();
if (retval != ERROR_OK)
return retval;
if (in)
LOG_DEBUG("in: 0x%8.8x", *in);
else
LOG_ERROR("BUG: called with in == NULL");
}
#endif
return ERROR_OK;
}
/* clock the target, and read the databus
* the *in pointer points to a buffer where elements of 'size' bytes
* are stored in big (be == 1) or little (be == 0) endianness
*/
int arm9tdmi_clock_data_in_endianness(struct arm_jtag *jtag_info,
void *in, int size, int be)
{
int retval = ERROR_OK;
struct scan_field fields[2];
retval = arm_jtag_scann(jtag_info, 0x1, TAP_DRPAUSE);
if (retval != ERROR_OK)
return retval;
retval = arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL, TAP_DRPAUSE);
if (retval != ERROR_OK)
return retval;
if (size == 4) {
fields[0].num_bits = 32;
fields[0].out_value = NULL;
fields[0].in_value = in;
fields[1].num_bits = 3 + 32;
fields[1].out_value = NULL;
fields[1].in_value = NULL;
} else {
/* Discard irrelevant bits of the scan, making sure we don't write more
* than size bytes to in */
fields[0].num_bits = size * 8;
fields[0].out_value = NULL;
fields[0].in_value = in;
fields[1].num_bits = 3 + 32 + 32 - size * 8;
fields[1].out_value = NULL;
fields[1].in_value = NULL;
}
jtag_add_dr_scan(jtag_info->tap, 2, fields, TAP_DRPAUSE);
jtag_add_callback4(arm7_9_endianness_callback,
(jtag_callback_data_t)in,
(jtag_callback_data_t)size,
(jtag_callback_data_t)be,
(jtag_callback_data_t)0);
jtag_add_runtest(0, TAP_DRPAUSE);
#ifdef _DEBUG_INSTRUCTION_EXECUTION_
{
retval = jtag_execute_queue();
if (retval != ERROR_OK)
return retval;
if (in)
LOG_DEBUG("in: 0x%8.8x", *(uint32_t *)in);
else
LOG_ERROR("BUG: called with in == NULL");
}
#endif
return ERROR_OK;
}
static void arm9tdmi_change_to_arm(struct target *target,
uint32_t *r0, uint32_t *pc)
{
int retval = ERROR_OK;
struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
struct arm_jtag *jtag_info = &arm7_9->jtag_info;
/* save r0 before using it and put system in ARM state
* to allow common handling of ARM and THUMB debugging */
/* fetch STR r0, [r0] */
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_STR(0, 0), 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
/* STR r0, [r0] in Memory */
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, r0, 0);
/* MOV r0, r15 fetched, STR in Decode */
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_MOV(0, 15), 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_STR(0, 0), 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
/* nothing fetched, STR r0, [r0] in Memory */
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, pc, 0);
/* use pc-relative LDR to clear r0[1:0] (for switch to ARM mode) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_LDR_PCREL(0), 0, NULL, 0);
/* LDR in Decode */
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
/* LDR in Execute */
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
/* LDR in Memory (to account for interlock) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
/* fetch BX */
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_BX(0), 0, NULL, 0);
/* NOP fetched, BX in Decode, MOV in Execute */
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
/* NOP fetched, BX in Execute (1) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
retval = jtag_execute_queue();
if (retval != ERROR_OK)
return;
/* fix program counter:
* MOV r0, r15 was the 5th instruction (+8)
* reading PC in Thumb state gives address of instruction + 4
*/
*pc -= 0xc;
}
void arm9tdmi_read_core_regs(struct target *target,
uint32_t mask, uint32_t *core_regs[16])
{
int i;
struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
struct arm_jtag *jtag_info = &arm7_9->jtag_info;
/* STMIA r0-15, [r0] at debug speed
* register values will start to appear on 4th DCLK
*/
arm9tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask & 0xffff, 0, 0), 0, NULL, 0);
/* fetch NOP, STM in DECODE stage */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* fetch NOP, STM in EXECUTE stage (1st cycle) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
for (i = 0; i <= 15; i++) {
if (mask & (1 << i))
/* nothing fetched, STM in MEMORY (i'th cycle) */
arm9tdmi_clock_data_in(jtag_info, core_regs[i]);
}
}
static void arm9tdmi_read_core_regs_target_buffer(struct target *target,
uint32_t mask, void *buffer, int size)
{
int i;
struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
struct arm_jtag *jtag_info = &arm7_9->jtag_info;
int be = (target->endianness == TARGET_BIG_ENDIAN) ? 1 : 0;
uint32_t *buf_u32 = buffer;
uint16_t *buf_u16 = buffer;
uint8_t *buf_u8 = buffer;
/* STMIA r0-15, [r0] at debug speed
* register values will start to appear on 4th DCLK
*/
arm9tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask & 0xffff, 0, 0), 0, NULL, 0);
/* fetch NOP, STM in DECODE stage */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* fetch NOP, STM in EXECUTE stage (1st cycle) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
for (i = 0; i <= 15; i++) {
if (mask & (1 << i))
/* nothing fetched, STM in MEMORY (i'th cycle) */
switch (size) {
case 4:
arm9tdmi_clock_data_in_endianness(jtag_info, buf_u32++, 4, be);
break;
case 2:
arm9tdmi_clock_data_in_endianness(jtag_info, buf_u16++, 2, be);
break;
case 1:
arm9tdmi_clock_data_in_endianness(jtag_info, buf_u8++, 1, be);
break;
}
}
}
static void arm9tdmi_read_xpsr(struct target *target, uint32_t *xpsr, int spsr)
{
struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
struct arm_jtag *jtag_info = &arm7_9->jtag_info;
/* MRS r0, cpsr */
arm9tdmi_clock_out(jtag_info, ARMV4_5_MRS(0, spsr & 1), 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* STR r0, [r15] */
arm9tdmi_clock_out(jtag_info, ARMV4_5_STR(0, 15), 0, NULL, 0);
/* fetch NOP, STR in DECODE stage */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* fetch NOP, STR in EXECUTE stage (1st cycle) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* nothing fetched, STR in MEMORY */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, xpsr, 0);
}
static void arm9tdmi_write_xpsr(struct target *target, uint32_t xpsr, int spsr)
{
struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
struct arm_jtag *jtag_info = &arm7_9->jtag_info;
LOG_DEBUG("xpsr: %8.8" PRIx32 ", spsr: %i", xpsr, spsr);
/* MSR1 fetched */
arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM(xpsr & 0xff, 0, 1, spsr), 0, NULL, 0);
/* MSR2 fetched, MSR1 in DECODE */
arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff00) >> 8, 0xc, 2, spsr), 0, NULL, 0);
/* MSR3 fetched, MSR1 in EXECUTE (1), MSR2 in DECODE */
arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff0000) >> 16, 0x8, 4, spsr), 0, NULL, 0);
/* nothing fetched, MSR1 in EXECUTE (2) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* nothing fetched, MSR1 in EXECUTE (3) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* MSR4 fetched, MSR2 in EXECUTE (1), MSR3 in DECODE */
arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff000000) >> 24, 0x4, 8, spsr), 0, NULL, 0);
/* nothing fetched, MSR2 in EXECUTE (2) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* nothing fetched, MSR2 in EXECUTE (3) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* NOP fetched, MSR3 in EXECUTE (1), MSR4 in DECODE */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* nothing fetched, MSR3 in EXECUTE (2) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* nothing fetched, MSR3 in EXECUTE (3) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* NOP fetched, MSR4 in EXECUTE (1) */
/* last MSR writes flags, which takes only one cycle */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
}
static void arm9tdmi_write_xpsr_im8(struct target *target,
uint8_t xpsr_im, int rot, int spsr)
{
struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
struct arm_jtag *jtag_info = &arm7_9->jtag_info;
LOG_DEBUG("xpsr_im: %2.2x, rot: %i, spsr: %i", xpsr_im, rot, spsr);
/* MSR fetched */
arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM(xpsr_im, rot, 1, spsr), 0, NULL, 0);
/* NOP fetched, MSR in DECODE */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* NOP fetched, MSR in EXECUTE (1) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* rot == 4 writes flags, which takes only one cycle */
if (rot != 4) {
/* nothing fetched, MSR in EXECUTE (2) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* nothing fetched, MSR in EXECUTE (3) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
}
}
void arm9tdmi_write_core_regs(struct target *target,
uint32_t mask, uint32_t core_regs[16])
{
int i;
struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
struct arm_jtag *jtag_info = &arm7_9->jtag_info;
/* LDMIA r0-15, [r0] at debug speed
* register values will start to appear on 4th DCLK
*/
arm9tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, mask & 0xffff, 0, 0), 0, NULL, 0);
/* fetch NOP, LDM in DECODE stage */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* fetch NOP, LDM in EXECUTE stage (1st cycle) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
for (i = 0; i <= 15; i++) {
if (mask & (1 << i))
/* nothing fetched, LDM still in EXECUTE (1 + i cycle) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, core_regs[i], NULL, 0);
}
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
}
void arm9tdmi_load_word_regs(struct target *target, uint32_t mask)
{
struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
struct arm_jtag *jtag_info = &arm7_9->jtag_info;
/* put system-speed load-multiple into the pipeline */
arm9tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, mask & 0xffff, 0, 1), 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1);
}
void arm9tdmi_load_hword_reg(struct target *target, int num)
{
struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
struct arm_jtag *jtag_info = &arm7_9->jtag_info;
/* put system-speed load half-word into the pipeline */
arm9tdmi_clock_out(jtag_info, ARMV4_5_LDRH_IP(num, 0), 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1);
}
void arm9tdmi_load_byte_reg(struct target *target, int num)
{
struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
struct arm_jtag *jtag_info = &arm7_9->jtag_info;
/* put system-speed load byte into the pipeline */
arm9tdmi_clock_out(jtag_info, ARMV4_5_LDRB_IP(num, 0), 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1);
}
void arm9tdmi_store_word_regs(struct target *target, uint32_t mask)
{
struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
struct arm_jtag *jtag_info = &arm7_9->jtag_info;
/* put system-speed store-multiple into the pipeline */
arm9tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask, 0, 1), 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1);
}
void arm9tdmi_store_hword_reg(struct target *target, int num)
{
struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
struct arm_jtag *jtag_info = &arm7_9->jtag_info;
/* put system-speed store half-word into the pipeline */
arm9tdmi_clock_out(jtag_info, ARMV4_5_STRH_IP(num, 0), 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1);
}
void arm9tdmi_store_byte_reg(struct target *target, int num)
{
struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
struct arm_jtag *jtag_info = &arm7_9->jtag_info;
/* put system-speed store byte into the pipeline */
arm9tdmi_clock_out(jtag_info, ARMV4_5_STRB_IP(num, 0), 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1);
}
static void arm9tdmi_write_pc(struct target *target, uint32_t pc)
{
struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
struct arm_jtag *jtag_info = &arm7_9->jtag_info;
/* LDMIA r0-15, [r0] at debug speed
* register values will start to appear on 4th DCLK
*/
arm9tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, 0x8000, 0, 0), 0, NULL, 0);
/* fetch NOP, LDM in DECODE stage */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* fetch NOP, LDM in EXECUTE stage (1st cycle) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* nothing fetched, LDM in EXECUTE stage (2nd cycle) (output data) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, pc, NULL, 0);
/* nothing fetched, LDM in EXECUTE stage (3rd cycle) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* fetch NOP, LDM in EXECUTE stage (4th cycle) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* fetch NOP, LDM in EXECUTE stage (5th cycle) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
}
void arm9tdmi_branch_resume(struct target *target)
{
struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
struct arm_jtag *jtag_info = &arm7_9->jtag_info;
arm9tdmi_clock_out(jtag_info, ARMV4_5_B(0xfffffc, 0), 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1);
}
static void arm9tdmi_branch_resume_thumb(struct target *target)
{
LOG_DEBUG("-");
struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
struct arm *arm = &arm7_9->arm;
struct arm_jtag *jtag_info = &arm7_9->jtag_info;
struct reg *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT];
/* LDMIA r0-15, [r0] at debug speed
* register values will start to appear on 4th DCLK
*/
arm9tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, 0x1, 0, 0), 0, NULL, 0);
/* fetch NOP, LDM in DECODE stage */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* fetch NOP, LDM in EXECUTE stage (1st cycle) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* nothing fetched, LDM in EXECUTE stage (2nd cycle) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP,
buf_get_u32(arm->pc->value, 0, 32) | 1, NULL, 0);
/* nothing fetched, LDM in EXECUTE stage (3rd cycle) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* Branch and eXchange */
arm9tdmi_clock_out(jtag_info, ARMV4_5_BX(0), 0, NULL, 0);
embeddedice_read_reg(dbg_stat);
/* fetch NOP, BX in DECODE stage */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
embeddedice_read_reg(dbg_stat);
/* fetch NOP, BX in EXECUTE stage (1st cycle) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* target is now in Thumb state */
embeddedice_read_reg(dbg_stat);
/* load r0 value, MOV_IM in Decode*/
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_LDR_PCREL(0), 0, NULL, 0);
/* fetch NOP, LDR in Decode, MOV_IM in Execute */
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
/* fetch NOP, LDR in Execute */
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
/* nothing fetched, LDR in EXECUTE stage (2nd cycle) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP,
buf_get_u32(arm->core_cache->reg_list[0].value, 0, 32), NULL, 0);
/* nothing fetched, LDR in EXECUTE stage (3rd cycle) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
embeddedice_read_reg(dbg_stat);
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_B(0x7f7), 0, NULL, 1);
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
}
void arm9tdmi_enable_single_step(struct target *target, uint32_t next_pc)
{
struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
if (arm7_9->has_single_step) {
buf_set_u32(arm7_9->eice_cache->reg_list[EICE_DBG_CTRL].value, 3, 1, 1);
embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_DBG_CTRL]);
} else
arm7_9_enable_eice_step(target, next_pc);
}
void arm9tdmi_disable_single_step(struct target *target)
{
struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
if (arm7_9->has_single_step) {
buf_set_u32(arm7_9->eice_cache->reg_list[EICE_DBG_CTRL].value, 3, 1, 0);
embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_DBG_CTRL]);
} else
arm7_9_disable_eice_step(target);
}
static void arm9tdmi_build_reg_cache(struct target *target)
{
struct reg_cache **cache_p = register_get_last_cache_p(&target->reg_cache);
struct arm *arm = target_to_arm(target);
(*cache_p) = arm_build_reg_cache(target, arm);
}
int arm9tdmi_init_target(struct command_context *cmd_ctx,
struct target *target)
{
arm9tdmi_build_reg_cache(target);
return ERROR_OK;
}
int arm9tdmi_init_arch_info(struct target *target,
struct arm7_9_common *arm7_9, struct jtag_tap *tap)
{
/* prepare JTAG information for the new target */
arm7_9->jtag_info.tap = tap;
arm7_9->jtag_info.scann_size = 5;
/* register arch-specific functions */
arm7_9->examine_debug_reason = arm9tdmi_examine_debug_reason;
arm7_9->change_to_arm = arm9tdmi_change_to_arm;
arm7_9->read_core_regs = arm9tdmi_read_core_regs;
arm7_9->read_core_regs_target_buffer = arm9tdmi_read_core_regs_target_buffer;
arm7_9->read_xpsr = arm9tdmi_read_xpsr;
arm7_9->write_xpsr = arm9tdmi_write_xpsr;
arm7_9->write_xpsr_im8 = arm9tdmi_write_xpsr_im8;
arm7_9->write_core_regs = arm9tdmi_write_core_regs;
arm7_9->load_word_regs = arm9tdmi_load_word_regs;
arm7_9->load_hword_reg = arm9tdmi_load_hword_reg;
arm7_9->load_byte_reg = arm9tdmi_load_byte_reg;
arm7_9->store_word_regs = arm9tdmi_store_word_regs;
arm7_9->store_hword_reg = arm9tdmi_store_hword_reg;
arm7_9->store_byte_reg = arm9tdmi_store_byte_reg;
arm7_9->write_pc = arm9tdmi_write_pc;
arm7_9->branch_resume = arm9tdmi_branch_resume;
arm7_9->branch_resume_thumb = arm9tdmi_branch_resume_thumb;
arm7_9->enable_single_step = arm9tdmi_enable_single_step;
arm7_9->disable_single_step = arm9tdmi_disable_single_step;
arm7_9->post_debug_entry = NULL;
arm7_9->pre_restore_context = NULL;
/* initialize arch-specific breakpoint handling */
arm7_9->arm_bkpt = 0xdeeedeee;
arm7_9->thumb_bkpt = 0xdeee;
arm7_9->dbgreq_adjust_pc = 3;
arm7_9_init_arch_info(target, arm7_9);
/* override use of DBGRQ, this is safe on ARM9TDMI */
arm7_9->use_dbgrq = 1;
/* all ARM9s have the vector catch register */
arm7_9->has_vector_catch = 1;
return ERROR_OK;
}
static int arm9tdmi_target_create(struct target *target, Jim_Interp *interp)
{
struct arm7_9_common *arm7_9 = calloc(1, sizeof(struct arm7_9_common));
arm9tdmi_init_arch_info(target, arm7_9, target->tap);
arm7_9->arm.is_armv4 = true;
return ERROR_OK;
}
COMMAND_HANDLER(handle_arm9tdmi_catch_vectors_command)
{
struct target *target = get_current_target(CMD_CTX);
struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
struct reg *vector_catch;
uint32_t vector_catch_value;
if (!target_was_examined(target)) {
LOG_ERROR("Target not examined yet");
return ERROR_FAIL;
}
/* it's uncommon, but some ARM7 chips can support this */
if (arm7_9->common_magic != ARM7_9_COMMON_MAGIC
|| !arm7_9->has_vector_catch) {
command_print(CMD_CTX, "target doesn't have EmbeddedICE "
"with vector_catch");
return ERROR_TARGET_INVALID;
}
vector_catch = &arm7_9->eice_cache->reg_list[EICE_VEC_CATCH];
/* read the vector catch register if necessary */
if (!vector_catch->valid)
embeddedice_read_reg(vector_catch);
/* get the current setting */
vector_catch_value = buf_get_u32(vector_catch->value, 0, 8);
if (CMD_ARGC > 0) {
vector_catch_value = 0x0;
if (strcmp(CMD_ARGV[0], "all") == 0)
vector_catch_value = 0xdf;
else if (strcmp(CMD_ARGV[0], "none") == 0) {
/* do nothing */
} else {
for (unsigned i = 0; i < CMD_ARGC; i++) {
/* go through list of vectors */
unsigned j;
for (j = 0; arm9tdmi_vectors[j].name; j++) {
if (strcmp(CMD_ARGV[i], arm9tdmi_vectors[j].name) == 0) {
vector_catch_value |= arm9tdmi_vectors[j].value;
break;
}
}
/* complain if vector wasn't found */
if (!arm9tdmi_vectors[j].name) {
command_print(CMD_CTX, "vector '%s' not found, leaving current setting unchanged", CMD_ARGV[i]);
/* reread current setting */
vector_catch_value = buf_get_u32(
vector_catch->value,
0, 8);
break;
}
}
}
/* store new settings */
buf_set_u32(vector_catch->value, 0, 8, vector_catch_value);
embeddedice_store_reg(vector_catch);
}
/* output current settings */
for (unsigned i = 0; arm9tdmi_vectors[i].name; i++) {
command_print(CMD_CTX, "%s: %s", arm9tdmi_vectors[i].name,
(vector_catch_value & arm9tdmi_vectors[i].value)
? "catch" : "don't catch");
}
return ERROR_OK;
}
static const struct command_registration arm9tdmi_exec_command_handlers[] = {
{
.name = "vector_catch",
.handler = handle_arm9tdmi_catch_vectors_command,
.mode = COMMAND_EXEC,
.help = "Display, after optionally updating, configuration "
"of vector catch unit.",
.usage = "[all|none|(reset|undef|swi|pabt|dabt|irq|fiq)*]",
},
COMMAND_REGISTRATION_DONE
};
const struct command_registration arm9tdmi_command_handlers[] = {
{
.chain = arm7_9_command_handlers,
},
{
.name = "arm9",
.mode = COMMAND_ANY,
.help = "arm9 command group",
.usage = "",
.chain = arm9tdmi_exec_command_handlers,
},
COMMAND_REGISTRATION_DONE
};
/** Holds methods for ARM9TDMI targets. */
struct target_type arm9tdmi_target = {
.name = "arm9tdmi",
.poll = arm7_9_poll,
.arch_state = arm_arch_state,
.target_request_data = arm7_9_target_request_data,
.halt = arm7_9_halt,
.resume = arm7_9_resume,
.step = arm7_9_step,
.assert_reset = arm7_9_assert_reset,
.deassert_reset = arm7_9_deassert_reset,
.soft_reset_halt = arm7_9_soft_reset_halt,
.get_gdb_reg_list = arm_get_gdb_reg_list,
.read_memory = arm7_9_read_memory,
.write_memory = arm7_9_write_memory,
.bulk_write_memory = arm7_9_bulk_write_memory,
.checksum_memory = arm_checksum_memory,
.blank_check_memory = arm_blank_check_memory,
.run_algorithm = armv4_5_run_algorithm,
.add_breakpoint = arm7_9_add_breakpoint,
.remove_breakpoint = arm7_9_remove_breakpoint,
.add_watchpoint = arm7_9_add_watchpoint,
.remove_watchpoint = arm7_9_remove_watchpoint,
.commands = arm9tdmi_command_handlers,
.target_create = arm9tdmi_target_create,
.init_target = arm9tdmi_init_target,
.examine = arm7_9_examine,
.check_reset = arm7_9_check_reset,
};

View File

@ -0,0 +1,58 @@
/***************************************************************************
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* Copyright (C) 2008 by Spencer Oliver *
* spen@spen-soft.co.uk *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef ARM9TDMI_H
#define ARM9TDMI_H
#include "embeddedice.h"
int arm9tdmi_init_target(struct command_context *cmd_ctx,
struct target *target);
int arm9tdmi_init_arch_info(struct target *target,
struct arm7_9_common *arm7_9, struct jtag_tap *tap);
extern const struct command_registration arm9tdmi_command_handlers[];
int arm9tdmi_clock_out(struct arm_jtag *jtag_info,
uint32_t instr, uint32_t out, uint32_t *in, int sysspeed);
int arm9tdmi_clock_data_in(struct arm_jtag *jtag_info, uint32_t *in);
int arm9tdmi_clock_data_in_endianness(struct arm_jtag *jtag_info,
void *in, int size, int be);
void arm9tdmi_read_core_regs(struct target *target,
uint32_t mask, uint32_t *core_regs[16]);
void arm9tdmi_write_core_regs(struct target *target,
uint32_t mask, uint32_t core_regs[16]);
int arm9tdmi_examine_debug_reason(struct target *target);
void arm9tdmi_load_word_regs(struct target *target, uint32_t mask);
void arm9tdmi_load_hword_reg(struct target *target, int num);
void arm9tdmi_load_byte_reg(struct target *target, int num);
void arm9tdmi_store_word_regs(struct target *target, uint32_t mask);
void arm9tdmi_store_hword_reg(struct target *target, int num);
void arm9tdmi_store_byte_reg(struct target *target, int num);
void arm9tdmi_branch_resume(struct target *target);
void arm9tdmi_enable_single_step(struct target *target, uint32_t next_pc);
void arm9tdmi_disable_single_step(struct target *target);
#endif /* ARM9TDMI_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,477 @@
/***************************************************************************
* Copyright (C) 2006 by Magnus Lundin *
* lundin@mlu.mine.nu *
* *
* Copyright (C) 2008 by Spencer Oliver *
* spen@spen-soft.co.uk *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef ARM_ADI_V5_H
#define ARM_ADI_V5_H
/**
* @file
* This defines formats and data structures used to talk to ADIv5 entities.
* Those include a DAP, different types of Debug Port (DP), and memory mapped
* resources accessed through a MEM-AP.
*/
#include "arm_jtag.h"
/* FIXME remove these JTAG-specific decls when mem_ap_read_buf_u32()
* is no longer JTAG-specific
*/
#define JTAG_DP_DPACC 0xA
#define JTAG_DP_APACC 0xB
/* three-bit ACK values for SWD access (sent LSB first) */
#define SWD_ACK_OK 0x4
#define SWD_ACK_WAIT 0x2
#define SWD_ACK_FAULT 0x1
#define DPAP_WRITE 0
#define DPAP_READ 1
/* A[3:0] for DP registers; A[1:0] are always zero.
* - JTAG accesses all of these via JTAG_DP_DPACC, except for
* IDCODE (JTAG_DP_IDCODE) and ABORT (JTAG_DP_ABORT).
* - SWD accesses these directly, sometimes needing SELECT.CTRLSEL
*/
#define DP_IDCODE 0 /* SWD: read */
#define DP_ABORT 0 /* SWD: write */
#define DP_CTRL_STAT 0x4 /* r/w */
#define DP_WCR 0x4 /* SWD: r/w (mux CTRLSEL) */
#define DP_RESEND 0x8 /* SWD: read */
#define DP_SELECT 0x8 /* JTAG: r/w; SWD: write */
#define DP_RDBUFF 0xC /* read-only */
#define WCR_TO_TRN(wcr) (1 + (3 & ((wcr)) >> 8)) /* 1..4 clocks */
#define WCR_TO_PRESCALE(wcr) (7 & ((wcr))) /* impl defined */
/* Fields of the DP's AP ABORT register */
#define DAPABORT (1 << 0)
#define STKCMPCLR (1 << 1) /* SWD-only */
#define STKERRCLR (1 << 2) /* SWD-only */
#define WDERRCLR (1 << 3) /* SWD-only */
#define ORUNERRCLR (1 << 4) /* SWD-only */
/* Fields of the DP's CTRL/STAT register */
#define CORUNDETECT (1 << 0)
#define SSTICKYORUN (1 << 1)
/* 3:2 - transaction mode (e.g. pushed compare) */
#define SSTICKYCMP (1 << 4)
#define SSTICKYERR (1 << 5)
#define READOK (1 << 6) /* SWD-only */
#define WDATAERR (1 << 7) /* SWD-only */
/* 11:8 - mask lanes for pushed compare or verify ops */
/* 21:12 - transaction counter */
#define CDBGRSTREQ (1 << 26)
#define CDBGRSTACK (1 << 27)
#define CDBGPWRUPREQ (1 << 28)
#define CDBGPWRUPACK (1 << 29)
#define CSYSPWRUPREQ (1 << 30)
#define CSYSPWRUPACK (1 << 31)
/* MEM-AP register addresses */
/* TODO: rename as MEM_AP_REG_* */
#define AP_REG_CSW 0x00
#define AP_REG_TAR 0x04
#define AP_REG_DRW 0x0C
#define AP_REG_BD0 0x10
#define AP_REG_BD1 0x14
#define AP_REG_BD2 0x18
#define AP_REG_BD3 0x1C
#define AP_REG_CFG 0xF4 /* big endian? */
#define AP_REG_BASE 0xF8
/* Generic AP register address */
#define AP_REG_IDR 0xFC
/* Fields of the MEM-AP's CSW register */
#define CSW_8BIT 0
#define CSW_16BIT 1
#define CSW_32BIT 2
#define CSW_ADDRINC_MASK (3 << 4)
#define CSW_ADDRINC_OFF 0
#define CSW_ADDRINC_SINGLE (1 << 4)
#define CSW_ADDRINC_PACKED (2 << 4)
#define CSW_DEVICE_EN (1 << 6)
#define CSW_TRIN_PROG (1 << 7)
#define CSW_SPIDEN (1 << 23)
/* 30:24 - implementation-defined! */
#define CSW_HPROT (1 << 25) /* ? */
#define CSW_MASTER_DEBUG (1 << 29) /* ? */
#define CSW_SPROT (1 << 30)
#define CSW_DBGSWENABLE (1 << 31)
/**
* This represents an ARM Debug Interface (v5) Debug Access Port (DAP).
* A DAP has two types of component: one Debug Port (DP), which is a
* transport agent; and at least one Access Port (AP), controlling
* resource access. Most common is a MEM-AP, for memory access.
*
* There are two basic DP transports: JTAG, and ARM's low pin-count SWD.
* Accordingly, this interface is responsible for hiding the transport
* differences so upper layer code can largely ignore them.
*
* When the chip is implemented with JTAG-DP or SW-DP, the transport is
* fixed as JTAG or SWD, respectively. Chips incorporating SWJ-DP permit
* a choice made at board design time (by only using the SWD pins), or
* as part of setting up a debug session (if all the dual-role JTAG/SWD
* signals are available).
*/
struct adiv5_dap {
const struct dap_ops *ops;
struct arm_jtag *jtag_info;
/* Control config */
uint32_t dp_ctrl_stat;
uint32_t apcsw[256];
uint32_t apsel;
/**
* Cache for DP_SELECT bits identifying the current AP. A DAP may
* connect to multiple APs, such as one MEM-AP for general access,
* another reserved for accessing debug modules, and a JTAG-DP.
* "-1" indicates no cached value.
*/
uint32_t ap_current;
/**
* Cache for DP_SELECT bits identifying the current four-word AP
* register bank. This caches AP register addresss bits 7:4; JTAG
* and SWD access primitves pass address bits 3:2; bits 1:0 are zero.
* "-1" indicates no cached value.
*/
uint32_t ap_bank_value;
/**
* Cache for (MEM-AP) AP_REG_CSW register value. This is written to
* configure an access mode, such as autoincrementing AP_REG_TAR during
* word access. "-1" indicates no cached value.
*/
uint32_t ap_csw_value;
/**
* Cache for (MEM-AP) AP_REG_TAR register value This is written to
* configure the address being read or written
* "-1" indicates no cached value.
*/
uint32_t ap_tar_value;
/* information about current pending SWjDP-AHBAP transaction */
uint8_t ack;
/**
* Configures how many extra tck clocks are added after starting a
* MEM-AP access before we try to read its status (and/or result).
*/
uint32_t memaccess_tck;
/* Size of TAR autoincrement block, ARM ADI Specification requires at least 10 bits */
uint32_t tar_autoincr_block;
};
/**
* Transport-neutral representation of queued DAP transactions, supporting
* both JTAG and SWD transports. All submitted transactions are logically
* queued, until the queue is executed by run(). Some implementations might
* execute transactions as soon as they're submitted, but no status is made
* availablue until run().
*/
struct dap_ops {
/** If the DAP transport isn't SWD, it must be JTAG. Upper level
* code may need to care about the difference in some cases.
*/
bool is_swd;
/** Reads the DAP's IDCODe register. */
int (*queue_idcode_read)(struct adiv5_dap *dap,
uint8_t *ack, uint32_t *data);
/** DP register read. */
int (*queue_dp_read)(struct adiv5_dap *dap, unsigned reg,
uint32_t *data);
/** DP register write. */
int (*queue_dp_write)(struct adiv5_dap *dap, unsigned reg,
uint32_t data);
/** AP register read. */
int (*queue_ap_read)(struct adiv5_dap *dap, unsigned reg,
uint32_t *data);
/** AP register write. */
int (*queue_ap_write)(struct adiv5_dap *dap, unsigned reg,
uint32_t data);
/** AP read block. */
int (*queue_ap_read_block)(struct adiv5_dap *dap, unsigned reg,
uint32_t blocksize, uint8_t *buffer);
/** AP operation abort. */
int (*queue_ap_abort)(struct adiv5_dap *dap, uint8_t *ack);
/** Executes all queued DAP operations. */
int (*run)(struct adiv5_dap *dap);
};
/*
* Access Port types
*/
enum ap_type {
AP_TYPE_AHB_AP = 0x01, /* AHB Memory-AP */
AP_TYPE_APB_AP = 0x02, /* APB Memory-AP */
AP_TYPE_JTAG_AP = 0x10 /* JTAG-AP - JTAG master for controlling other JTAG devices */
};
/**
* Queue an IDCODE register read. This is primarily useful for SWD
* transports, where it is required as part of link initialization.
* (For JTAG, this register is read as part of scan chain setup.)
*
* @param dap The DAP used for reading.
* @param ack Pointer to where transaction status will be stored.
* @param data Pointer saying where to store the IDCODE value.
*
* @return ERROR_OK for success, else a fault code.
*/
static inline int dap_queue_idcode_read(struct adiv5_dap *dap,
uint8_t *ack, uint32_t *data)
{
assert(dap->ops != NULL);
return dap->ops->queue_idcode_read(dap, ack, data);
}
/**
* Queue a DP register read.
* Note that not all DP registers are readable; also, that JTAG and SWD
* have slight differences in DP register support.
*
* @param dap The DAP used for reading.
* @param reg The two-bit number of the DP register being read.
* @param data Pointer saying where to store the register's value
* (in host endianness).
*
* @return ERROR_OK for success, else a fault code.
*/
static inline int dap_queue_dp_read(struct adiv5_dap *dap,
unsigned reg, uint32_t *data)
{
assert(dap->ops != NULL);
return dap->ops->queue_dp_read(dap, reg, data);
}
/**
* Queue a DP register write.
* Note that not all DP registers are writable; also, that JTAG and SWD
* have slight differences in DP register support.
*
* @param dap The DAP used for writing.
* @param reg The two-bit number of the DP register being written.
* @param data Value being written (host endianness)
*
* @return ERROR_OK for success, else a fault code.
*/
static inline int dap_queue_dp_write(struct adiv5_dap *dap,
unsigned reg, uint32_t data)
{
assert(dap->ops != NULL);
return dap->ops->queue_dp_write(dap, reg, data);
}
/**
* Queue an AP register read.
*
* @param dap The DAP used for reading.
* @param reg The number of the AP register being read.
* @param data Pointer saying where to store the register's value
* (in host endianness).
*
* @return ERROR_OK for success, else a fault code.
*/
static inline int dap_queue_ap_read(struct adiv5_dap *dap,
unsigned reg, uint32_t *data)
{
assert(dap->ops != NULL);
return dap->ops->queue_ap_read(dap, reg, data);
}
/**
* Queue an AP register write.
*
* @param dap The DAP used for writing.
* @param reg The number of the AP register being written.
* @param data Value being written (host endianness)
*
* @return ERROR_OK for success, else a fault code.
*/
static inline int dap_queue_ap_write(struct adiv5_dap *dap,
unsigned reg, uint32_t data)
{
assert(dap->ops != NULL);
return dap->ops->queue_ap_write(dap, reg, data);
}
/**
* Queue an AP block read.
*
* @param dap The DAP used for reading.
* @param reg The number of the AP register being read.
* @param blocksize The number of the AP register being read.
* @param buffer Pointer saying where to store the data
* (in host endianness).
*
* @return ERROR_OK for success, else a fault code.
*/
static inline int dap_queue_ap_read_block(struct adiv5_dap *dap,
unsigned reg, unsigned blocksize, uint8_t *buffer)
{
assert(dap->ops != NULL);
return dap->ops->queue_ap_read_block(dap, reg, blocksize, buffer);
}
/**
* Queue an AP abort operation. The current AP transaction is aborted,
* including any update of the transaction counter. The AP is left in
* an unknown state (so it must be re-initialized). For use only after
* the AP has reported WAIT status for an extended period.
*
* @param dap The DAP used for writing.
* @param ack Pointer to where transaction status will be stored.
*
* @return ERROR_OK for success, else a fault code.
*/
static inline int dap_queue_ap_abort(struct adiv5_dap *dap, uint8_t *ack)
{
assert(dap->ops != NULL);
return dap->ops->queue_ap_abort(dap, ack);
}
/**
* Perform all queued DAP operations, and clear any errors posted in the
* CTRL_STAT register when they are done. Note that if more than one AP
* operation will be queued, one of the first operations in the queue
* should probably enable CORUNDETECT in the CTRL/STAT register.
*
* @param dap The DAP used.
*
* @return ERROR_OK for success, else a fault code.
*/
static inline int dap_run(struct adiv5_dap *dap)
{
assert(dap->ops != NULL);
return dap->ops->run(dap);
}
/** Accessor for currently selected DAP-AP number (0..255) */
static inline uint8_t dap_ap_get_select(struct adiv5_dap *swjdp)
{
return (uint8_t)(swjdp->ap_current >> 24);
}
/* AP selection applies to future AP transactions */
void dap_ap_select(struct adiv5_dap *dap, uint8_t ap);
/* Queued AP transactions */
int dap_setup_accessport(struct adiv5_dap *swjdp,
uint32_t csw, uint32_t tar);
/* Queued MEM-AP memory mapped single word transfers */
int mem_ap_read_u32(struct adiv5_dap *swjdp, uint32_t address, uint32_t *value);
int mem_ap_write_u32(struct adiv5_dap *swjdp, uint32_t address, uint32_t value);
/* Synchronous MEM-AP memory mapped single word transfers */
int mem_ap_read_atomic_u32(struct adiv5_dap *swjdp,
uint32_t address, uint32_t *value);
int mem_ap_write_atomic_u32(struct adiv5_dap *swjdp,
uint32_t address, uint32_t value);
/* MEM-AP memory mapped bus block transfers */
int mem_ap_read_buf_u8(struct adiv5_dap *swjdp,
uint8_t *buffer, int count, uint32_t address);
int mem_ap_read_buf_u16(struct adiv5_dap *swjdp,
uint8_t *buffer, int count, uint32_t address);
int mem_ap_read_buf_u32(struct adiv5_dap *swjdp,
uint8_t *buffer, int count, uint32_t address, bool addr_incr);
int mem_ap_write_buf_u8(struct adiv5_dap *swjdp,
const uint8_t *buffer, int count, uint32_t address);
int mem_ap_write_buf_u16(struct adiv5_dap *swjdp,
const uint8_t *buffer, int count, uint32_t address);
int mem_ap_write_buf_u32(struct adiv5_dap *swjdp,
const uint8_t *buffer, int count, uint32_t address, bool addr_incr);
/* Queued MEM-AP memory mapped single word transfers with selection of ap */
int mem_ap_sel_read_u32(struct adiv5_dap *swjdp, uint8_t ap,
uint32_t address, uint32_t *value);
int mem_ap_sel_write_u32(struct adiv5_dap *swjdp, uint8_t ap,
uint32_t address, uint32_t value);
/* Synchronous MEM-AP memory mapped single word transfers with selection of ap */
int mem_ap_sel_read_atomic_u32(struct adiv5_dap *swjdp, uint8_t ap,
uint32_t address, uint32_t *value);
int mem_ap_sel_write_atomic_u32(struct adiv5_dap *swjdp, uint8_t ap,
uint32_t address, uint32_t value);
/* Non incrementing buffer functions for accessing fifos */
int mem_ap_sel_read_buf_u32_noincr(struct adiv5_dap *swjdp, uint8_t ap,
uint8_t *buffer, int count, uint32_t address);
int mem_ap_sel_write_buf_u32_noincr(struct adiv5_dap *swjdp, uint8_t ap,
const uint8_t *buffer, int count, uint32_t address);
/* MEM-AP memory mapped bus block transfers with selection of ap */
int mem_ap_sel_read_buf_u8(struct adiv5_dap *swjdp, uint8_t ap,
uint8_t *buffer, int count, uint32_t address);
int mem_ap_sel_read_buf_u16(struct adiv5_dap *swjdp, uint8_t ap,
uint8_t *buffer, int count, uint32_t address);
int mem_ap_sel_read_buf_u32(struct adiv5_dap *swjdp, uint8_t ap,
uint8_t *buffer, int count, uint32_t address);
int mem_ap_sel_write_buf_u8(struct adiv5_dap *swjdp, uint8_t ap,
const uint8_t *buffer, int count, uint32_t address);
int mem_ap_sel_write_buf_u16(struct adiv5_dap *swjdp, uint8_t ap,
const uint8_t *buffer, int count, uint32_t address);
int mem_ap_sel_write_buf_u32(struct adiv5_dap *swjdp, uint8_t ap,
const uint8_t *buffer, int count, uint32_t address);
/* Initialisation of the debug system, power domains and registers */
int ahbap_debugport_init(struct adiv5_dap *swjdp);
/* Probe the AP for ROM Table location */
int dap_get_debugbase(struct adiv5_dap *dap, int ap,
uint32_t *dbgbase, uint32_t *apid);
/* Probe Access Ports to find a particular type */
int dap_find_ap(struct adiv5_dap *dap,
enum ap_type type_to_find,
uint8_t *ap_num_out);
/* Lookup CoreSight component */
int dap_lookup_cs_component(struct adiv5_dap *dap, int ap,
uint32_t dbgbase, uint8_t type, uint32_t *addr);
struct target;
/* Put debug link into SWD mode */
int dap_to_swd(struct target *target);
/* Put debug link into JTAG mode */
int dap_to_jtag(struct target *target);
extern const struct command_registration dap_command_handlers[];
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,201 @@
/***************************************************************************
* Copyright (C) 2006 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef ARM_DISASSEMBLER_H
#define ARM_DISASSEMBLER_H
enum arm_instruction_type {
ARM_UNKNOWN_INSTUCTION,
/* Branch instructions */
ARM_B,
ARM_BL,
ARM_BX,
ARM_BLX,
/* Data processing instructions */
ARM_AND,
ARM_EOR,
ARM_SUB,
ARM_RSB,
ARM_ADD,
ARM_ADC,
ARM_SBC,
ARM_RSC,
ARM_TST,
ARM_TEQ,
ARM_CMP,
ARM_CMN,
ARM_ORR,
ARM_MOV,
ARM_BIC,
ARM_MVN,
/* Load/store instructions */
ARM_LDR,
ARM_LDRB,
ARM_LDRT,
ARM_LDRBT,
ARM_LDRH,
ARM_LDRSB,
ARM_LDRSH,
ARM_LDM,
ARM_STR,
ARM_STRB,
ARM_STRT,
ARM_STRBT,
ARM_STRH,
ARM_STM,
/* Status register access instructions */
ARM_MRS,
ARM_MSR,
/* Multiply instructions */
ARM_MUL,
ARM_MLA,
ARM_SMULL,
ARM_SMLAL,
ARM_UMULL,
ARM_UMLAL,
/* Miscellaneous instructions */
ARM_CLZ,
/* Exception generating instructions */
ARM_BKPT,
ARM_SWI,
/* Coprocessor instructions */
ARM_CDP,
ARM_LDC,
ARM_STC,
ARM_MCR,
ARM_MRC,
/* Semaphore instructions */
ARM_SWP,
ARM_SWPB,
/* Enhanced DSP extensions */
ARM_MCRR,
ARM_MRRC,
ARM_PLD,
ARM_QADD,
ARM_QDADD,
ARM_QSUB,
ARM_QDSUB,
ARM_SMLAxy,
ARM_SMLALxy,
ARM_SMLAWy,
ARM_SMULxy,
ARM_SMULWy,
ARM_LDRD,
ARM_STRD,
ARM_UNDEFINED_INSTRUCTION = 0xffffffff,
};
struct arm_b_bl_bx_blx_instr {
int reg_operand;
uint32_t target_address;
};
union arm_shifter_operand {
struct {
uint32_t immediate;
} immediate;
struct {
uint8_t Rm;
uint8_t shift; /* 0: LSL, 1: LSR, 2: ASR, 3: ROR, 4: RRX */
uint8_t shift_imm;
} immediate_shift;
struct {
uint8_t Rm;
uint8_t shift;
uint8_t Rs;
} register_shift;
};
struct arm_data_proc_instr {
int variant; /* 0: immediate, 1: immediate_shift, 2: register_shift */
uint8_t S;
uint8_t Rn;
uint8_t Rd;
union arm_shifter_operand shifter_operand;
};
struct arm_load_store_instr {
uint8_t Rd;
uint8_t Rn;
uint8_t U;
int index_mode; /* 0: offset, 1: pre-indexed, 2: post-indexed */
int offset_mode; /* 0: immediate, 1: (scaled) register */
union {
uint32_t offset;
struct {
uint8_t Rm;
uint8_t shift; /* 0: LSL, 1: LSR, 2: ASR, 3: ROR, 4: RRX */
uint8_t shift_imm;
} reg;
} offset;
};
struct arm_load_store_multiple_instr {
uint8_t Rn;
uint32_t register_list;
uint8_t addressing_mode; /* 0: IA, 1: IB, 2: DA, 3: DB */
uint8_t S;
uint8_t W;
};
struct arm_instruction {
enum arm_instruction_type type;
char text[128];
uint32_t opcode;
/* return value ... Thumb-2 sizes vary */
unsigned instruction_size;
union {
struct arm_b_bl_bx_blx_instr b_bl_bx_blx;
struct arm_data_proc_instr data_proc;
struct arm_load_store_instr load_store;
struct arm_load_store_multiple_instr load_store_multiple;
} info;
};
int arm_evaluate_opcode(uint32_t opcode, uint32_t address,
struct arm_instruction *instruction);
int thumb_evaluate_opcode(uint16_t opcode, uint32_t address,
struct arm_instruction *instruction);
int thumb2_opcode(struct target *target, uint32_t address,
struct arm_instruction *instruction);
int arm_access_size(struct arm_instruction *instruction);
#define COND(opcode) (arm_condition_strings[(opcode & 0xf0000000) >> 28])
#endif /* ARM_DISASSEMBLER_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,203 @@
/*
* Copyright (C) 2009 by David Brownell
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef __ARM_DPM_H
#define __ARM_DPM_H
/**
* @file
* This is the interface to the Debug Programmers Model for ARMv6 and
* ARMv7 processors. ARMv6 processors (such as ARM11xx implementations)
* introduced a model which became part of the ARMv7-AR architecture
* which is most familiar through the Cortex-A series parts. While
* specific details differ (like how to write the instruction register),
* the high level models easily support shared code because those
* registers are compatible.
*/
struct dpm_bpwp {
unsigned number;
uint32_t address;
uint32_t control;
/* true if hardware state needs flushing */
bool dirty;
};
struct dpm_bp {
struct breakpoint *bp;
struct dpm_bpwp bpwp;
};
struct dpm_wp {
struct watchpoint *wp;
struct dpm_bpwp bpwp;
};
/**
* This wraps an implementation of DPM primitives. Each interface
* provider supplies a structure like this, which is the glue between
* upper level code and the lower level hardware access.
*
* It is a PRELIMINARY AND INCOMPLETE set of primitives, starting with
* support for CPU register access.
*/
struct arm_dpm {
struct arm *arm;
/** Cache of DIDR */
uint32_t didr;
/** Invoke before a series of instruction operations */
int (*prepare)(struct arm_dpm *);
/** Invoke after a series of instruction operations */
int (*finish)(struct arm_dpm *);
/* WRITE TO CPU */
/** Runs one instruction, writing data to DCC before execution. */
int (*instr_write_data_dcc)(struct arm_dpm *,
uint32_t opcode, uint32_t data);
/** Runs one instruction, writing data to R0 before execution. */
int (*instr_write_data_r0)(struct arm_dpm *,
uint32_t opcode, uint32_t data);
/** Optional core-specific operation invoked after CPSR writes. */
int (*instr_cpsr_sync)(struct arm_dpm *dpm);
/* READ FROM CPU */
/** Runs one instruction, reading data from dcc after execution. */
int (*instr_read_data_dcc)(struct arm_dpm *,
uint32_t opcode, uint32_t *data);
/** Runs one instruction, reading data from r0 after execution. */
int (*instr_read_data_r0)(struct arm_dpm *,
uint32_t opcode, uint32_t *data);
/* BREAKPOINT/WATCHPOINT SUPPORT */
/**
* Enables one breakpoint or watchpoint by writing to the
* hardware registers. The specified breakpoint/watchpoint
* must currently be disabled. Indices 0..15 are used for
* breakpoints; indices 16..31 are for watchpoints.
*/
int (*bpwp_enable)(struct arm_dpm *, unsigned index_value,
uint32_t addr, uint32_t control);
/**
* Disables one breakpoint or watchpoint by clearing its
* hardware control registers. Indices are the same ones
* accepted by bpwp_enable().
*/
int (*bpwp_disable)(struct arm_dpm *, unsigned index_value);
/* The breakpoint and watchpoint arrays are private to the
* DPM infrastructure. There are nbp indices in the dbp
* array. There are nwp indices in the dwp array.
*/
unsigned nbp;
unsigned nwp;
struct dpm_bp *dbp;
struct dpm_wp *dwp;
/** Address of the instruction which triggered a watchpoint. */
uint32_t wp_pc;
/** Recent value of DSCR. */
uint32_t dscr;
/* FIXME -- read/write DCSR methods and symbols */
};
int arm_dpm_setup(struct arm_dpm *dpm);
int arm_dpm_initialize(struct arm_dpm *dpm);
int arm_dpm_read_current_registers(struct arm_dpm *);
int dpm_modeswitch(struct arm_dpm *dpm, enum arm_mode mode);
int arm_dpm_write_dirty_registers(struct arm_dpm *, bool bpwp);
void arm_dpm_report_wfar(struct arm_dpm *, uint32_t wfar);
/* DSCR bits; see ARMv7a arch spec section C10.3.1.
* Not all v7 bits are valid in v6.
*/
#define DSCR_CORE_HALTED (0x1 << 0)
#define DSCR_CORE_RESTARTED (0x1 << 1)
#define DSCR_ENTRY_MASK (0xF << 2)
#define DSCR_STICKY_ABORT_PRECISE (0x1 << 6)
#define DSCR_STICKY_ABORT_IMPRECISE (0x1 << 7)
#define DSCR_STICKY_UNDEFINED (0x1 << 8)
#define DSCR_DBG_NOPWRDWN (0x1 << 9) /* v6 only */
#define DSCR_DBG_ACK (0x1 << 10)
#define DSCR_INT_DIS (0x1 << 11)
#define DSCR_CP14_USR_COMMS (0x1 << 12)
#define DSCR_ITR_EN (0x1 << 13)
#define DSCR_HALT_DBG_MODE (0x1 << 14)
#define DSCR_MON_DBG_MODE (0x1 << 15)
#define DSCR_SEC_PRIV_INVASV_DIS (0x1 << 16)
#define DSCR_SEC_PRIV_NINVASV_DIS (0x1 << 17)
#define DSCR_NON_SECURE (0x1 << 18)
#define DSCR_DSCRD_IMPRECISE_ABORT (0x1 << 19)
#define DSCR_EXT_DCC_MASK (0x3 << 20) /* DTR mode */ /* bits 22, 23 are reserved */
#define DSCR_INSTR_COMP (0x1 << 24)
#define DSCR_PIPE_ADVANCE (0x1 << 25)
#define DSCR_DTRTX_FULL_LATCHED (0x1 << 26)
#define DSCR_DTRRX_FULL_LATCHED (0x1 << 27) /* bit 28 is reserved */
#define DSCR_DTR_TX_FULL (0x1 << 29)
#define DSCR_DTR_RX_FULL (0x1 << 30) /* bit 31 is reserved */
#define DSCR_ENTRY(dscr) (((dscr) >> 2) & 0xf)
#define DSCR_RUN_MODE(dscr) ((dscr) & (DSCR_CORE_HALTED | DSCR_CORE_RESTARTED))
/* Methods of entry into debug mode */
#define DSCR_ENTRY_HALT_REQ (0x0 << 2)
#define DSCR_ENTRY_BREAKPOINT (0x1 << 2)
#define DSCR_ENTRY_IMPRECISE_WATCHPT (0x2 << 2)
#define DSCR_ENTRY_BKPT_INSTR (0x3 << 2)
#define DSCR_ENTRY_EXT_DBG_REQ (0x4 << 2)
#define DSCR_ENTRY_VECT_CATCH (0x5 << 2)
#define DSCR_ENTRY_D_SIDE_ABORT (0x6 << 2) /* v6 only */
#define DSCR_ENTRY_I_SIDE_ABORT (0x7 << 2) /* v6 only */
#define DSCR_ENTRY_OS_UNLOCK (0x8 << 2)
#define DSCR_ENTRY_PRECISE_WATCHPT (0xA << 2)
/* DTR modes */
#define DSCR_EXT_DCC_NON_BLOCKING (0x0 << 20)
#define DSCR_EXT_DCC_STALL_MODE (0x1 << 20)
#define DSCR_EXT_DCC_FAST_MODE (0x2 << 20) /* bits 22, 23 are reserved */
/* DRCR (debug run control register) bits */
#define DRCR_HALT (1 << 0)
#define DRCR_RESTART (1 << 1)
#define DRCR_CLEAR_EXCEPTIONS (1 << 2)
void arm_dpm_report_dscr(struct arm_dpm *dpm, uint32_t dcsr);
#endif /* __ARM_DPM_H */

View File

@ -0,0 +1,100 @@
/***************************************************************************
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* Copyright (C) 2007,2008 Øyvind Harboe *
* oyvind.harboe@zylin.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "arm_jtag.h"
#if 0
#define _ARM_JTAG_SCAN_N_CHECK_
#endif
int arm_jtag_set_instr_inner(struct arm_jtag *jtag_info,
uint32_t new_instr, void *no_verify_capture, tap_state_t end_state)
{
struct jtag_tap *tap;
tap = jtag_info->tap;
struct scan_field field;
uint8_t t[4];
field.num_bits = tap->ir_length;
field.out_value = t;
buf_set_u32(t, 0, field.num_bits, new_instr);
field.in_value = NULL;
if (no_verify_capture == NULL)
jtag_add_ir_scan(tap, &field, end_state);
else {
/* FIX!!!! this is a kludge!!! arm926ejs.c should reimplement this arm_jtag_set_instr to
* have special verification code.
*/
jtag_add_ir_scan_noverify(tap, &field, end_state);
}
return ERROR_OK;
}
int arm_jtag_scann_inner(struct arm_jtag *jtag_info, uint32_t new_scan_chain, tap_state_t end_state)
{
int retval = ERROR_OK;
uint32_t values[1];
int num_bits[1];
values[0] = new_scan_chain;
num_bits[0] = jtag_info->scann_size;
retval = arm_jtag_set_instr(jtag_info, jtag_info->scann_instr, NULL, end_state);
if (retval != ERROR_OK)
return retval;
jtag_add_dr_out(jtag_info->tap,
1,
num_bits,
values,
end_state);
jtag_info->cur_scan_chain = new_scan_chain;
return retval;
}
static int arm_jtag_reset_callback(enum jtag_event event, void *priv)
{
struct arm_jtag *jtag_info = priv;
if (event == JTAG_TRST_ASSERTED)
jtag_info->cur_scan_chain = 0;
return ERROR_OK;
}
int arm_jtag_setup_connection(struct arm_jtag *jtag_info)
{
jtag_info->scann_instr = 0x2;
jtag_info->cur_scan_chain = 0;
jtag_info->intest_instr = 0xc;
return jtag_register_event_callback(arm_jtag_reset_callback, jtag_info);
}

View File

@ -0,0 +1,84 @@
/***************************************************************************
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* Copyright (C) 2007-2010 Øyvind Harboe *
* oyvind.harboe@zylin.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef ARM_JTAG
#define ARM_JTAG
#include <jtag/jtag.h>
struct arm_jtag {
struct jtag_tap *tap;
uint32_t scann_size;
uint32_t scann_instr;
uint32_t cur_scan_chain;
uint32_t intest_instr;
};
int arm_jtag_set_instr_inner(struct arm_jtag *jtag_info, uint32_t new_instr,
void *no_verify_capture,
tap_state_t end_state);
static inline int arm_jtag_set_instr(struct arm_jtag *jtag_info,
uint32_t new_instr, void *no_verify_capture, tap_state_t end_state)
{
/* inline most common code path */
struct jtag_tap *tap;
tap = jtag_info->tap;
assert(tap != NULL);
if (buf_get_u32(tap->cur_instr, 0, tap->ir_length) != new_instr)
return arm_jtag_set_instr_inner(jtag_info, new_instr, no_verify_capture, end_state);
return ERROR_OK;
}
int arm_jtag_scann_inner(struct arm_jtag *jtag_info, uint32_t new_scan_chain, tap_state_t end_state);
static inline int arm_jtag_scann(struct arm_jtag *jtag_info, uint32_t new_scan_chain, tap_state_t end_state)
{
/* inline most common code path */
int retval = ERROR_OK;
if (jtag_info->cur_scan_chain != new_scan_chain)
return arm_jtag_scann_inner(jtag_info, new_scan_chain, end_state);
return retval;
}
int arm_jtag_setup_connection(struct arm_jtag *jtag_info);
/* use this as a static so we can inline it in -O3 and refer to it via a pointer */
static inline void arm7flip32(jtag_callback_data_t arg)
{
uint8_t *in = (uint8_t *)arg;
*((uint32_t *)arg) = flip_u32(le_to_h_u32(in), 32);
}
static inline void arm_le_to_h_u32(jtag_callback_data_t arg)
{
uint8_t *in = (uint8_t *)arg;
*((uint32_t *)arg) = le_to_h_u32(in);
}
#endif /* ARM_JTAG */

View File

@ -0,0 +1,314 @@
/*
* Copyright (C) 2005 by Dominic Rath
* Dominic.Rath@gmx.de
*
* Copyright (C) 2006 by Magnus Lundin
* lundin@mlu.mine.nu
*
* Copyright (C) 2008 by Spencer Oliver
* spen@spen-soft.co.uk
*
* Copyright (C) 2009 by Øyvind Harboe
* oyvind.harboe@zylin.com
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef __ARM_OPCODES_H
#define __ARM_OPCODES_H
/**
* @file
* Macros used to generate various ARM or Thumb opcodes.
*/
/* ARM mode instructions */
/* Store multiple increment after
* Rn: base register
* List: for each bit in list: store register
* S: in priviledged mode: store user-mode registers
* W = 1: update the base register. W = 0: leave the base register untouched
*/
#define ARMV4_5_STMIA(Rn, List, S, W) \
(0xe8800000 | ((S) << 22) | ((W) << 21) | ((Rn) << 16) | (List))
/* Load multiple increment after
* Rn: base register
* List: for each bit in list: store register
* S: in priviledged mode: store user-mode registers
* W = 1: update the base register. W = 0: leave the base register untouched
*/
#define ARMV4_5_LDMIA(Rn, List, S, W) \
(0xe8900000 | ((S) << 22) | ((W) << 21) | ((Rn) << 16) | (List))
/* MOV r8, r8 */
#define ARMV4_5_NOP (0xe1a08008)
/* Move PSR to general purpose register
* R = 1: SPSR R = 0: CPSR
* Rn: target register
*/
#define ARMV4_5_MRS(Rn, R) (0xe10f0000 | ((R) << 22) | ((Rn) << 12))
/* Store register
* Rd: register to store
* Rn: base register
*/
#define ARMV4_5_STR(Rd, Rn) (0xe5800000 | ((Rd) << 12) | ((Rn) << 16))
/* Load register
* Rd: register to load
* Rn: base register
*/
#define ARMV4_5_LDR(Rd, Rn) (0xe5900000 | ((Rd) << 12) | ((Rn) << 16))
/* Move general purpose register to PSR
* R = 1: SPSR R = 0: CPSR
* Field: Field mask
* 1: control field 2: extension field 4: status field 8: flags field
* Rm: source register
*/
#define ARMV4_5_MSR_GP(Rm, Field, R) \
(0xe120f000 | (Rm) | ((Field) << 16) | ((R) << 22))
#define ARMV4_5_MSR_IM(Im, Rotate, Field, R) \
(0xe320f000 | (Im) | ((Rotate) << 8) | ((Field) << 16) | ((R) << 22))
/* Load Register Word Immediate Post-Index
* Rd: register to load
* Rn: base register
*/
#define ARMV4_5_LDRW_IP(Rd, Rn) (0xe4900004 | ((Rd) << 12) | ((Rn) << 16))
/* Load Register Halfword Immediate Post-Index
* Rd: register to load
* Rn: base register
*/
#define ARMV4_5_LDRH_IP(Rd, Rn) (0xe0d000b2 | ((Rd) << 12) | ((Rn) << 16))
/* Load Register Byte Immediate Post-Index
* Rd: register to load
* Rn: base register
*/
#define ARMV4_5_LDRB_IP(Rd, Rn) (0xe4d00001 | ((Rd) << 12) | ((Rn) << 16))
/* Store register Word Immediate Post-Index
* Rd: register to store
* Rn: base register
*/
#define ARMV4_5_STRW_IP(Rd, Rn) (0xe4800004 | ((Rd) << 12) | ((Rn) << 16))
/* Store register Halfword Immediate Post-Index
* Rd: register to store
* Rn: base register
*/
#define ARMV4_5_STRH_IP(Rd, Rn) (0xe0c000b2 | ((Rd) << 12) | ((Rn) << 16))
/* Store register Byte Immediate Post-Index
* Rd: register to store
* Rn: base register
*/
#define ARMV4_5_STRB_IP(Rd, Rn) (0xe4c00001 | ((Rd) << 12) | ((Rn) << 16))
/* Branch (and Link)
* Im: Branch target (left-shifted by 2 bits, added to PC)
* L: 1: branch and link 0: branch only
*/
#define ARMV4_5_B(Im, L) (0xea000000 | (Im) | ((L) << 24))
/* Branch and exchange (ARM state)
* Rm: register holding branch target address
*/
#define ARMV4_5_BX(Rm) (0xe12fff10 | (Rm))
/* Store data from coprocessor to consecutive memory
* See Armv7-A arch doc section A8.6.187
* P: 1=index mode (offset from Rn)
* U: 1=add, 0=subtract Rn address with imm
* D: Opcode D encoding
* W: write back the offset start address to the Rn register
* CP: Coprocessor number (4 bits)
* CRd: Coprocessor source register (4 bits)
* Rn: Base register for memory address (4 bits)
* imm: Immediate value (0 - 1020, must be divisible by 4)
*/
#define ARMV4_5_STC(P, U, D, W, CP, CRd, Rn, imm) \
(0xec000000 | ((P) << 24) | ((U) << 23) | ((D) << 22) | \
((W) << 21) | ((Rn) << 16) | ((CRd) << 12) | ((CP) << 8) | ((imm)>>2))
/* Loads data from consecutive memory to coprocessor
* See Armv7-A arch doc section A8.6.51
* P: 1=index mode (offset from Rn)
* U: 1=add, 0=subtract Rn address with imm
* D: Opcode D encoding
* W: write back the offset start address to the Rn register
* CP: Coprocessor number (4 bits)
* CRd: Coprocessor dest register (4 bits)
* Rn: Base register for memory address (4 bits)
* imm: Immediate value (0 - 1020, must be divisible by 4)
*/
#define ARMV4_5_LDC(P, U, D, W, CP, CRd, Rn, imm) \
(0xec100000 | ((P) << 24) | ((U) << 23) | ((D) << 22) | \
((W) << 21) | ((Rn) << 16) | ((CRd) << 12) | ((CP) << 8) | ((imm) >> 2))
/* Move to ARM register from coprocessor
* CP: Coprocessor number
* op1: Coprocessor opcode
* Rd: destination register
* CRn: first coprocessor operand
* CRm: second coprocessor operand
* op2: Second coprocessor opcode
*/
#define ARMV4_5_MRC(CP, op1, Rd, CRn, CRm, op2) \
(0xee100010 | (CRm) | ((op2) << 5) | ((CP) << 8) \
| ((Rd) << 12) | ((CRn) << 16) | ((op1) << 21))
/* Move to coprocessor from ARM register
* CP: Coprocessor number
* op1: Coprocessor opcode
* Rd: destination register
* CRn: first coprocessor operand
* CRm: second coprocessor operand
* op2: Second coprocessor opcode
*/
#define ARMV4_5_MCR(CP, op1, Rd, CRn, CRm, op2) \
(0xee000010 | (CRm) | ((op2) << 5) | ((CP) << 8) \
| ((Rd) << 12) | ((CRn) << 16) | ((op1) << 21))
/* Breakpoint instruction (ARMv5)
* Im: 16-bit immediate
*/
#define ARMV5_BKPT(Im) (0xe1200070 | ((Im & 0xfff0) << 8) | (Im & 0xf))
/* Thumb mode instructions
*
* NOTE: these 16-bit opcodes fill both halves of a word with the same
* value. The reason for this is that when we need to execute Thumb
* opcodes on ARM7/ARM9 cores (to switch to ARM state on debug entry),
* we must shift 32 bits to the bus using scan chain 1 ... if we write
* both halves, we don't need to track which half matters. On ARMv6 and
* ARMv7 we don't execute Thumb instructions in debug mode; the ITR
* register does not accept Thumb (or Thumb2) opcodes.
*/
/* Store register (Thumb mode)
* Rd: source register
* Rn: base register
*/
#define ARMV4_5_T_STR(Rd, Rn) \
((0x6000 | (Rd) | ((Rn) << 3)) | \
((0x6000 | (Rd) | ((Rn) << 3)) << 16))
/* Load register (Thumb state)
* Rd: destination register
* Rn: base register
*/
#define ARMV4_5_T_LDR(Rd, Rn) \
((0x6800 | ((Rn) << 3) | (Rd)) \
| ((0x6800 | ((Rn) << 3) | (Rd)) << 16))
/* Load multiple (Thumb state)
* Rn: base register
* List: for each bit in list: store register
*/
#define ARMV4_5_T_LDMIA(Rn, List) \
((0xc800 | ((Rn) << 8) | (List)) \
| ((0xc800 | ((Rn) << 8) | (List)) << 16))
/* Load register with PC relative addressing
* Rd: register to load
*/
#define ARMV4_5_T_LDR_PCREL(Rd) \
((0x4800 | ((Rd) << 8)) \
| ((0x4800 | ((Rd) << 8)) << 16))
/* Move hi register (Thumb mode)
* Rd: destination register
* Rm: source register
*/
#define ARMV4_5_T_MOV(Rd, Rm) \
((0x4600 | ((Rd) & 0x7) | (((Rd) & 0x8) << 4) | \
(((Rm) & 0x7) << 3) | (((Rm) & 0x8) << 3)) \
| ((0x4600 | ((Rd) & 0x7) | (((Rd) & 0x8) << 4) | \
(((Rm) & 0x7) << 3) | (((Rm) & 0x8) << 3)) << 16))
/* No operation (Thumb mode)
* NOTE: this is "MOV r8, r8" ... Thumb2 adds two
* architected NOPs, 16-bit and 32-bit.
*/
#define ARMV4_5_T_NOP (0x46c0 | (0x46c0 << 16))
/* Move immediate to register (Thumb state)
* Rd: destination register
* Im: 8-bit immediate value
*/
#define ARMV4_5_T_MOV_IM(Rd, Im) \
((0x2000 | ((Rd) << 8) | (Im)) \
| ((0x2000 | ((Rd) << 8) | (Im)) << 16))
/* Branch and Exchange
* Rm: register containing branch target
*/
#define ARMV4_5_T_BX(Rm) \
((0x4700 | ((Rm) << 3)) \
| ((0x4700 | ((Rm) << 3)) << 16))
/* Branch (Thumb state)
* Imm: Branch target
*/
#define ARMV4_5_T_B(Imm) \
((0xe000 | (Imm)) \
| ((0xe000 | (Imm)) << 16))
/* Breakpoint instruction (ARMv5) (Thumb state)
* Im: 8-bit immediate
*/
#define ARMV5_T_BKPT(Im) \
((0xbe00 | (Im)) \
| ((0xbe00 | (Im)) << 16))
/* Move to Register from Special Register
* 32 bit Thumb2 instruction
* Rd: destination register
* SYSm: source special register
*/
#define ARM_T2_MRS(Rd, SYSm) \
((0xF3EF) | ((0x8000 | (Rd << 8) | SYSm) << 16))
/* Move from Register from Special Register
* 32 bit Thumb2 instruction
* Rd: source register
* SYSm: destination special register
*/
#define ARM_T2_MSR(SYSm, Rn) \
((0xF380 | (Rn << 8)) | ((0x8800 | SYSm) << 16))
/* Change Processor State.
* 16 bit Thumb2 instruction
* Rd: source register
* IF: A_FLAG and/or I_FLAG and/or F_FLAG
*/
#define A_FLAG 4
#define I_FLAG 2
#define F_FLAG 1
#define ARM_T2_CPSID(IF) \
((0xB660 | (1 << 8) | ((IF)&0x3)) \
| ((0xB660 | (1 << 8) | ((IF)&0x3)) << 16))
#define ARM_T2_CPSIE(IF) \
((0xB660 | (0 << 8) | ((IF)&0x3)) \
| ((0xB660 | (0 << 8) | ((IF)&0x3)) << 16))
#endif /* __ARM_OPCODES_H */

View File

@ -0,0 +1,533 @@
/***************************************************************************
* Copyright (C) 2009 by Marvell Technology Group Ltd. *
* Written by Nicolas Pitre <nico@marvell.com> *
* *
* Copyright (C) 2010 by Spencer Oliver *
* spen@spen-soft.co.uk *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
/**
* @file
* Hold ARM semihosting support.
*
* Semihosting enables code running on an ARM target to use the I/O
* facilities on the host computer. The target application must be linked
* against a library that forwards operation requests by using the SVC
* instruction trapped at the Supervisor Call vector by the debugger.
* Details can be found in chapter 8 of DUI0203I_rvct_developer_guide.pdf
* from ARM Ltd.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "arm.h"
#include "armv4_5.h"
#include "arm7_9_common.h"
#include "armv7m.h"
#include "cortex_m.h"
#include "register.h"
#include "arm_semihosting.h"
#include <helper/binarybuffer.h>
#include <helper/log.h>
#include <sys/stat.h>
static int open_modeflags[12] = {
O_RDONLY,
O_RDONLY | O_BINARY,
O_RDWR,
O_RDWR | O_BINARY,
O_WRONLY | O_CREAT | O_TRUNC,
O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
O_RDWR | O_CREAT | O_TRUNC,
O_RDWR | O_CREAT | O_TRUNC | O_BINARY,
O_WRONLY | O_CREAT | O_APPEND,
O_WRONLY | O_CREAT | O_APPEND | O_BINARY,
O_RDWR | O_CREAT | O_APPEND,
O_RDWR | O_CREAT | O_APPEND | O_BINARY
};
static int do_semihosting(struct target *target)
{
struct arm *arm = target_to_arm(target);
uint32_t r0 = buf_get_u32(arm->core_cache->reg_list[0].value, 0, 32);
uint32_t r1 = buf_get_u32(arm->core_cache->reg_list[1].value, 0, 32);
uint8_t params[16];
int retval, result;
/*
* TODO: lots of security issues are not considered yet, such as:
* - no validation on target provided file descriptors
* - no safety checks on opened/deleted/renamed file paths
* Beware the target app you use this support with.
*
* TODO: explore mapping requests to GDB's "File-I/O Remote
* Protocol Extension" ... when GDB is active.
*/
switch (r0) {
case 0x01: /* SYS_OPEN */
retval = target_read_memory(target, r1, 4, 3, params);
if (retval != ERROR_OK)
return retval;
else {
uint32_t a = target_buffer_get_u32(target, params+0);
uint32_t m = target_buffer_get_u32(target, params+4);
uint32_t l = target_buffer_get_u32(target, params+8);
if (l <= 255 && m <= 11) {
uint8_t fn[256];
retval = target_read_memory(target, a, 1, l, fn);
if (retval != ERROR_OK)
return retval;
fn[l] = 0;
if (strcmp((char *)fn, ":tt") == 0) {
if (m < 4)
result = dup(STDIN_FILENO);
else
result = dup(STDOUT_FILENO);
} else {
/* cygwin requires the permission setting
* otherwise it will fail to reopen a previously
* written file */
result = open((char *)fn, open_modeflags[m], 0644);
}
arm->semihosting_errno = errno;
} else {
result = -1;
arm->semihosting_errno = EINVAL;
}
}
break;
case 0x02: /* SYS_CLOSE */
retval = target_read_memory(target, r1, 4, 1, params);
if (retval != ERROR_OK)
return retval;
else {
int fd = target_buffer_get_u32(target, params+0);
result = close(fd);
arm->semihosting_errno = errno;
}
break;
case 0x03: /* SYS_WRITEC */
{
unsigned char c;
retval = target_read_memory(target, r1, 1, 1, &c);
if (retval != ERROR_OK)
return retval;
putchar(c);
result = 0;
}
break;
case 0x04: /* SYS_WRITE0 */
do {
unsigned char c;
retval = target_read_memory(target, r1++, 1, 1, &c);
if (retval != ERROR_OK)
return retval;
if (!c)
break;
putchar(c);
} while (1);
result = 0;
break;
case 0x05: /* SYS_WRITE */
retval = target_read_memory(target, r1, 4, 3, params);
if (retval != ERROR_OK)
return retval;
else {
int fd = target_buffer_get_u32(target, params+0);
uint32_t a = target_buffer_get_u32(target, params+4);
size_t l = target_buffer_get_u32(target, params+8);
uint8_t *buf = malloc(l);
if (!buf) {
result = -1;
arm->semihosting_errno = ENOMEM;
} else {
retval = target_read_buffer(target, a, l, buf);
if (retval != ERROR_OK) {
free(buf);
return retval;
}
result = write(fd, buf, l);
arm->semihosting_errno = errno;
if (result >= 0)
result = l - result;
free(buf);
}
}
break;
case 0x06: /* SYS_READ */
retval = target_read_memory(target, r1, 4, 3, params);
if (retval != ERROR_OK)
return retval;
else {
int fd = target_buffer_get_u32(target, params+0);
uint32_t a = target_buffer_get_u32(target, params+4);
ssize_t l = target_buffer_get_u32(target, params+8);
uint8_t *buf = malloc(l);
if (!buf) {
result = -1;
arm->semihosting_errno = ENOMEM;
} else {
result = read(fd, buf, l);
arm->semihosting_errno = errno;
if (result >= 0) {
retval = target_write_buffer(target, a, result, buf);
if (retval != ERROR_OK) {
free(buf);
return retval;
}
result = l - result;
}
free(buf);
}
}
break;
case 0x07: /* SYS_READC */
result = getchar();
break;
case 0x08: /* SYS_ISERROR */
retval = target_read_memory(target, r1, 4, 1, params);
if (retval != ERROR_OK)
return retval;
result = (target_buffer_get_u32(target, params+0) != 0);
break;
case 0x09: /* SYS_ISTTY */
retval = target_read_memory(target, r1, 4, 1, params);
if (retval != ERROR_OK)
return retval;
result = isatty(target_buffer_get_u32(target, params+0));
break;
case 0x0a: /* SYS_SEEK */
retval = target_read_memory(target, r1, 4, 2, params);
if (retval != ERROR_OK)
return retval;
else {
int fd = target_buffer_get_u32(target, params+0);
off_t pos = target_buffer_get_u32(target, params+4);
result = lseek(fd, pos, SEEK_SET);
arm->semihosting_errno = errno;
if (result == pos)
result = 0;
}
break;
case 0x0c: /* SYS_FLEN */
retval = target_read_memory(target, r1, 4, 1, params);
if (retval != ERROR_OK)
return retval;
else {
int fd = target_buffer_get_u32(target, params+0);
struct stat buf;
result = fstat(fd, &buf);
if (result == -1) {
arm->semihosting_errno = errno;
result = -1;
break;
}
result = buf.st_size;
}
break;
case 0x0e: /* SYS_REMOVE */
retval = target_read_memory(target, r1, 4, 2, params);
if (retval != ERROR_OK)
return retval;
else {
uint32_t a = target_buffer_get_u32(target, params+0);
uint32_t l = target_buffer_get_u32(target, params+4);
if (l <= 255) {
uint8_t fn[256];
retval = target_read_memory(target, a, 1, l, fn);
if (retval != ERROR_OK)
return retval;
fn[l] = 0;
result = remove((char *)fn);
arm->semihosting_errno = errno;
} else {
result = -1;
arm->semihosting_errno = EINVAL;
}
}
break;
case 0x0f: /* SYS_RENAME */
retval = target_read_memory(target, r1, 4, 4, params);
if (retval != ERROR_OK)
return retval;
else {
uint32_t a1 = target_buffer_get_u32(target, params+0);
uint32_t l1 = target_buffer_get_u32(target, params+4);
uint32_t a2 = target_buffer_get_u32(target, params+8);
uint32_t l2 = target_buffer_get_u32(target, params+12);
if (l1 <= 255 && l2 <= 255) {
uint8_t fn1[256], fn2[256];
retval = target_read_memory(target, a1, 1, l1, fn1);
if (retval != ERROR_OK)
return retval;
retval = target_read_memory(target, a2, 1, l2, fn2);
if (retval != ERROR_OK)
return retval;
fn1[l1] = 0;
fn2[l2] = 0;
result = rename((char *)fn1, (char *)fn2);
arm->semihosting_errno = errno;
} else {
result = -1;
arm->semihosting_errno = EINVAL;
}
}
break;
case 0x11: /* SYS_TIME */
result = time(NULL);
break;
case 0x13: /* SYS_ERRNO */
result = arm->semihosting_errno;
break;
case 0x15: /* SYS_GET_CMDLINE */
retval = target_read_memory(target, r1, 4, 2, params);
if (retval != ERROR_OK)
return retval;
else {
uint32_t a = target_buffer_get_u32(target, params+0);
uint32_t l = target_buffer_get_u32(target, params+4);
char *arg = "foobar";
uint32_t s = strlen(arg) + 1;
if (l < s)
result = -1;
else {
retval = target_write_buffer(target, a, s, (void *)arg);
if (retval != ERROR_OK)
return retval;
result = 0;
}
}
break;
case 0x16: /* SYS_HEAPINFO */
retval = target_read_memory(target, r1, 4, 1, params);
if (retval != ERROR_OK)
return retval;
else {
uint32_t a = target_buffer_get_u32(target, params+0);
/* tell the remote we have no idea */
memset(params, 0, 4*4);
retval = target_write_memory(target, a, 4, 4, params);
if (retval != ERROR_OK)
return retval;
result = 0;
}
break;
case 0x18: /* angel_SWIreason_ReportException */
switch (r1) {
case 0x20026: /* ADP_Stopped_ApplicationExit */
fprintf(stderr, "semihosting: *** application exited ***\n");
break;
case 0x20000: /* ADP_Stopped_BranchThroughZero */
case 0x20001: /* ADP_Stopped_UndefinedInstr */
case 0x20002: /* ADP_Stopped_SoftwareInterrupt */
case 0x20003: /* ADP_Stopped_PrefetchAbort */
case 0x20004: /* ADP_Stopped_DataAbort */
case 0x20005: /* ADP_Stopped_AddressException */
case 0x20006: /* ADP_Stopped_IRQ */
case 0x20007: /* ADP_Stopped_FIQ */
case 0x20020: /* ADP_Stopped_BreakPoint */
case 0x20021: /* ADP_Stopped_WatchPoint */
case 0x20022: /* ADP_Stopped_StepComplete */
case 0x20023: /* ADP_Stopped_RunTimeErrorUnknown */
case 0x20024: /* ADP_Stopped_InternalError */
case 0x20025: /* ADP_Stopped_UserInterruption */
case 0x20027: /* ADP_Stopped_StackOverflow */
case 0x20028: /* ADP_Stopped_DivisionByZero */
case 0x20029: /* ADP_Stopped_OSSpecific */
default:
fprintf(stderr, "semihosting: exception %#x\n",
(unsigned) r1);
}
return target_call_event_callbacks(target, TARGET_EVENT_HALTED);
case 0x0d: /* SYS_TMPNAM */
case 0x10: /* SYS_CLOCK */
case 0x12: /* SYS_SYSTEM */
case 0x17: /* angel_SWIreason_EnterSVC */
case 0x30: /* SYS_ELAPSED */
case 0x31: /* SYS_TICKFREQ */
default:
fprintf(stderr, "semihosting: unsupported call %#x\n",
(unsigned) r0);
result = -1;
arm->semihosting_errno = ENOTSUP;
}
/* resume execution to the original mode */
/* REVISIT this looks wrong ... ARM11 and Cortex-A8
* should work this way at least sometimes.
*/
if (is_arm7_9(target_to_arm7_9(target))) {
uint32_t spsr;
/* return value in R0 */
buf_set_u32(arm->core_cache->reg_list[0].value, 0, 32, result);
arm->core_cache->reg_list[0].dirty = 1;
/* LR --> PC */
buf_set_u32(arm->core_cache->reg_list[15].value, 0, 32,
buf_get_u32(arm_reg_current(arm, 14)->value, 0, 32));
arm->core_cache->reg_list[15].dirty = 1;
/* saved PSR --> current PSR */
spsr = buf_get_u32(arm->spsr->value, 0, 32);
/* REVISIT should this be arm_set_cpsr(arm, spsr)
* instead of a partially unrolled version?
*/
buf_set_u32(arm->cpsr->value, 0, 32, spsr);
arm->cpsr->dirty = 1;
arm->core_mode = spsr & 0x1f;
if (spsr & 0x20)
arm->core_state = ARM_STATE_THUMB;
} else {
/* resume execution, this will be pc+2 to skip over the
* bkpt instruction */
/* return result in R0 */
buf_set_u32(arm->core_cache->reg_list[0].value, 0, 32, result);
arm->core_cache->reg_list[0].dirty = 1;
}
return target_resume(target, 1, 0, 0, 0);
}
/**
* Checks for and processes an ARM semihosting request. This is meant
* to be called when the target is stopped due to a debug mode entry.
* If the value 0 is returned then there was nothing to process. A non-zero
* return value signifies that a request was processed and the target resumed,
* or an error was encountered, in which case the caller must return
* immediately.
*
* @param target Pointer to the ARM target to process. This target must
* not represent an ARMv6-M or ARMv7-M processor.
* @param retval Pointer to a location where the return code will be stored
* @return non-zero value if a request was processed or an error encountered
*/
int arm_semihosting(struct target *target, int *retval)
{
struct arm *arm = target_to_arm(target);
uint32_t pc, lr, spsr;
struct reg *r;
if (!arm->is_semihosting)
return 0;
if (is_arm7_9(target_to_arm7_9(target))) {
if (arm->core_mode != ARM_MODE_SVC)
return 0;
/* Check for PC == 0x00000008 or 0xffff0008: Supervisor Call vector. */
r = arm->pc;
pc = buf_get_u32(r->value, 0, 32);
if (pc != 0x00000008 && pc != 0xffff0008)
return 0;
r = arm_reg_current(arm, 14);
lr = buf_get_u32(r->value, 0, 32);
/* Core-specific code should make sure SPSR is retrieved
* when the above checks pass...
*/
if (!arm->spsr->valid) {
LOG_ERROR("SPSR not valid!");
*retval = ERROR_FAIL;
return 1;
}
spsr = buf_get_u32(arm->spsr->value, 0, 32);
/* check instruction that triggered this trap */
if (spsr & (1 << 5)) {
/* was in Thumb (or ThumbEE) mode */
uint8_t insn_buf[2];
uint16_t insn;
*retval = target_read_memory(target, lr-2, 2, 1, insn_buf);
if (*retval != ERROR_OK)
return 1;
insn = target_buffer_get_u16(target, insn_buf);
/* SVC 0xab */
if (insn != 0xDFAB)
return 0;
} else if (spsr & (1 << 24)) {
/* was in Jazelle mode */
return 0;
} else {
/* was in ARM mode */
uint8_t insn_buf[4];
uint32_t insn;
*retval = target_read_memory(target, lr-4, 4, 1, insn_buf);
if (*retval != ERROR_OK)
return 1;
insn = target_buffer_get_u32(target, insn_buf);
/* SVC 0x123456 */
if (insn != 0xEF123456)
return 0;
}
} else if (is_armv7m(target_to_armv7m(target))) {
uint16_t insn;
if (target->debug_reason != DBG_REASON_BREAKPOINT)
return 0;
r = arm->pc;
pc = buf_get_u32(r->value, 0, 32);
pc &= ~1;
*retval = target_read_u16(target, pc, &insn);
if (*retval != ERROR_OK)
return 1;
/* bkpt 0xAB */
if (insn != 0xBEAB)
return 0;
} else {
LOG_ERROR("Unsupported semi-hosting Target");
return 0;
}
*retval = do_semihosting(target);
return 1;
}

View File

@ -0,0 +1,26 @@
/***************************************************************************
* Copyright (C) 2009 by Marvell Technology Group Ltd. *
* Written by Nicolas Pitre <nico@marvell.com> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef ARM_SEMIHOSTING_H
#define ARM_SEMIHOSTING_H
int arm_semihosting(struct target *target, int *retval);
#endif

View File

@ -0,0 +1,724 @@
/***************************************************************************
* Copyright (C) 2006 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* Copyright (C) 2008 by Hongtao Zheng *
* hontor@126.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "arm.h"
#include "armv4_5.h"
#include "arm_disassembler.h"
#include "arm_simulator.h"
#include <helper/binarybuffer.h>
#include "register.h"
#include <helper/log.h>
static uint32_t arm_shift(uint8_t shift, uint32_t Rm,
uint32_t shift_amount, uint8_t *carry)
{
uint32_t return_value = 0;
shift_amount &= 0xff;
if (shift == 0x0) { /* LSL */
if ((shift_amount > 0) && (shift_amount <= 32)) {
return_value = Rm << shift_amount;
*carry = Rm >> (32 - shift_amount);
} else if (shift_amount > 32) {
return_value = 0x0;
*carry = 0x0;
} else /* (shift_amount == 0) */
return_value = Rm;
} else if (shift == 0x1) { /* LSR */
if ((shift_amount > 0) && (shift_amount <= 32)) {
return_value = Rm >> shift_amount;
*carry = (Rm >> (shift_amount - 1)) & 1;
} else if (shift_amount > 32) {
return_value = 0x0;
*carry = 0x0;
} else /* (shift_amount == 0) */
return_value = Rm;
} else if (shift == 0x2) { /* ASR */
if ((shift_amount > 0) && (shift_amount <= 32)) {
/* C right shifts of unsigned values are guaranteed to
* be logical (shift in zeroes); simulate an arithmetic
* shift (shift in signed-bit) by adding the sign bit
* manually
*/
return_value = Rm >> shift_amount;
if (Rm & 0x80000000)
return_value |= 0xffffffff << (32 - shift_amount);
} else if (shift_amount > 32) {
if (Rm & 0x80000000) {
return_value = 0xffffffff;
*carry = 0x1;
} else {
return_value = 0x0;
*carry = 0x0;
}
} else /* (shift_amount == 0) */
return_value = Rm;
} else if (shift == 0x3) { /* ROR */
if (shift_amount == 0)
return_value = Rm;
else {
shift_amount = shift_amount % 32;
return_value = (Rm >> shift_amount) | (Rm << (32 - shift_amount));
*carry = (return_value >> 31) & 0x1;
}
} else if (shift == 0x4) { /* RRX */
return_value = Rm >> 1;
if (*carry)
Rm |= 0x80000000;
*carry = Rm & 0x1;
}
return return_value;
}
static uint32_t arm_shifter_operand(struct arm_sim_interface *sim,
int variant, union arm_shifter_operand shifter_operand,
uint8_t *shifter_carry_out)
{
uint32_t return_value;
int instruction_size;
if (sim->get_state(sim) == ARM_STATE_ARM)
instruction_size = 4;
else
instruction_size = 2;
*shifter_carry_out = sim->get_cpsr(sim, 29, 1);
if (variant == 0) /* 32-bit immediate */
return_value = shifter_operand.immediate.immediate;
else if (variant == 1) {/* immediate shift */
uint32_t Rm = sim->get_reg_mode(sim, shifter_operand.immediate_shift.Rm);
/* adjust RM in case the PC is being read */
if (shifter_operand.immediate_shift.Rm == 15)
Rm += 2 * instruction_size;
return_value = arm_shift(shifter_operand.immediate_shift.shift,
Rm, shifter_operand.immediate_shift.shift_imm,
shifter_carry_out);
} else if (variant == 2) { /* register shift */
uint32_t Rm = sim->get_reg_mode(sim, shifter_operand.register_shift.Rm);
uint32_t Rs = sim->get_reg_mode(sim, shifter_operand.register_shift.Rs);
/* adjust RM in case the PC is being read */
if (shifter_operand.register_shift.Rm == 15)
Rm += 2 * instruction_size;
return_value = arm_shift(shifter_operand.immediate_shift.shift,
Rm, Rs, shifter_carry_out);
} else {
LOG_ERROR("BUG: shifter_operand.variant not 0, 1 or 2");
return_value = 0xffffffff;
}
return return_value;
}
static int pass_condition(uint32_t cpsr, uint32_t opcode)
{
switch ((opcode & 0xf0000000) >> 28) {
case 0x0: /* EQ */
if (cpsr & 0x40000000)
return 1;
else
return 0;
case 0x1: /* NE */
if (!(cpsr & 0x40000000))
return 1;
else
return 0;
case 0x2: /* CS */
if (cpsr & 0x20000000)
return 1;
else
return 0;
case 0x3: /* CC */
if (!(cpsr & 0x20000000))
return 1;
else
return 0;
case 0x4: /* MI */
if (cpsr & 0x80000000)
return 1;
else
return 0;
case 0x5: /* PL */
if (!(cpsr & 0x80000000))
return 1;
else
return 0;
case 0x6: /* VS */
if (cpsr & 0x10000000)
return 1;
else
return 0;
case 0x7: /* VC */
if (!(cpsr & 0x10000000))
return 1;
else
return 0;
case 0x8: /* HI */
if ((cpsr & 0x20000000) && !(cpsr & 0x40000000))
return 1;
else
return 0;
case 0x9: /* LS */
if (!(cpsr & 0x20000000) || (cpsr & 0x40000000))
return 1;
else
return 0;
case 0xa: /* GE */
if (((cpsr & 0x80000000) && (cpsr & 0x10000000))
|| (!(cpsr & 0x80000000) && !(cpsr & 0x10000000)))
return 1;
else
return 0;
case 0xb: /* LT */
if (((cpsr & 0x80000000) && !(cpsr & 0x10000000))
|| (!(cpsr & 0x80000000) && (cpsr & 0x10000000)))
return 1;
else
return 0;
case 0xc: /* GT */
if (!(cpsr & 0x40000000) &&
(((cpsr & 0x80000000) && (cpsr & 0x10000000))
|| (!(cpsr & 0x80000000) && !(cpsr & 0x10000000))))
return 1;
else
return 0;
case 0xd: /* LE */
if ((cpsr & 0x40000000) ||
((cpsr & 0x80000000) && !(cpsr & 0x10000000))
|| (!(cpsr & 0x80000000) && (cpsr & 0x10000000)))
return 1;
else
return 0;
case 0xe:
case 0xf:
return 1;
}
LOG_ERROR("BUG: should never get here");
return 0;
}
static int thumb_pass_branch_condition(uint32_t cpsr, uint16_t opcode)
{
return pass_condition(cpsr, (opcode & 0x0f00) << 20);
}
/* simulate a single step (if possible)
* if the dry_run_pc argument is provided, no state is changed,
* but the new pc is stored in the variable pointed at by the argument
*/
static int arm_simulate_step_core(struct target *target,
uint32_t *dry_run_pc, struct arm_sim_interface *sim)
{
uint32_t current_pc = sim->get_reg(sim, 15);
struct arm_instruction instruction;
int instruction_size;
int retval = ERROR_OK;
if (sim->get_state(sim) == ARM_STATE_ARM) {
uint32_t opcode;
/* get current instruction, and identify it */
retval = target_read_u32(target, current_pc, &opcode);
if (retval != ERROR_OK)
return retval;
retval = arm_evaluate_opcode(opcode, current_pc, &instruction);
if (retval != ERROR_OK)
return retval;
instruction_size = 4;
/* check condition code (for all instructions) */
if (!pass_condition(sim->get_cpsr(sim, 0, 32), opcode)) {
if (dry_run_pc)
*dry_run_pc = current_pc + instruction_size;
else
sim->set_reg(sim, 15, current_pc + instruction_size);
return ERROR_OK;
}
} else {
uint16_t opcode;
retval = target_read_u16(target, current_pc, &opcode);
if (retval != ERROR_OK)
return retval;
retval = thumb_evaluate_opcode(opcode, current_pc, &instruction);
if (retval != ERROR_OK)
return retval;
instruction_size = 2;
/* check condition code (only for branch (1) instructions) */
if ((opcode & 0xf000) == 0xd000
&& !thumb_pass_branch_condition(
sim->get_cpsr(sim, 0, 32), opcode)) {
if (dry_run_pc)
*dry_run_pc = current_pc + instruction_size;
else
sim->set_reg(sim, 15, current_pc + instruction_size);
return ERROR_OK;
}
/* Deal with 32-bit BL/BLX */
if ((opcode & 0xf800) == 0xf000) {
uint32_t high = instruction.info.b_bl_bx_blx.target_address;
retval = target_read_u16(target, current_pc+2, &opcode);
if (retval != ERROR_OK)
return retval;
retval = thumb_evaluate_opcode(opcode, current_pc, &instruction);
if (retval != ERROR_OK)
return retval;
instruction.info.b_bl_bx_blx.target_address += high;
}
}
/* examine instruction type */
/* branch instructions */
if ((instruction.type >= ARM_B) && (instruction.type <= ARM_BLX)) {
uint32_t target_address;
if (instruction.info.b_bl_bx_blx.reg_operand == -1)
target_address = instruction.info.b_bl_bx_blx.target_address;
else {
target_address = sim->get_reg_mode(sim,
instruction.info.b_bl_bx_blx.reg_operand);
if (instruction.info.b_bl_bx_blx.reg_operand == 15)
target_address += 2 * instruction_size;
}
if (dry_run_pc) {
*dry_run_pc = target_address & ~1;
return ERROR_OK;
} else {
if (instruction.type == ARM_B)
sim->set_reg(sim, 15, target_address);
else if (instruction.type == ARM_BL) {
uint32_t old_pc = sim->get_reg(sim, 15);
int T = (sim->get_state(sim) == ARM_STATE_THUMB);
sim->set_reg_mode(sim, 14, old_pc + 4 + T);
sim->set_reg(sim, 15, target_address);
} else if (instruction.type == ARM_BX) {
if (target_address & 0x1)
sim->set_state(sim, ARM_STATE_THUMB);
else
sim->set_state(sim, ARM_STATE_ARM);
sim->set_reg(sim, 15, target_address & 0xfffffffe);
} else if (instruction.type == ARM_BLX) {
uint32_t old_pc = sim->get_reg(sim, 15);
int T = (sim->get_state(sim) == ARM_STATE_THUMB);
sim->set_reg_mode(sim, 14, old_pc + 4 + T);
if (target_address & 0x1)
sim->set_state(sim, ARM_STATE_THUMB);
else
sim->set_state(sim, ARM_STATE_ARM);
sim->set_reg(sim, 15, target_address & 0xfffffffe);
}
return ERROR_OK;
}
}
/* data processing instructions, except compare instructions (CMP, CMN, TST, TEQ) */
else if (((instruction.type >= ARM_AND) && (instruction.type <= ARM_RSC))
|| ((instruction.type >= ARM_ORR) && (instruction.type <= ARM_MVN))) {
uint32_t Rd, Rn, shifter_operand;
uint8_t C = sim->get_cpsr(sim, 29, 1);
uint8_t carry_out;
Rd = 0x0;
/* ARM_MOV and ARM_MVN does not use Rn */
if ((instruction.type != ARM_MOV) && (instruction.type != ARM_MVN))
Rn = sim->get_reg_mode(sim, instruction.info.data_proc.Rn);
else
Rn = 0;
shifter_operand = arm_shifter_operand(sim,
instruction.info.data_proc.variant,
instruction.info.data_proc.shifter_operand,
&carry_out);
/* adjust Rn in case the PC is being read */
if (instruction.info.data_proc.Rn == 15)
Rn += 2 * instruction_size;
if (instruction.type == ARM_AND)
Rd = Rn & shifter_operand;
else if (instruction.type == ARM_EOR)
Rd = Rn ^ shifter_operand;
else if (instruction.type == ARM_SUB)
Rd = Rn - shifter_operand;
else if (instruction.type == ARM_RSB)
Rd = shifter_operand - Rn;
else if (instruction.type == ARM_ADD)
Rd = Rn + shifter_operand;
else if (instruction.type == ARM_ADC)
Rd = Rn + shifter_operand + (C & 1);
else if (instruction.type == ARM_SBC)
Rd = Rn - shifter_operand - (C & 1) ? 0 : 1;
else if (instruction.type == ARM_RSC)
Rd = shifter_operand - Rn - (C & 1) ? 0 : 1;
else if (instruction.type == ARM_ORR)
Rd = Rn | shifter_operand;
else if (instruction.type == ARM_BIC)
Rd = Rn & ~(shifter_operand);
else if (instruction.type == ARM_MOV)
Rd = shifter_operand;
else if (instruction.type == ARM_MVN)
Rd = ~shifter_operand;
else
LOG_WARNING("unhandled instruction type");
if (dry_run_pc) {
if (instruction.info.data_proc.Rd == 15)
*dry_run_pc = Rd & ~1;
else
*dry_run_pc = current_pc + instruction_size;
return ERROR_OK;
} else {
if (instruction.info.data_proc.Rd == 15) {
sim->set_reg_mode(sim, 15, Rd & ~1);
if (Rd & 1)
sim->set_state(sim, ARM_STATE_THUMB);
else
sim->set_state(sim, ARM_STATE_ARM);
return ERROR_OK;
}
sim->set_reg_mode(sim, instruction.info.data_proc.Rd, Rd);
LOG_WARNING("no updating of flags yet");
}
}
/* compare instructions (CMP, CMN, TST, TEQ) */
else if ((instruction.type >= ARM_TST) && (instruction.type <= ARM_CMN)) {
if (dry_run_pc) {
*dry_run_pc = current_pc + instruction_size;
return ERROR_OK;
} else
LOG_WARNING("no updating of flags yet");
}
/* load register instructions */
else if ((instruction.type >= ARM_LDR) && (instruction.type <= ARM_LDRSH)) {
uint32_t load_address = 0, modified_address = 0, load_value = 0;
uint32_t Rn = sim->get_reg_mode(sim, instruction.info.load_store.Rn);
/* adjust Rn in case the PC is being read */
if (instruction.info.load_store.Rn == 15)
Rn += 2 * instruction_size;
if (instruction.info.load_store.offset_mode == 0) {
if (instruction.info.load_store.U)
modified_address = Rn + instruction.info.load_store.offset.offset;
else
modified_address = Rn - instruction.info.load_store.offset.offset;
} else if (instruction.info.load_store.offset_mode == 1) {
uint32_t offset;
uint32_t Rm = sim->get_reg_mode(sim,
instruction.info.load_store.offset.reg.Rm);
uint8_t shift = instruction.info.load_store.offset.reg.shift;
uint8_t shift_imm = instruction.info.load_store.offset.reg.shift_imm;
uint8_t carry = sim->get_cpsr(sim, 29, 1);
offset = arm_shift(shift, Rm, shift_imm, &carry);
if (instruction.info.load_store.U)
modified_address = Rn + offset;
else
modified_address = Rn - offset;
} else
LOG_ERROR("BUG: offset_mode neither 0 (offset) nor 1 (scaled register)");
if (instruction.info.load_store.index_mode == 0) {
/* offset mode
* we load from the modified address, but don't change
* the base address register
*/
load_address = modified_address;
modified_address = Rn;
} else if (instruction.info.load_store.index_mode == 1) {
/* pre-indexed mode
* we load from the modified address, and write it
* back to the base address register
*/
load_address = modified_address;
} else if (instruction.info.load_store.index_mode == 2) {
/* post-indexed mode
* we load from the unmodified address, and write the
* modified address back
*/
load_address = Rn;
}
if ((!dry_run_pc) || (instruction.info.load_store.Rd == 15)) {
retval = target_read_u32(target, load_address, &load_value);
if (retval != ERROR_OK)
return retval;
}
if (dry_run_pc) {
if (instruction.info.load_store.Rd == 15)
*dry_run_pc = load_value & ~1;
else
*dry_run_pc = current_pc + instruction_size;
return ERROR_OK;
} else {
if ((instruction.info.load_store.index_mode == 1) ||
(instruction.info.load_store.index_mode == 2))
sim->set_reg_mode(sim,
instruction.info.load_store.Rn,
modified_address);
if (instruction.info.load_store.Rd == 15) {
sim->set_reg_mode(sim, 15, load_value & ~1);
if (load_value & 1)
sim->set_state(sim, ARM_STATE_THUMB);
else
sim->set_state(sim, ARM_STATE_ARM);
return ERROR_OK;
}
sim->set_reg_mode(sim, instruction.info.load_store.Rd, load_value);
}
}
/* load multiple instruction */
else if (instruction.type == ARM_LDM) {
int i;
uint32_t Rn = sim->get_reg_mode(sim, instruction.info.load_store_multiple.Rn);
uint32_t load_values[16];
int bits_set = 0;
for (i = 0; i < 16; i++) {
if (instruction.info.load_store_multiple.register_list & (1 << i))
bits_set++;
}
switch (instruction.info.load_store_multiple.addressing_mode) {
case 0: /* Increment after */
/* Rn = Rn; */
break;
case 1: /* Increment before */
Rn = Rn + 4;
break;
case 2: /* Decrement after */
Rn = Rn - (bits_set * 4) + 4;
break;
case 3: /* Decrement before */
Rn = Rn - (bits_set * 4);
break;
}
for (i = 0; i < 16; i++) {
if (instruction.info.load_store_multiple.register_list & (1 << i)) {
if ((!dry_run_pc) || (i == 15))
target_read_u32(target, Rn, &load_values[i]);
Rn += 4;
}
}
if (dry_run_pc) {
if (instruction.info.load_store_multiple.register_list & 0x8000) {
*dry_run_pc = load_values[15] & ~1;
return ERROR_OK;
}
} else {
int update_cpsr = 0;
if (instruction.info.load_store_multiple.S) {
if (instruction.info.load_store_multiple.register_list & 0x8000)
update_cpsr = 1;
}
for (i = 0; i < 16; i++) {
if (instruction.info.load_store_multiple.register_list & (1 << i)) {
if (i == 15) {
uint32_t val = load_values[i];
sim->set_reg_mode(sim, i, val & ~1);
if (val & 1)
sim->set_state(sim, ARM_STATE_THUMB);
else
sim->set_state(sim, ARM_STATE_ARM);
} else
sim->set_reg_mode(sim, i, load_values[i]);
}
}
if (update_cpsr) {
uint32_t spsr = sim->get_reg_mode(sim, 16);
sim->set_reg(sim, ARMV4_5_CPSR, spsr);
}
/* base register writeback */
if (instruction.info.load_store_multiple.W)
sim->set_reg_mode(sim, instruction.info.load_store_multiple.Rn, Rn);
if (instruction.info.load_store_multiple.register_list & 0x8000)
return ERROR_OK;
}
}
/* store multiple instruction */
else if (instruction.type == ARM_STM) {
int i;
if (dry_run_pc) {
/* STM wont affect PC (advance by instruction size */
} else {
uint32_t Rn = sim->get_reg_mode(sim,
instruction.info.load_store_multiple.Rn);
int bits_set = 0;
for (i = 0; i < 16; i++) {
if (instruction.info.load_store_multiple.register_list & (1 << i))
bits_set++;
}
switch (instruction.info.load_store_multiple.addressing_mode) {
case 0: /* Increment after */
/* Rn = Rn; */
break;
case 1: /* Increment before */
Rn = Rn + 4;
break;
case 2: /* Decrement after */
Rn = Rn - (bits_set * 4) + 4;
break;
case 3: /* Decrement before */
Rn = Rn - (bits_set * 4);
break;
}
for (i = 0; i < 16; i++) {
if (instruction.info.load_store_multiple.register_list & (1 << i)) {
target_write_u32(target, Rn, sim->get_reg_mode(sim, i));
Rn += 4;
}
}
/* base register writeback */
if (instruction.info.load_store_multiple.W)
sim->set_reg_mode(sim,
instruction.info.load_store_multiple.Rn, Rn);
}
} else if (!dry_run_pc) {
/* the instruction wasn't handled, but we're supposed to simulate it
*/
LOG_ERROR("Unimplemented instruction, could not simulate it.");
return ERROR_FAIL;
}
if (dry_run_pc) {
*dry_run_pc = current_pc + instruction_size;
return ERROR_OK;
} else {
sim->set_reg(sim, 15, current_pc + instruction_size);
return ERROR_OK;
}
}
static uint32_t armv4_5_get_reg(struct arm_sim_interface *sim, int reg)
{
struct arm *arm = (struct arm *)sim->user_data;
return buf_get_u32(arm->core_cache->reg_list[reg].value, 0, 32);
}
static void armv4_5_set_reg(struct arm_sim_interface *sim, int reg, uint32_t value)
{
struct arm *arm = (struct arm *)sim->user_data;
buf_set_u32(arm->core_cache->reg_list[reg].value, 0, 32, value);
}
static uint32_t armv4_5_get_reg_mode(struct arm_sim_interface *sim, int reg)
{
struct arm *arm = (struct arm *)sim->user_data;
return buf_get_u32(ARMV4_5_CORE_REG_MODE(arm->core_cache,
arm->core_mode, reg).value, 0, 32);
}
static void armv4_5_set_reg_mode(struct arm_sim_interface *sim, int reg, uint32_t value)
{
struct arm *arm = (struct arm *)sim->user_data;
buf_set_u32(ARMV4_5_CORE_REG_MODE(arm->core_cache,
arm->core_mode, reg).value, 0, 32, value);
}
static uint32_t armv4_5_get_cpsr(struct arm_sim_interface *sim, int pos, int bits)
{
struct arm *arm = (struct arm *)sim->user_data;
return buf_get_u32(arm->cpsr->value, pos, bits);
}
static enum arm_state armv4_5_get_state(struct arm_sim_interface *sim)
{
struct arm *arm = (struct arm *)sim->user_data;
return arm->core_state;
}
static void armv4_5_set_state(struct arm_sim_interface *sim, enum arm_state mode)
{
struct arm *arm = (struct arm *)sim->user_data;
arm->core_state = mode;
}
static enum arm_mode armv4_5_get_mode(struct arm_sim_interface *sim)
{
struct arm *arm = (struct arm *)sim->user_data;
return arm->core_mode;
}
int arm_simulate_step(struct target *target, uint32_t *dry_run_pc)
{
struct arm *arm = target_to_arm(target);
struct arm_sim_interface sim;
sim.user_data = arm;
sim.get_reg = &armv4_5_get_reg;
sim.set_reg = &armv4_5_set_reg;
sim.get_reg_mode = &armv4_5_get_reg_mode;
sim.set_reg_mode = &armv4_5_set_reg_mode;
sim.get_cpsr = &armv4_5_get_cpsr;
sim.get_mode = &armv4_5_get_mode;
sim.get_state = &armv4_5_get_state;
sim.set_state = &armv4_5_set_state;
return arm_simulate_step_core(target, dry_run_pc, &sim);
}

View File

@ -0,0 +1,41 @@
/***************************************************************************
* Copyright (C) 2006 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef ARM_SIMULATOR_H
#define ARM_SIMULATOR_H
struct target;
struct arm_sim_interface {
void *user_data;
uint32_t (*get_reg)(struct arm_sim_interface *sim, int reg);
void (*set_reg)(struct arm_sim_interface *sim, int reg, uint32_t value);
uint32_t (*get_reg_mode)(struct arm_sim_interface *sim, int reg);
void (*set_reg_mode)(struct arm_sim_interface *sim, int reg, uint32_t value);
uint32_t (*get_cpsr)(struct arm_sim_interface *sim, int pos, int bits);
enum arm_state (*get_state)(struct arm_sim_interface *sim);
void (*set_state)(struct arm_sim_interface *sim, enum arm_state mode);
enum arm_mode (*get_mode)(struct arm_sim_interface *sim);
};
/* armv4_5 version */
int arm_simulate_step(struct target *target, uint32_t *dry_run_pc);
#endif /* ARM_SIMULATOR_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,51 @@
/***************************************************************************
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* Copyright (C) 2008 by Spencer Oliver *
* spen@spen-soft.co.uk *
* *
* Copyright (C) 2009 by Øyvind Harboe *
* oyvind.harboe@zylin.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef ARMV4_5_H
#define ARMV4_5_H
/* This stuff "knows" that its callers aren't talking
* to microcontroller profile (current Cortex-M) parts.
* We want to phase it out so core code can be shared.
*/
/* OBSOLETE, DO NOT USE IN NEW CODE! The "number" of an arm_mode is an
* index into the armv4_5_core_reg_map array. Its remaining users are
* remnants which could as easily walk * the register cache directly as
* use the expensive ARMV4_5_CORE_REG_MODE() macro.
*/
int arm_mode_to_number(enum arm_mode mode);
enum arm_mode armv4_5_number_to_mode(int number);
extern const int armv4_5_core_reg_map[8][17];
#define ARMV4_5_CORE_REG_MODE(cache, mode, num) \
(cache->reg_list[armv4_5_core_reg_map[arm_mode_to_number(mode)][num]])
/* offset into armv4_5 core register cache -- OBSOLETE, DO NOT USE! */
enum { ARMV4_5_CPSR = 31, };
#endif /* ARMV4_5_H */

View File

@ -0,0 +1,104 @@
/***************************************************************************
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "armv4_5_cache.h"
#include <helper/log.h>
int armv4_5_identify_cache(uint32_t cache_type_reg, struct armv4_5_cache_common *cache)
{
int size, assoc, M, len, multiplier;
cache->ctype = (cache_type_reg & 0x1e000000U) >> 25;
cache->separate = (cache_type_reg & 0x01000000U) >> 24;
size = (cache_type_reg & 0x1c0000) >> 18;
assoc = (cache_type_reg & 0x38000) >> 15;
M = (cache_type_reg & 0x4000) >> 14;
len = (cache_type_reg & 0x3000) >> 12;
multiplier = 2 + M;
if ((assoc != 0) || (M != 1)) /* assoc 0 and M 1 means cache absent */ {
/* cache is present */
cache->d_u_size.linelen = 1 << (len + 3);
cache->d_u_size.associativity = multiplier << (assoc - 1);
cache->d_u_size.nsets = 1 << (size + 6 - assoc - len);
cache->d_u_size.cachesize = multiplier << (size + 8);
} else {
/* cache is absent */
cache->d_u_size.linelen = -1;
cache->d_u_size.associativity = -1;
cache->d_u_size.nsets = -1;
cache->d_u_size.cachesize = -1;
}
if (cache->separate) {
size = (cache_type_reg & 0x1c0) >> 6;
assoc = (cache_type_reg & 0x38) >> 3;
M = (cache_type_reg & 0x4) >> 2;
len = (cache_type_reg & 0x3);
multiplier = 2 + M;
if ((assoc != 0) || (M != 1)) /* assoc 0 and M 1 means cache absent */ {
/* cache is present */
cache->i_size.linelen = 1 << (len + 3);
cache->i_size.associativity = multiplier << (assoc - 1);
cache->i_size.nsets = 1 << (size + 6 - assoc - len);
cache->i_size.cachesize = multiplier << (size + 8);
} else {
/* cache is absent */
cache->i_size.linelen = -1;
cache->i_size.associativity = -1;
cache->i_size.nsets = -1;
cache->i_size.cachesize = -1;
}
} else
cache->i_size = cache->d_u_size;
return ERROR_OK;
}
int armv4_5_handle_cache_info_command(struct command_context *cmd_ctx, struct armv4_5_cache_common *armv4_5_cache)
{
if (armv4_5_cache->ctype == -1) {
command_print(cmd_ctx, "cache not yet identified");
return ERROR_OK;
}
command_print(cmd_ctx, "cache type: 0x%1.1x, %s", armv4_5_cache->ctype,
(armv4_5_cache->separate) ? "separate caches" : "unified cache");
command_print(cmd_ctx, "D-Cache: linelen %i, associativity %i, nsets %i, cachesize 0x%x",
armv4_5_cache->d_u_size.linelen,
armv4_5_cache->d_u_size.associativity,
armv4_5_cache->d_u_size.nsets,
armv4_5_cache->d_u_size.cachesize);
command_print(cmd_ctx, "I-Cache: linelen %i, associativity %i, nsets %i, cachesize 0x%x",
armv4_5_cache->i_size.linelen,
armv4_5_cache->i_size.associativity,
armv4_5_cache->i_size.nsets,
armv4_5_cache->i_size.cachesize);
return ERROR_OK;
}

View File

@ -0,0 +1,57 @@
/***************************************************************************
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef ARMV4_5_CACHE_H
#define ARMV4_5_CACHE_H
struct command_context;
struct armv4_5_cachesize {
int linelen;
int associativity;
int nsets;
int cachesize;
};
struct armv4_5_cache_common {
int ctype; /* specify supported cache operations */
int separate; /* separate caches or unified cache */
struct armv4_5_cachesize d_u_size; /* data cache */
struct armv4_5_cachesize i_size; /* instruction cache */
int i_cache_enabled;
int d_u_cache_enabled;
};
int armv4_5_identify_cache(uint32_t cache_type_reg,
struct armv4_5_cache_common *cache);
int armv4_5_cache_state(uint32_t cp15_control_reg,
struct armv4_5_cache_common *cache);
int armv4_5_handle_cache_info_command(struct command_context *cmd_ctx,
struct armv4_5_cache_common *armv4_5_cache);
enum {
ARMV4_5_D_U_CACHE_ENABLED = 0x4,
ARMV4_5_I_CACHE_ENABLED = 0x1000,
ARMV4_5_WRITE_BUFFER_ENABLED = 0x8,
ARMV4_5_CACHE_RR_BIT = 0x5000,
};
#endif /* ARMV4_5_CACHE_H */

View File

@ -0,0 +1,171 @@
/***************************************************************************
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <helper/log.h>
#include "target.h"
#include "armv4_5_mmu.h"
int armv4_5_mmu_translate_va(struct target *target,
struct armv4_5_mmu_common *armv4_5_mmu, uint32_t va, uint32_t *cb, uint32_t *val)
{
uint32_t first_lvl_descriptor = 0x0;
uint32_t second_lvl_descriptor = 0x0;
uint32_t ttb;
int retval;
retval = armv4_5_mmu->get_ttb(target, &ttb);
if (retval != ERROR_OK)
return retval;
retval = armv4_5_mmu_read_physical(target, armv4_5_mmu,
(ttb & 0xffffc000) | ((va & 0xfff00000) >> 18),
4, 1, (uint8_t *)&first_lvl_descriptor);
if (retval != ERROR_OK)
return retval;
first_lvl_descriptor = target_buffer_get_u32(target, (uint8_t *)&first_lvl_descriptor);
LOG_DEBUG("1st lvl desc: %8.8" PRIx32 "", first_lvl_descriptor);
if ((first_lvl_descriptor & 0x3) == 0) {
LOG_ERROR("Address translation failure");
return ERROR_TARGET_TRANSLATION_FAULT;
}
if (!armv4_5_mmu->has_tiny_pages && ((first_lvl_descriptor & 0x3) == 3)) {
LOG_ERROR("Address translation failure");
return ERROR_TARGET_TRANSLATION_FAULT;
}
if ((first_lvl_descriptor & 0x3) == 2) {
/* section descriptor */
*cb = (first_lvl_descriptor & 0xc) >> 2;
*val = (first_lvl_descriptor & 0xfff00000) | (va & 0x000fffff);
return ERROR_OK;
}
if ((first_lvl_descriptor & 0x3) == 1) {
/* coarse page table */
retval = armv4_5_mmu_read_physical(target, armv4_5_mmu,
(first_lvl_descriptor & 0xfffffc00) | ((va & 0x000ff000) >> 10),
4, 1, (uint8_t *)&second_lvl_descriptor);
if (retval != ERROR_OK)
return retval;
} else if ((first_lvl_descriptor & 0x3) == 3) {
/* fine page table */
retval = armv4_5_mmu_read_physical(target, armv4_5_mmu,
(first_lvl_descriptor & 0xfffff000) | ((va & 0x000ffc00) >> 8),
4, 1, (uint8_t *)&second_lvl_descriptor);
if (retval != ERROR_OK)
return retval;
}
second_lvl_descriptor = target_buffer_get_u32(target, (uint8_t *)&second_lvl_descriptor);
LOG_DEBUG("2nd lvl desc: %8.8" PRIx32 "", second_lvl_descriptor);
if ((second_lvl_descriptor & 0x3) == 0) {
LOG_ERROR("Address translation failure");
return ERROR_TARGET_TRANSLATION_FAULT;
}
/* cacheable/bufferable is always specified in bits 3-2 */
*cb = (second_lvl_descriptor & 0xc) >> 2;
if ((second_lvl_descriptor & 0x3) == 1) {
/* large page descriptor */
*val = (second_lvl_descriptor & 0xffff0000) | (va & 0x0000ffff);
return ERROR_OK;
}
if ((second_lvl_descriptor & 0x3) == 2) {
/* small page descriptor */
*val = (second_lvl_descriptor & 0xfffff000) | (va & 0x00000fff);
return ERROR_OK;
}
if ((second_lvl_descriptor & 0x3) == 3) {
/* tiny page descriptor */
*val = (second_lvl_descriptor & 0xfffffc00) | (va & 0x000003ff);
return ERROR_OK;
}
/* should not happen */
LOG_ERROR("Address translation failure");
return ERROR_TARGET_TRANSLATION_FAULT;
}
int armv4_5_mmu_read_physical(struct target *target,
struct armv4_5_mmu_common *armv4_5_mmu, uint32_t address,
uint32_t size, uint32_t count, uint8_t *buffer)
{
int retval;
if (target->state != TARGET_HALTED)
return ERROR_TARGET_NOT_HALTED;
/* disable MMU and data (or unified) cache */
retval = armv4_5_mmu->disable_mmu_caches(target, 1, 1, 0);
if (retval != ERROR_OK)
return retval;
retval = armv4_5_mmu->read_memory(target, address, size, count, buffer);
if (retval != ERROR_OK)
return retval;
/* reenable MMU / cache */
retval = armv4_5_mmu->enable_mmu_caches(target, armv4_5_mmu->mmu_enabled,
armv4_5_mmu->armv4_5_cache.d_u_cache_enabled,
armv4_5_mmu->armv4_5_cache.i_cache_enabled);
if (retval != ERROR_OK)
return retval;
return retval;
}
int armv4_5_mmu_write_physical(struct target *target,
struct armv4_5_mmu_common *armv4_5_mmu, uint32_t address,
uint32_t size, uint32_t count, const uint8_t *buffer)
{
int retval;
if (target->state != TARGET_HALTED)
return ERROR_TARGET_NOT_HALTED;
/* disable MMU and data (or unified) cache */
retval = armv4_5_mmu->disable_mmu_caches(target, 1, 1, 0);
if (retval != ERROR_OK)
return retval;
retval = armv4_5_mmu->write_memory(target, address, size, count, buffer);
if (retval != ERROR_OK)
return retval;
/* reenable MMU / cache */
retval = armv4_5_mmu->enable_mmu_caches(target, armv4_5_mmu->mmu_enabled,
armv4_5_mmu->armv4_5_cache.d_u_cache_enabled,
armv4_5_mmu->armv4_5_cache.i_cache_enabled);
if (retval != ERROR_OK)
return retval;
return retval;
}

View File

@ -0,0 +1,58 @@
/***************************************************************************
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef ARMV4_5_MMU_H
#define ARMV4_5_MMU_H
#include "armv4_5_cache.h"
struct target;
struct armv4_5_mmu_common {
int (*get_ttb)(struct target *target, uint32_t *result);
int (*read_memory)(struct target *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer);
int (*write_memory)(struct target *target, uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer);
int (*disable_mmu_caches)(struct target *target, int mmu, int d_u_cache, int i_cache);
int (*enable_mmu_caches)(struct target *target, int mmu, int d_u_cache, int i_cache);
struct armv4_5_cache_common armv4_5_cache;
int has_tiny_pages;
int mmu_enabled;
};
int armv4_5_mmu_translate_va(struct target *target,
struct armv4_5_mmu_common *armv4_5_mmu, uint32_t va,
uint32_t *cb, uint32_t *val);
int armv4_5_mmu_read_physical(struct target *target,
struct armv4_5_mmu_common *armv4_5_mmu,
uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer);
int armv4_5_mmu_write_physical(struct target *target,
struct armv4_5_mmu_common *armv4_5_mmu,
uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer);
enum {
ARMV4_5_MMU_ENABLED = 0x1,
ARMV4_5_ALIGNMENT_CHECK = 0x2,
ARMV4_5_MMU_S_BIT = 0x100,
ARMV4_5_MMU_R_BIT = 0x200
};
#endif /* ARMV4_5_MMU_H */

View File

@ -0,0 +1,804 @@
/***************************************************************************
* Copyright (C) 2009 by David Brownell *
* *
* Copyright (C) ST-Ericsson SA 2011 michel.jaouen@stericsson.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <helper/replacements.h>
#include "armv7a.h"
#include "arm_disassembler.h"
#include "register.h"
#include <helper/binarybuffer.h>
#include <helper/command.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "arm_opcodes.h"
#include "target.h"
#include "target_type.h"
static void armv7a_show_fault_registers(struct target *target)
{
uint32_t dfsr, ifsr, dfar, ifar;
struct armv7a_common *armv7a = target_to_armv7a(target);
struct arm_dpm *dpm = armv7a->arm.dpm;
int retval;
retval = dpm->prepare(dpm);
if (retval != ERROR_OK)
return;
/* ARMV4_5_MRC(cpnum, op1, r0, CRn, CRm, op2) */
/* c5/c0 - {data, instruction} fault status registers */
retval = dpm->instr_read_data_r0(dpm,
ARMV4_5_MRC(15, 0, 0, 5, 0, 0),
&dfsr);
if (retval != ERROR_OK)
goto done;
retval = dpm->instr_read_data_r0(dpm,
ARMV4_5_MRC(15, 0, 0, 5, 0, 1),
&ifsr);
if (retval != ERROR_OK)
goto done;
/* c6/c0 - {data, instruction} fault address registers */
retval = dpm->instr_read_data_r0(dpm,
ARMV4_5_MRC(15, 0, 0, 6, 0, 0),
&dfar);
if (retval != ERROR_OK)
goto done;
retval = dpm->instr_read_data_r0(dpm,
ARMV4_5_MRC(15, 0, 0, 6, 0, 2),
&ifar);
if (retval != ERROR_OK)
goto done;
LOG_USER("Data fault registers DFSR: %8.8" PRIx32
", DFAR: %8.8" PRIx32, dfsr, dfar);
LOG_USER("Instruction fault registers IFSR: %8.8" PRIx32
", IFAR: %8.8" PRIx32, ifsr, ifar);
done:
/* (void) */ dpm->finish(dpm);
}
static int armv7a_read_ttbcr(struct target *target)
{
struct armv7a_common *armv7a = target_to_armv7a(target);
struct arm_dpm *dpm = armv7a->arm.dpm;
uint32_t ttbcr;
int retval = dpm->prepare(dpm);
if (retval != ERROR_OK)
goto done;
/* MRC p15,0,<Rt>,c2,c0,2 ; Read CP15 Translation Table Base Control Register*/
retval = dpm->instr_read_data_r0(dpm,
ARMV4_5_MRC(15, 0, 0, 2, 0, 2),
&ttbcr);
if (retval != ERROR_OK)
goto done;
armv7a->armv7a_mmu.ttbr1_used = ((ttbcr & 0x7) != 0) ? 1 : 0;
armv7a->armv7a_mmu.ttbr0_mask = 7 << (32 - ((ttbcr & 0x7)));
#if 0
LOG_INFO("ttb1 %s ,ttb0_mask %x",
armv7a->armv7a_mmu.ttbr1_used ? "used" : "not used",
armv7a->armv7a_mmu.ttbr0_mask);
#endif
if (armv7a->armv7a_mmu.ttbr1_used == 1) {
LOG_INFO("SVC access above %x",
(0xffffffff & armv7a->armv7a_mmu.ttbr0_mask));
armv7a->armv7a_mmu.os_border = 0xffffffff & armv7a->armv7a_mmu.ttbr0_mask;
} else {
/* fix me , default is hard coded LINUX border */
armv7a->armv7a_mmu.os_border = 0xc0000000;
}
done:
dpm->finish(dpm);
return retval;
}
/* method adapted to cortex A : reused arm v4 v5 method*/
int armv7a_mmu_translate_va(struct target *target, uint32_t va, uint32_t *val)
{
uint32_t first_lvl_descriptor = 0x0;
uint32_t second_lvl_descriptor = 0x0;
int retval;
struct armv7a_common *armv7a = target_to_armv7a(target);
struct arm_dpm *dpm = armv7a->arm.dpm;
uint32_t ttb = 0; /* default ttb0 */
if (armv7a->armv7a_mmu.ttbr1_used == -1)
armv7a_read_ttbcr(target);
if ((armv7a->armv7a_mmu.ttbr1_used) &&
(va > (0xffffffff & armv7a->armv7a_mmu.ttbr0_mask))) {
/* select ttb 1 */
ttb = 1;
}
retval = dpm->prepare(dpm);
if (retval != ERROR_OK)
goto done;
/* MRC p15,0,<Rt>,c2,c0,ttb */
retval = dpm->instr_read_data_r0(dpm,
ARMV4_5_MRC(15, 0, 0, 2, 0, ttb),
&ttb);
if (retval != ERROR_OK)
return retval;
retval = armv7a->armv7a_mmu.read_physical_memory(target,
(ttb & 0xffffc000) | ((va & 0xfff00000) >> 18),
4, 1, (uint8_t *)&first_lvl_descriptor);
if (retval != ERROR_OK)
return retval;
first_lvl_descriptor = target_buffer_get_u32(target, (uint8_t *)
&first_lvl_descriptor);
/* reuse armv4_5 piece of code, specific armv7a changes may come later */
LOG_DEBUG("1st lvl desc: %8.8" PRIx32 "", first_lvl_descriptor);
if ((first_lvl_descriptor & 0x3) == 0) {
LOG_ERROR("Address translation failure");
return ERROR_TARGET_TRANSLATION_FAULT;
}
if ((first_lvl_descriptor & 0x3) == 2) {
/* section descriptor */
*val = (first_lvl_descriptor & 0xfff00000) | (va & 0x000fffff);
return ERROR_OK;
}
if ((first_lvl_descriptor & 0x3) == 1) {
/* coarse page table */
retval = armv7a->armv7a_mmu.read_physical_memory(target,
(first_lvl_descriptor & 0xfffffc00) | ((va & 0x000ff000) >> 10),
4, 1, (uint8_t *)&second_lvl_descriptor);
if (retval != ERROR_OK)
return retval;
} else if ((first_lvl_descriptor & 0x3) == 3) {
/* fine page table */
retval = armv7a->armv7a_mmu.read_physical_memory(target,
(first_lvl_descriptor & 0xfffff000) | ((va & 0x000ffc00) >> 8),
4, 1, (uint8_t *)&second_lvl_descriptor);
if (retval != ERROR_OK)
return retval;
}
second_lvl_descriptor = target_buffer_get_u32(target, (uint8_t *)
&second_lvl_descriptor);
LOG_DEBUG("2nd lvl desc: %8.8" PRIx32 "", second_lvl_descriptor);
if ((second_lvl_descriptor & 0x3) == 0) {
LOG_ERROR("Address translation failure");
return ERROR_TARGET_TRANSLATION_FAULT;
}
if ((second_lvl_descriptor & 0x3) == 1) {
/* large page descriptor */
*val = (second_lvl_descriptor & 0xffff0000) | (va & 0x0000ffff);
return ERROR_OK;
}
if ((second_lvl_descriptor & 0x3) == 2) {
/* small page descriptor */
*val = (second_lvl_descriptor & 0xfffff000) | (va & 0x00000fff);
return ERROR_OK;
}
if ((second_lvl_descriptor & 0x3) == 3) {
*val = (second_lvl_descriptor & 0xfffffc00) | (va & 0x000003ff);
return ERROR_OK;
}
/* should not happen */
LOG_ERROR("Address translation failure");
return ERROR_TARGET_TRANSLATION_FAULT;
done:
return retval;
}
/* V7 method VA TO PA */
int armv7a_mmu_translate_va_pa(struct target *target, uint32_t va,
uint32_t *val, int meminfo)
{
int retval = ERROR_FAIL;
struct armv7a_common *armv7a = target_to_armv7a(target);
struct arm_dpm *dpm = armv7a->arm.dpm;
uint32_t virt = va & ~0xfff;
uint32_t NOS, NS, INNER, OUTER;
*val = 0xdeadbeef;
retval = dpm->prepare(dpm);
if (retval != ERROR_OK)
goto done;
/* mmu must be enable in order to get a correct translation
* use VA to PA CP15 register for conversion */
retval = dpm->instr_write_data_r0(dpm,
ARMV4_5_MCR(15, 0, 0, 7, 8, 0),
virt);
if (retval != ERROR_OK)
goto done;
retval = dpm->instr_read_data_r0(dpm,
ARMV4_5_MRC(15, 0, 0, 7, 4, 0),
val);
/* decode memory attribute */
NOS = (*val >> 10) & 1; /* Not Outer shareable */
NS = (*val >> 9) & 1; /* Non secure */
INNER = (*val >> 4) & 0x7;
OUTER = (*val >> 2) & 0x3;
if (retval != ERROR_OK)
goto done;
*val = (*val & ~0xfff) + (va & 0xfff);
if (*val == va)
LOG_WARNING("virt = phys : MMU disable !!");
if (meminfo) {
LOG_INFO("%x : %x %s outer shareable %s secured",
va, *val,
NOS == 1 ? "not" : " ",
NS == 1 ? "not" : "");
switch (OUTER) {
case 0:
LOG_INFO("outer: Non-Cacheable");
break;
case 1:
LOG_INFO("outer: Write-Back, Write-Allocate");
break;
case 2:
LOG_INFO("outer: Write-Through, No Write-Allocate");
break;
case 3:
LOG_INFO("outer: Write-Back, no Write-Allocate");
break;
}
switch (INNER) {
case 0:
LOG_INFO("inner: Non-Cacheable");
break;
case 1:
LOG_INFO("inner: Strongly-ordered");
break;
case 3:
LOG_INFO("inner: Device");
break;
case 5:
LOG_INFO("inner: Write-Back, Write-Allocate");
break;
case 6:
LOG_INFO("inner: Write-Through");
break;
case 7:
LOG_INFO("inner: Write-Back, no Write-Allocate");
default:
LOG_INFO("inner: %x ???", INNER);
}
}
done:
dpm->finish(dpm);
return retval;
}
static int armv7a_handle_inner_cache_info_command(struct command_context *cmd_ctx,
struct armv7a_cache_common *armv7a_cache)
{
if (armv7a_cache->ctype == -1) {
command_print(cmd_ctx, "cache not yet identified");
return ERROR_OK;
}
command_print(cmd_ctx,
"D-Cache: linelen %i, associativity %i, nsets %i, cachesize %d KBytes",
armv7a_cache->d_u_size.linelen,
armv7a_cache->d_u_size.associativity,
armv7a_cache->d_u_size.nsets,
armv7a_cache->d_u_size.cachesize);
command_print(cmd_ctx,
"I-Cache: linelen %i, associativity %i, nsets %i, cachesize %d KBytes",
armv7a_cache->i_size.linelen,
armv7a_cache->i_size.associativity,
armv7a_cache->i_size.nsets,
armv7a_cache->i_size.cachesize);
return ERROR_OK;
}
static int _armv7a_flush_all_data(struct target *target)
{
struct armv7a_common *armv7a = target_to_armv7a(target);
struct arm_dpm *dpm = armv7a->arm.dpm;
struct armv7a_cachesize *d_u_size =
&(armv7a->armv7a_mmu.armv7a_cache.d_u_size);
int32_t c_way, c_index = d_u_size->index;
int retval;
/* check that cache data is on at target halt */
if (!armv7a->armv7a_mmu.armv7a_cache.d_u_cache_enabled) {
LOG_INFO("flushed not performed :cache not on at target halt");
return ERROR_OK;
}
retval = dpm->prepare(dpm);
if (retval != ERROR_OK)
goto done;
do {
c_way = d_u_size->way;
do {
uint32_t value = (c_index << d_u_size->index_shift)
| (c_way << d_u_size->way_shift);
/* DCCISW */
/* LOG_INFO ("%d %d %x",c_way,c_index,value); */
retval = dpm->instr_write_data_r0(dpm,
ARMV4_5_MCR(15, 0, 0, 7, 14, 2),
value);
if (retval != ERROR_OK)
goto done;
c_way -= 1;
} while (c_way >= 0);
c_index -= 1;
} while (c_index >= 0);
return retval;
done:
LOG_ERROR("flushed failed");
dpm->finish(dpm);
return retval;
}
static int armv7a_flush_all_data(struct target *target)
{
int retval = ERROR_FAIL;
/* check that armv7a_cache is correctly identify */
struct armv7a_common *armv7a = target_to_armv7a(target);
if (armv7a->armv7a_mmu.armv7a_cache.ctype == -1) {
LOG_ERROR("trying to flush un-identified cache");
return retval;
}
if (target->smp) {
/* look if all the other target have been flushed in order to flush level
* 2 */
struct target_list *head;
struct target *curr;
head = target->head;
while (head != (struct target_list *)NULL) {
curr = head->target;
if (curr->state == TARGET_HALTED) {
LOG_INFO("Wait flushing data l1 on core %d", curr->coreid);
retval = _armv7a_flush_all_data(curr);
}
head = head->next;
}
} else
retval = _armv7a_flush_all_data(target);
return retval;
}
/* L2 is not specific to armv7a a specific file is needed */
static int armv7a_l2x_flush_all_data(struct target *target)
{
#define L2X0_CLEAN_INV_WAY 0x7FC
int retval = ERROR_FAIL;
struct armv7a_common *armv7a = target_to_armv7a(target);
struct armv7a_l2x_cache *l2x_cache = (struct armv7a_l2x_cache *)
(armv7a->armv7a_mmu.armv7a_cache.l2_cache);
uint32_t base = l2x_cache->base;
uint32_t l2_way = l2x_cache->way;
uint32_t l2_way_val = (1 << l2_way) - 1;
retval = armv7a_flush_all_data(target);
if (retval != ERROR_OK)
return retval;
retval = target->type->write_phys_memory(target,
(uint32_t)(base+(uint32_t)L2X0_CLEAN_INV_WAY),
(uint32_t)4,
(uint32_t)1,
(uint8_t *)&l2_way_val);
return retval;
}
static int armv7a_handle_l2x_cache_info_command(struct command_context *cmd_ctx,
struct armv7a_cache_common *armv7a_cache)
{
struct armv7a_l2x_cache *l2x_cache = (struct armv7a_l2x_cache *)
(armv7a_cache->l2_cache);
if (armv7a_cache->ctype == -1) {
command_print(cmd_ctx, "cache not yet identified");
return ERROR_OK;
}
command_print(cmd_ctx,
"L1 D-Cache: linelen %i, associativity %i, nsets %i, cachesize %d KBytes",
armv7a_cache->d_u_size.linelen,
armv7a_cache->d_u_size.associativity,
armv7a_cache->d_u_size.nsets,
armv7a_cache->d_u_size.cachesize);
command_print(cmd_ctx,
"L1 I-Cache: linelen %i, associativity %i, nsets %i, cachesize %d KBytes",
armv7a_cache->i_size.linelen,
armv7a_cache->i_size.associativity,
armv7a_cache->i_size.nsets,
armv7a_cache->i_size.cachesize);
command_print(cmd_ctx, "L2 unified cache Base Address 0x%x, %d ways",
l2x_cache->base, l2x_cache->way);
return ERROR_OK;
}
static int armv7a_l2x_cache_init(struct target *target, uint32_t base, uint32_t way)
{
struct armv7a_l2x_cache *l2x_cache;
struct target_list *head = target->head;
struct target *curr;
struct armv7a_common *armv7a = target_to_armv7a(target);
l2x_cache = calloc(1, sizeof(struct armv7a_l2x_cache));
l2x_cache->base = base;
l2x_cache->way = way;
/*LOG_INFO("cache l2 initialized base %x way %d",
l2x_cache->base,l2x_cache->way);*/
if (armv7a->armv7a_mmu.armv7a_cache.l2_cache)
LOG_INFO("cache l2 already initialized\n");
armv7a->armv7a_mmu.armv7a_cache.l2_cache = (void *) l2x_cache;
/* initialize l1 / l2x cache function */
armv7a->armv7a_mmu.armv7a_cache.flush_all_data_cache
= armv7a_l2x_flush_all_data;
armv7a->armv7a_mmu.armv7a_cache.display_cache_info =
armv7a_handle_l2x_cache_info_command;
/* initialize all target in this cluster (smp target)
* l2 cache must be configured after smp declaration */
while (head != (struct target_list *)NULL) {
curr = head->target;
if (curr != target) {
armv7a = target_to_armv7a(curr);
if (armv7a->armv7a_mmu.armv7a_cache.l2_cache)
LOG_ERROR("smp target : cache l2 already initialized\n");
armv7a->armv7a_mmu.armv7a_cache.l2_cache = (void *) l2x_cache;
armv7a->armv7a_mmu.armv7a_cache.flush_all_data_cache =
armv7a_l2x_flush_all_data;
armv7a->armv7a_mmu.armv7a_cache.display_cache_info =
armv7a_handle_l2x_cache_info_command;
}
head = head->next;
}
return JIM_OK;
}
COMMAND_HANDLER(handle_cache_l2x)
{
struct target *target = get_current_target(CMD_CTX);
uint32_t base, way;
switch (CMD_ARGC) {
case 0:
return ERROR_COMMAND_SYNTAX_ERROR;
break;
case 2:
/* command_print(CMD_CTX, "%s %s", CMD_ARGV[0], CMD_ARGV[1]); */
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], base);
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], way);
/* AP address is in bits 31:24 of DP_SELECT */
armv7a_l2x_cache_init(target, base, way);
break;
default:
return ERROR_COMMAND_SYNTAX_ERROR;
}
return ERROR_OK;
}
int armv7a_handle_cache_info_command(struct command_context *cmd_ctx,
struct armv7a_cache_common *armv7a_cache)
{
if (armv7a_cache->ctype == -1) {
command_print(cmd_ctx, "cache not yet identified");
return ERROR_OK;
}
if (armv7a_cache->display_cache_info)
armv7a_cache->display_cache_info(cmd_ctx, armv7a_cache);
return ERROR_OK;
}
/* retrieve core id cluster id */
static int armv7a_read_mpidr(struct target *target)
{
int retval = ERROR_FAIL;
struct armv7a_common *armv7a = target_to_armv7a(target);
struct arm_dpm *dpm = armv7a->arm.dpm;
uint32_t mpidr;
retval = dpm->prepare(dpm);
if (retval != ERROR_OK)
goto done;
/* MRC p15,0,<Rd>,c0,c0,5; read Multiprocessor ID register*/
retval = dpm->instr_read_data_r0(dpm,
ARMV4_5_MRC(15, 0, 0, 0, 0, 5),
&mpidr);
if (retval != ERROR_OK)
goto done;
if (mpidr & 1<<31) {
armv7a->multi_processor_system = (mpidr >> 30) & 1;
armv7a->cluster_id = (mpidr >> 8) & 0xf;
armv7a->cpu_id = mpidr & 0x3;
LOG_INFO("%s cluster %x core %x %s", target_name(target),
armv7a->cluster_id,
armv7a->cpu_id,
armv7a->multi_processor_system == 0 ? "multi core" : "mono core");
} else
LOG_ERROR("mpdir not in multiprocessor format");
done:
dpm->finish(dpm);
return retval;
}
int armv7a_identify_cache(struct target *target)
{
/* read cache descriptor */
int retval = ERROR_FAIL;
struct armv7a_common *armv7a = target_to_armv7a(target);
struct arm_dpm *dpm = armv7a->arm.dpm;
uint32_t cache_selected, clidr;
uint32_t cache_i_reg, cache_d_reg;
struct armv7a_cache_common *cache = &(armv7a->armv7a_mmu.armv7a_cache);
if (!armv7a->is_armv7r)
armv7a_read_ttbcr(target);
retval = dpm->prepare(dpm);
if (retval != ERROR_OK)
goto done;
/* retrieve CLIDR
* mrc p15, 1, r0, c0, c0, 1 @ read clidr */
retval = dpm->instr_read_data_r0(dpm,
ARMV4_5_MRC(15, 1, 0, 0, 0, 1),
&clidr);
if (retval != ERROR_OK)
goto done;
clidr = (clidr & 0x7000000) >> 23;
LOG_INFO("number of cache level %d", clidr / 2);
if ((clidr / 2) > 1) {
/* FIXME not supported present in cortex A8 and later */
/* in cortex A7, A15 */
LOG_ERROR("cache l2 present :not supported");
}
/* retrieve selected cache
* MRC p15, 2,<Rd>, c0, c0, 0; Read CSSELR */
retval = dpm->instr_read_data_r0(dpm,
ARMV4_5_MRC(15, 2, 0, 0, 0, 0),
&cache_selected);
if (retval != ERROR_OK)
goto done;
retval = armv7a->arm.mrc(target, 15,
2, 0, /* op1, op2 */
0, 0, /* CRn, CRm */
&cache_selected);
if (retval != ERROR_OK)
goto done;
/* select instruction cache
* MCR p15, 2,<Rd>, c0, c0, 0; Write CSSELR
* [0] : 1 instruction cache selection , 0 data cache selection */
retval = dpm->instr_write_data_r0(dpm,
ARMV4_5_MRC(15, 2, 0, 0, 0, 0),
1);
if (retval != ERROR_OK)
goto done;
/* read CCSIDR
* MRC P15,1,<RT>,C0, C0,0 ;on cortex A9 read CCSIDR
* [2:0] line size 001 eight word per line
* [27:13] NumSet 0x7f 16KB, 0xff 32Kbytes, 0x1ff 64Kbytes */
retval = dpm->instr_read_data_r0(dpm,
ARMV4_5_MRC(15, 1, 0, 0, 0, 0),
&cache_i_reg);
if (retval != ERROR_OK)
goto done;
/* select data cache*/
retval = dpm->instr_write_data_r0(dpm,
ARMV4_5_MRC(15, 2, 0, 0, 0, 0),
0);
if (retval != ERROR_OK)
goto done;
retval = dpm->instr_read_data_r0(dpm,
ARMV4_5_MRC(15, 1, 0, 0, 0, 0),
&cache_d_reg);
if (retval != ERROR_OK)
goto done;
/* restore selected cache */
dpm->instr_write_data_r0(dpm,
ARMV4_5_MRC(15, 2, 0, 0, 0, 0),
cache_selected);
if (retval != ERROR_OK)
goto done;
dpm->finish(dpm);
/* put fake type */
cache->d_u_size.linelen = 16 << (cache_d_reg & 0x7);
cache->d_u_size.cachesize = (((cache_d_reg >> 13) & 0x7fff)+1)/8;
cache->d_u_size.nsets = (cache_d_reg >> 13) & 0x7fff;
cache->d_u_size.associativity = ((cache_d_reg >> 3) & 0x3ff) + 1;
/* compute info for set way operation on cache */
cache->d_u_size.index_shift = (cache_d_reg & 0x7) + 4;
cache->d_u_size.index = (cache_d_reg >> 13) & 0x7fff;
cache->d_u_size.way = ((cache_d_reg >> 3) & 0x3ff);
cache->d_u_size.way_shift = cache->d_u_size.way + 1;
{
int i = 0;
while (((cache->d_u_size.way_shift >> i) & 1) != 1)
i++;
cache->d_u_size.way_shift = 32-i;
}
#if 0
LOG_INFO("data cache index %d << %d, way %d << %d",
cache->d_u_size.index, cache->d_u_size.index_shift,
cache->d_u_size.way,
cache->d_u_size.way_shift);
LOG_INFO("data cache %d bytes %d KBytes asso %d ways",
cache->d_u_size.linelen,
cache->d_u_size.cachesize,
cache->d_u_size.associativity);
#endif
cache->i_size.linelen = 16 << (cache_i_reg & 0x7);
cache->i_size.associativity = ((cache_i_reg >> 3) & 0x3ff) + 1;
cache->i_size.nsets = (cache_i_reg >> 13) & 0x7fff;
cache->i_size.cachesize = (((cache_i_reg >> 13) & 0x7fff)+1)/8;
/* compute info for set way operation on cache */
cache->i_size.index_shift = (cache_i_reg & 0x7) + 4;
cache->i_size.index = (cache_i_reg >> 13) & 0x7fff;
cache->i_size.way = ((cache_i_reg >> 3) & 0x3ff);
cache->i_size.way_shift = cache->i_size.way + 1;
{
int i = 0;
while (((cache->i_size.way_shift >> i) & 1) != 1)
i++;
cache->i_size.way_shift = 32-i;
}
#if 0
LOG_INFO("instruction cache index %d << %d, way %d << %d",
cache->i_size.index, cache->i_size.index_shift,
cache->i_size.way, cache->i_size.way_shift);
LOG_INFO("instruction cache %d bytes %d KBytes asso %d ways",
cache->i_size.linelen,
cache->i_size.cachesize,
cache->i_size.associativity);
#endif
/* if no l2 cache initialize l1 data cache flush function function */
if (armv7a->armv7a_mmu.armv7a_cache.flush_all_data_cache == NULL) {
armv7a->armv7a_mmu.armv7a_cache.display_cache_info =
armv7a_handle_inner_cache_info_command;
armv7a->armv7a_mmu.armv7a_cache.flush_all_data_cache =
armv7a_flush_all_data;
}
armv7a->armv7a_mmu.armv7a_cache.ctype = 0;
done:
dpm->finish(dpm);
armv7a_read_mpidr(target);
return retval;
}
int armv7a_init_arch_info(struct target *target, struct armv7a_common *armv7a)
{
struct arm *arm = &armv7a->arm;
arm->arch_info = armv7a;
target->arch_info = &armv7a->arm;
/* target is useful in all function arm v4 5 compatible */
armv7a->arm.target = target;
armv7a->arm.common_magic = ARM_COMMON_MAGIC;
armv7a->common_magic = ARMV7_COMMON_MAGIC;
armv7a->armv7a_mmu.armv7a_cache.l2_cache = NULL;
armv7a->armv7a_mmu.armv7a_cache.ctype = -1;
armv7a->armv7a_mmu.armv7a_cache.flush_all_data_cache = NULL;
armv7a->armv7a_mmu.armv7a_cache.display_cache_info = NULL;
return ERROR_OK;
}
int armv7a_arch_state(struct target *target)
{
static const char *state[] = {
"disabled", "enabled"
};
struct armv7a_common *armv7a = target_to_armv7a(target);
struct arm *arm = &armv7a->arm;
if (armv7a->common_magic != ARMV7_COMMON_MAGIC) {
LOG_ERROR("BUG: called for a non-ARMv7A target");
return ERROR_COMMAND_SYNTAX_ERROR;
}
arm_arch_state(target);
if (armv7a->is_armv7r) {
LOG_USER("D-Cache: %s, I-Cache: %s",
state[armv7a->armv7a_mmu.armv7a_cache.d_u_cache_enabled],
state[armv7a->armv7a_mmu.armv7a_cache.i_cache_enabled]);
} else {
LOG_USER("MMU: %s, D-Cache: %s, I-Cache: %s",
state[armv7a->armv7a_mmu.mmu_enabled],
state[armv7a->armv7a_mmu.armv7a_cache.d_u_cache_enabled],
state[armv7a->armv7a_mmu.armv7a_cache.i_cache_enabled]);
}
if (arm->core_mode == ARM_MODE_ABT)
armv7a_show_fault_registers(target);
if (target->debug_reason == DBG_REASON_WATCHPOINT)
LOG_USER("Watchpoint triggered at PC %#08x",
(unsigned) armv7a->dpm.wp_pc);
return ERROR_OK;
}
static const struct command_registration l2_cache_commands[] = {
{
.name = "l2x",
.handler = handle_cache_l2x,
.mode = COMMAND_EXEC,
.help = "configure l2x cache "
"",
.usage = "[base_addr] [number_of_way]",
},
COMMAND_REGISTRATION_DONE
};
const struct command_registration l2x_cache_command_handlers[] = {
{
.name = "cache_config",
.mode = COMMAND_EXEC,
.help = "cache configuation for a target",
.usage = "",
.chain = l2_cache_commands,
},
COMMAND_REGISTRATION_DONE
};
const struct command_registration armv7a_command_handlers[] = {
{
.chain = dap_command_handlers,
},
{
.chain = l2x_cache_command_handlers,
},
COMMAND_REGISTRATION_DONE
};

View File

@ -0,0 +1,173 @@
/***************************************************************************
* Copyright (C) 2009 by David Brownell *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef ARMV7A_H
#define ARMV7A_H
#include "arm_adi_v5.h"
#include "arm.h"
#include "armv4_5_mmu.h"
#include "armv4_5_cache.h"
#include "arm_dpm.h"
enum {
ARM_PC = 15,
ARM_CPSR = 16
};
#define ARMV7_COMMON_MAGIC 0x0A450999
/* VA to PA translation operations opc2 values*/
#define V2PCWPR 0
#define V2PCWPW 1
#define V2PCWUR 2
#define V2PCWUW 3
#define V2POWPR 4
#define V2POWPW 5
#define V2POWUR 6
#define V2POWUW 7
/* L210/L220 cache controller support */
struct armv7a_l2x_cache {
uint32_t base;
uint32_t way;
};
struct armv7a_cachesize {
uint32_t level_num;
/* cache dimensionning */
uint32_t linelen;
uint32_t associativity;
uint32_t nsets;
uint32_t cachesize;
/* info for set way operation on cache */
uint32_t index;
uint32_t index_shift;
uint32_t way;
uint32_t way_shift;
};
struct armv7a_cache_common {
int ctype;
struct armv7a_cachesize d_u_size; /* data cache */
struct armv7a_cachesize i_size; /* instruction cache */
int i_cache_enabled;
int d_u_cache_enabled;
/* l2 external unified cache if some */
void *l2_cache;
int (*flush_all_data_cache)(struct target *target);
int (*display_cache_info)(struct command_context *cmd_ctx,
struct armv7a_cache_common *armv7a_cache);
};
struct armv7a_mmu_common {
/* following field mmu working way */
int32_t ttbr1_used; /* -1 not initialized, 0 no ttbr1 1 ttbr1 used and */
uint32_t ttbr0_mask;/* masked to be used */
uint32_t os_border;
int (*read_physical_memory)(struct target *target, uint32_t address, uint32_t size,
uint32_t count, uint8_t *buffer);
struct armv7a_cache_common armv7a_cache;
uint32_t mmu_enabled;
};
struct armv7a_common {
struct arm arm;
int common_magic;
struct reg_cache *core_cache;
struct adiv5_dap dap;
/* Core Debug Unit */
struct arm_dpm dpm;
uint32_t debug_base;
uint8_t debug_ap;
uint8_t memory_ap;
bool memory_ap_available;
/* mdir */
uint8_t multi_processor_system;
uint8_t cluster_id;
uint8_t cpu_id;
bool is_armv7r;
/* cache specific to V7 Memory Management Unit compatible with v4_5*/
struct armv7a_mmu_common armv7a_mmu;
int (*examine_debug_reason)(struct target *target);
int (*post_debug_entry)(struct target *target);
void (*pre_restore_context)(struct target *target);
};
static inline struct armv7a_common *
target_to_armv7a(struct target *target)
{
return container_of(target->arch_info, struct armv7a_common, arm);
}
/* register offsets from armv7a.debug_base */
/* See ARMv7a arch spec section C10.2 */
#define CPUDBG_DIDR 0x000
/* See ARMv7a arch spec section C10.3 */
#define CPUDBG_WFAR 0x018
/* PCSR at 0x084 -or- 0x0a0 -or- both ... based on flags in DIDR */
#define CPUDBG_DSCR 0x088
#define CPUDBG_DRCR 0x090
#define CPUDBG_PRCR 0x310
#define CPUDBG_PRSR 0x314
/* See ARMv7a arch spec section C10.4 */
#define CPUDBG_DTRRX 0x080
#define CPUDBG_ITR 0x084
#define CPUDBG_DTRTX 0x08c
/* See ARMv7a arch spec section C10.5 */
#define CPUDBG_BVR_BASE 0x100
#define CPUDBG_BCR_BASE 0x140
#define CPUDBG_WVR_BASE 0x180
#define CPUDBG_WCR_BASE 0x1C0
#define CPUDBG_VCR 0x01C
/* See ARMv7a arch spec section C10.6 */
#define CPUDBG_OSLAR 0x300
#define CPUDBG_OSLSR 0x304
#define CPUDBG_OSSRR 0x308
#define CPUDBG_ECR 0x024
/* See ARMv7a arch spec section C10.7 */
#define CPUDBG_DSCCR 0x028
/* See ARMv7a arch spec section C10.8 */
#define CPUDBG_AUTHSTATUS 0xFB8
int armv7a_arch_state(struct target *target);
int armv7a_identify_cache(struct target *target);
int armv7a_init_arch_info(struct target *target, struct armv7a_common *armv7a);
int armv7a_mmu_translate_va_pa(struct target *target, uint32_t va,
uint32_t *val, int meminfo);
int armv7a_mmu_translate_va(struct target *target, uint32_t va, uint32_t *val);
int armv7a_handle_cache_info_command(struct command_context *cmd_ctx,
struct armv7a_cache_common *armv7a_cache);
extern const struct command_registration armv7a_command_handlers[];
#endif /* ARMV4_5_H */

View File

@ -0,0 +1,799 @@
/***************************************************************************
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* Copyright (C) 2006 by Magnus Lundin *
* lundin@mlu.mine.nu *
* *
* Copyright (C) 2008 by Spencer Oliver *
* spen@spen-soft.co.uk *
* *
* Copyright (C) 2007,2008 Øyvind Harboe *
* oyvind.harboe@zylin.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
* *
* ARMv7-M Architecture, Application Level Reference Manual *
* ARM DDI 0405C (September 2008) *
* *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "breakpoints.h"
#include "armv7m.h"
#include "algorithm.h"
#include "register.h"
#if 0
#define _DEBUG_INSTRUCTION_EXECUTION_
#endif
static char *armv7m_exception_strings[] = {
"", "Reset", "NMI", "HardFault",
"MemManage", "BusFault", "UsageFault", "RESERVED",
"RESERVED", "RESERVED", "RESERVED", "SVCall",
"DebugMonitor", "RESERVED", "PendSV", "SysTick"
};
/* PSP is used in some thread modes */
const int armv7m_psp_reg_map[17] = {
ARMV7M_R0, ARMV7M_R1, ARMV7M_R2, ARMV7M_R3,
ARMV7M_R4, ARMV7M_R5, ARMV7M_R6, ARMV7M_R7,
ARMV7M_R8, ARMV7M_R9, ARMV7M_R10, ARMV7M_R11,
ARMV7M_R12, ARMV7M_PSP, ARMV7M_R14, ARMV7M_PC,
ARMV7M_xPSR,
};
/* MSP is used in handler and some thread modes */
const int armv7m_msp_reg_map[17] = {
ARMV7M_R0, ARMV7M_R1, ARMV7M_R2, ARMV7M_R3,
ARMV7M_R4, ARMV7M_R5, ARMV7M_R6, ARMV7M_R7,
ARMV7M_R8, ARMV7M_R9, ARMV7M_R10, ARMV7M_R11,
ARMV7M_R12, ARMV7M_MSP, ARMV7M_R14, ARMV7M_PC,
ARMV7M_xPSR,
};
#ifdef ARMV7_GDB_HACKS
uint8_t armv7m_gdb_dummy_cpsr_value[] = {0, 0, 0, 0};
struct reg armv7m_gdb_dummy_cpsr_reg = {
.name = "GDB dummy cpsr register",
.value = armv7m_gdb_dummy_cpsr_value,
.dirty = 0,
.valid = 1,
.size = 32,
.arch_info = NULL,
};
#endif
/*
* These registers are not memory-mapped. The ARMv7-M profile includes
* memory mapped registers too, such as for the NVIC (interrupt controller)
* and SysTick (timer) modules; those can mostly be treated as peripherals.
*
* The ARMv6-M profile is almost identical in this respect, except that it
* doesn't include basepri or faultmask registers.
*/
static const struct {
unsigned id;
const char *name;
unsigned bits;
} armv7m_regs[] = {
{ ARMV7M_R0, "r0", 32 },
{ ARMV7M_R1, "r1", 32 },
{ ARMV7M_R2, "r2", 32 },
{ ARMV7M_R3, "r3", 32 },
{ ARMV7M_R4, "r4", 32 },
{ ARMV7M_R5, "r5", 32 },
{ ARMV7M_R6, "r6", 32 },
{ ARMV7M_R7, "r7", 32 },
{ ARMV7M_R8, "r8", 32 },
{ ARMV7M_R9, "r9", 32 },
{ ARMV7M_R10, "r10", 32 },
{ ARMV7M_R11, "r11", 32 },
{ ARMV7M_R12, "r12", 32 },
{ ARMV7M_R13, "sp", 32 },
{ ARMV7M_R14, "lr", 32 },
{ ARMV7M_PC, "pc", 32 },
{ ARMV7M_xPSR, "xPSR", 32 },
{ ARMV7M_MSP, "msp", 32 },
{ ARMV7M_PSP, "psp", 32 },
{ ARMV7M_PRIMASK, "primask", 1 },
{ ARMV7M_BASEPRI, "basepri", 8 },
{ ARMV7M_FAULTMASK, "faultmask", 1 },
{ ARMV7M_CONTROL, "control", 2 },
};
#define ARMV7M_NUM_REGS ARRAY_SIZE(armv7m_regs)
/**
* Restores target context using the cache of core registers set up
* by armv7m_build_reg_cache(), calling optional core-specific hooks.
*/
int armv7m_restore_context(struct target *target)
{
int i;
struct armv7m_common *armv7m = target_to_armv7m(target);
struct reg_cache *cache = armv7m->arm.core_cache;
LOG_DEBUG(" ");
if (armv7m->pre_restore_context)
armv7m->pre_restore_context(target);
for (i = ARMV7M_NUM_REGS - 1; i >= 0; i--) {
if (cache->reg_list[i].dirty) {
uint32_t value = buf_get_u32(cache->reg_list[i].value, 0, 32);
armv7m->arm.write_core_reg(target, &cache->reg_list[i], i, ARM_MODE_ANY, value);
}
}
return ERROR_OK;
}
/* Core state functions */
/**
* Maps ISR number (from xPSR) to name.
* Note that while names and meanings for the first sixteen are standardized
* (with zero not a true exception), external interrupts are only numbered.
* They are assigned by vendors, which generally assign different numbers to
* peripherals (such as UART0 or a USB peripheral controller).
*/
char *armv7m_exception_string(int number)
{
static char enamebuf[32];
if ((number < 0) | (number > 511))
return "Invalid exception";
if (number < 16)
return armv7m_exception_strings[number];
sprintf(enamebuf, "External Interrupt(%i)", number - 16);
return enamebuf;
}
static int armv7m_get_core_reg(struct reg *reg)
{
int retval;
struct arm_reg *armv7m_reg = reg->arch_info;
struct target *target = armv7m_reg->target;
struct arm *arm = target_to_arm(target);
if (target->state != TARGET_HALTED)
return ERROR_TARGET_NOT_HALTED;
retval = arm->read_core_reg(target, reg, armv7m_reg->num, arm->core_mode);
return retval;
}
static int armv7m_set_core_reg(struct reg *reg, uint8_t *buf)
{
struct arm_reg *armv7m_reg = reg->arch_info;
struct target *target = armv7m_reg->target;
uint32_t value = buf_get_u32(buf, 0, 32);
if (target->state != TARGET_HALTED)
return ERROR_TARGET_NOT_HALTED;
buf_set_u32(reg->value, 0, 32, value);
reg->dirty = 1;
reg->valid = 1;
return ERROR_OK;
}
static int armv7m_read_core_reg(struct target *target, struct reg *r,
int num, enum arm_mode mode)
{
uint32_t reg_value;
int retval;
struct arm_reg *armv7m_core_reg;
struct armv7m_common *armv7m = target_to_armv7m(target);
assert(num < (int)armv7m->arm.core_cache->num_regs);
armv7m_core_reg = armv7m->arm.core_cache->reg_list[num].arch_info;
retval = armv7m->load_core_reg_u32(target,
armv7m_core_reg->num, &reg_value);
buf_set_u32(armv7m->arm.core_cache->reg_list[num].value, 0, 32, reg_value);
armv7m->arm.core_cache->reg_list[num].valid = 1;
armv7m->arm.core_cache->reg_list[num].dirty = 0;
return retval;
}
static int armv7m_write_core_reg(struct target *target, struct reg *r,
int num, enum arm_mode mode, uint32_t value)
{
int retval;
uint32_t reg_value;
struct arm_reg *armv7m_core_reg;
struct armv7m_common *armv7m = target_to_armv7m(target);
assert(num < (int)armv7m->arm.core_cache->num_regs);
reg_value = buf_get_u32(armv7m->arm.core_cache->reg_list[num].value, 0, 32);
armv7m_core_reg = armv7m->arm.core_cache->reg_list[num].arch_info;
retval = armv7m->store_core_reg_u32(target,
armv7m_core_reg->num,
reg_value);
if (retval != ERROR_OK) {
LOG_ERROR("JTAG failure");
armv7m->arm.core_cache->reg_list[num].dirty = armv7m->arm.core_cache->reg_list[num].valid;
return ERROR_JTAG_DEVICE_ERROR;
}
LOG_DEBUG("write core reg %i value 0x%" PRIx32 "", num, reg_value);
armv7m->arm.core_cache->reg_list[num].valid = 1;
armv7m->arm.core_cache->reg_list[num].dirty = 0;
return ERROR_OK;
}
/**
* Returns generic ARM userspace registers to GDB.
* GDB doesn't quite understand that most ARMs don't have floating point
* hardware, so this also fakes a set of long-obsolete FPA registers that
* are not used in EABI based software stacks.
*/
int armv7m_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size)
{
struct armv7m_common *armv7m = target_to_armv7m(target);
int i;
*reg_list_size = 26;
*reg_list = malloc(sizeof(struct reg *) * (*reg_list_size));
/*
* GDB register packet format for ARM:
* - the first 16 registers are r0..r15
* - (obsolete) 8 FPA registers
* - (obsolete) FPA status
* - CPSR
*/
for (i = 0; i < 16; i++)
(*reg_list)[i] = &armv7m->arm.core_cache->reg_list[i];
for (i = 16; i < 24; i++)
(*reg_list)[i] = &arm_gdb_dummy_fp_reg;
(*reg_list)[24] = &arm_gdb_dummy_fps_reg;
#ifdef ARMV7_GDB_HACKS
/* use dummy cpsr reg otherwise gdb may try and set the thumb bit */
(*reg_list)[25] = &armv7m_gdb_dummy_cpsr_reg;
/* ARMV7M is always in thumb mode, try to make GDB understand this
* if it does not support this arch */
*((char *)armv7m->arm.pc->value) |= 1;
#else
(*reg_list)[25] = &armv7m->arm.core_cache->reg_list[ARMV7M_xPSR];
#endif
return ERROR_OK;
}
/** Runs a Thumb algorithm in the target. */
int armv7m_run_algorithm(struct target *target,
int num_mem_params, struct mem_param *mem_params,
int num_reg_params, struct reg_param *reg_params,
uint32_t entry_point, uint32_t exit_point,
int timeout_ms, void *arch_info)
{
int retval;
retval = armv7m_start_algorithm(target,
num_mem_params, mem_params,
num_reg_params, reg_params,
entry_point, exit_point,
arch_info);
if (retval == ERROR_OK)
retval = armv7m_wait_algorithm(target,
num_mem_params, mem_params,
num_reg_params, reg_params,
exit_point, timeout_ms,
arch_info);
return retval;
}
/** Starts a Thumb algorithm in the target. */
int armv7m_start_algorithm(struct target *target,
int num_mem_params, struct mem_param *mem_params,
int num_reg_params, struct reg_param *reg_params,
uint32_t entry_point, uint32_t exit_point,
void *arch_info)
{
struct armv7m_common *armv7m = target_to_armv7m(target);
struct armv7m_algorithm *armv7m_algorithm_info = arch_info;
enum arm_mode core_mode = armv7m->arm.core_mode;
int retval = ERROR_OK;
/* NOTE: armv7m_run_algorithm requires that each algorithm uses a software breakpoint
* at the exit point */
if (armv7m_algorithm_info->common_magic != ARMV7M_COMMON_MAGIC) {
LOG_ERROR("current target isn't an ARMV7M target");
return ERROR_TARGET_INVALID;
}
if (target->state != TARGET_HALTED) {
LOG_WARNING("target not halted");
return ERROR_TARGET_NOT_HALTED;
}
/* refresh core register cache
* Not needed if core register cache is always consistent with target process state */
for (unsigned i = 0; i < ARMV7M_NUM_REGS; i++) {
armv7m_algorithm_info->context[i] = buf_get_u32(
armv7m->arm.core_cache->reg_list[i].value,
0,
32);
}
for (int i = 0; i < num_mem_params; i++) {
/* TODO: Write only out params */
retval = target_write_buffer(target, mem_params[i].address,
mem_params[i].size,
mem_params[i].value);
if (retval != ERROR_OK)
return retval;
}
for (int i = 0; i < num_reg_params; i++) {
struct reg *reg =
register_get_by_name(armv7m->arm.core_cache, reg_params[i].reg_name, 0);
/* uint32_t regvalue; */
if (!reg) {
LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name);
return ERROR_COMMAND_SYNTAX_ERROR;
}
if (reg->size != reg_params[i].size) {
LOG_ERROR("BUG: register '%s' size doesn't match reg_params[i].size",
reg_params[i].reg_name);
return ERROR_COMMAND_SYNTAX_ERROR;
}
/* regvalue = buf_get_u32(reg_params[i].value, 0, 32); */
armv7m_set_core_reg(reg, reg_params[i].value);
}
if (armv7m_algorithm_info->core_mode != ARM_MODE_ANY &&
armv7m_algorithm_info->core_mode != core_mode) {
/* we cannot set ARM_MODE_HANDLER, so use ARM_MODE_THREAD instead */
if (armv7m_algorithm_info->core_mode == ARM_MODE_HANDLER) {
armv7m_algorithm_info->core_mode = ARM_MODE_THREAD;
LOG_INFO("ARM_MODE_HANDLER not currently supported, using ARM_MODE_THREAD instead");
}
LOG_DEBUG("setting core_mode: 0x%2.2x", armv7m_algorithm_info->core_mode);
buf_set_u32(armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].value,
0, 1, armv7m_algorithm_info->core_mode);
armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].dirty = 1;
armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].valid = 1;
}
/* save previous core mode */
armv7m_algorithm_info->core_mode = core_mode;
retval = target_resume(target, 0, entry_point, 1, 1);
return retval;
}
/** Waits for an algorithm in the target. */
int armv7m_wait_algorithm(struct target *target,
int num_mem_params, struct mem_param *mem_params,
int num_reg_params, struct reg_param *reg_params,
uint32_t exit_point, int timeout_ms,
void *arch_info)
{
struct armv7m_common *armv7m = target_to_armv7m(target);
struct armv7m_algorithm *armv7m_algorithm_info = arch_info;
int retval = ERROR_OK;
uint32_t pc;
/* NOTE: armv7m_run_algorithm requires that each algorithm uses a software breakpoint
* at the exit point */
if (armv7m_algorithm_info->common_magic != ARMV7M_COMMON_MAGIC) {
LOG_ERROR("current target isn't an ARMV7M target");
return ERROR_TARGET_INVALID;
}
retval = target_wait_state(target, TARGET_HALTED, timeout_ms);
/* If the target fails to halt due to the breakpoint, force a halt */
if (retval != ERROR_OK || target->state != TARGET_HALTED) {
retval = target_halt(target);
if (retval != ERROR_OK)
return retval;
retval = target_wait_state(target, TARGET_HALTED, 500);
if (retval != ERROR_OK)
return retval;
return ERROR_TARGET_TIMEOUT;
}
armv7m->load_core_reg_u32(target, 15, &pc);
if (exit_point && (pc != exit_point)) {
LOG_DEBUG("failed algorithm halted at 0x%" PRIx32 ", expected 0x%" PRIx32,
pc,
exit_point);
return ERROR_TARGET_TIMEOUT;
}
/* Read memory values to mem_params[] */
for (int i = 0; i < num_mem_params; i++) {
if (mem_params[i].direction != PARAM_OUT) {
retval = target_read_buffer(target, mem_params[i].address,
mem_params[i].size,
mem_params[i].value);
if (retval != ERROR_OK)
return retval;
}
}
/* Copy core register values to reg_params[] */
for (int i = 0; i < num_reg_params; i++) {
if (reg_params[i].direction != PARAM_OUT) {
struct reg *reg = register_get_by_name(armv7m->arm.core_cache,
reg_params[i].reg_name,
0);
if (!reg) {
LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name);
return ERROR_COMMAND_SYNTAX_ERROR;
}
if (reg->size != reg_params[i].size) {
LOG_ERROR(
"BUG: register '%s' size doesn't match reg_params[i].size",
reg_params[i].reg_name);
return ERROR_COMMAND_SYNTAX_ERROR;
}
buf_set_u32(reg_params[i].value, 0, 32, buf_get_u32(reg->value, 0, 32));
}
}
for (int i = ARMV7M_NUM_REGS - 1; i >= 0; i--) {
uint32_t regvalue;
regvalue = buf_get_u32(armv7m->arm.core_cache->reg_list[i].value, 0, 32);
if (regvalue != armv7m_algorithm_info->context[i]) {
LOG_DEBUG("restoring register %s with value 0x%8.8" PRIx32,
armv7m->arm.core_cache->reg_list[i].name,
armv7m_algorithm_info->context[i]);
buf_set_u32(armv7m->arm.core_cache->reg_list[i].value,
0, 32, armv7m_algorithm_info->context[i]);
armv7m->arm.core_cache->reg_list[i].valid = 1;
armv7m->arm.core_cache->reg_list[i].dirty = 1;
}
}
/* restore previous core mode */
if (armv7m_algorithm_info->core_mode != armv7m->arm.core_mode) {
LOG_DEBUG("restoring core_mode: 0x%2.2x", armv7m_algorithm_info->core_mode);
buf_set_u32(armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].value,
0, 1, armv7m_algorithm_info->core_mode);
armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].dirty = 1;
armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].valid = 1;
}
armv7m->arm.core_mode = armv7m_algorithm_info->core_mode;
return retval;
}
/** Logs summary of ARMv7-M state for a halted target. */
int armv7m_arch_state(struct target *target)
{
struct armv7m_common *armv7m = target_to_armv7m(target);
struct arm *arm = &armv7m->arm;
uint32_t ctrl, sp;
ctrl = buf_get_u32(arm->core_cache->reg_list[ARMV7M_CONTROL].value, 0, 32);
sp = buf_get_u32(arm->core_cache->reg_list[ARMV7M_R13].value, 0, 32);
LOG_USER("target halted due to %s, current mode: %s %s\n"
"xPSR: %#8.8" PRIx32 " pc: %#8.8" PRIx32 " %csp: %#8.8" PRIx32 "%s",
debug_reason_name(target),
arm_mode_name(arm->core_mode),
armv7m_exception_string(armv7m->exception_number),
buf_get_u32(arm->cpsr->value, 0, 32),
buf_get_u32(arm->pc->value, 0, 32),
(ctrl & 0x02) ? 'p' : 'm',
sp,
arm->is_semihosting ? ", semihosting" : "");
return ERROR_OK;
}
static const struct reg_arch_type armv7m_reg_type = {
.get = armv7m_get_core_reg,
.set = armv7m_set_core_reg,
};
/** Builds cache of architecturally defined registers. */
struct reg_cache *armv7m_build_reg_cache(struct target *target)
{
struct armv7m_common *armv7m = target_to_armv7m(target);
struct arm *arm = &armv7m->arm;
int num_regs = ARMV7M_NUM_REGS;
struct reg_cache **cache_p = register_get_last_cache_p(&target->reg_cache);
struct reg_cache *cache = malloc(sizeof(struct reg_cache));
struct reg *reg_list = calloc(num_regs, sizeof(struct reg));
struct arm_reg *arch_info = calloc(num_regs, sizeof(struct arm_reg));
int i;
#ifdef ARMV7_GDB_HACKS
register_init_dummy(&armv7m_gdb_dummy_cpsr_reg);
#endif
/* Build the process context cache */
cache->name = "arm v7m registers";
cache->next = NULL;
cache->reg_list = reg_list;
cache->num_regs = num_regs;
(*cache_p) = cache;
for (i = 0; i < num_regs; i++) {
arch_info[i].num = armv7m_regs[i].id;
arch_info[i].target = target;
arch_info[i].arm = arm;
reg_list[i].name = armv7m_regs[i].name;
reg_list[i].size = armv7m_regs[i].bits;
reg_list[i].value = calloc(1, 4);
reg_list[i].dirty = 0;
reg_list[i].valid = 0;
reg_list[i].type = &armv7m_reg_type;
reg_list[i].arch_info = &arch_info[i];
}
arm->cpsr = reg_list + ARMV7M_xPSR;
arm->pc = reg_list + ARMV7M_PC;
arm->core_cache = cache;
return cache;
}
static int armv7m_setup_semihosting(struct target *target, int enable)
{
/* nothing todo for armv7m */
return ERROR_OK;
}
/** Sets up target as a generic ARMv7-M core */
int armv7m_init_arch_info(struct target *target, struct armv7m_common *armv7m)
{
struct arm *arm = &armv7m->arm;
armv7m->common_magic = ARMV7M_COMMON_MAGIC;
armv7m->fp_feature = FP_NONE;
arm->core_type = ARM_MODE_THREAD;
arm->arch_info = armv7m;
arm->setup_semihosting = armv7m_setup_semihosting;
arm->read_core_reg = armv7m_read_core_reg;
arm->write_core_reg = armv7m_write_core_reg;
return arm_init_arch_info(target, arm);
}
/** Generates a CRC32 checksum of a memory region. */
int armv7m_checksum_memory(struct target *target,
uint32_t address, uint32_t count, uint32_t *checksum)
{
struct working_area *crc_algorithm;
struct armv7m_algorithm armv7m_info;
struct reg_param reg_params[2];
int retval;
/* see contrib/loaders/checksum/armv7m_crc.s for src */
static const uint8_t cortex_m3_crc_code[] = {
/* main: */
0x02, 0x46, /* mov r2, r0 */
0x00, 0x20, /* movs r0, #0 */
0xC0, 0x43, /* mvns r0, r0 */
0x0A, 0x4E, /* ldr r6, CRC32XOR */
0x0B, 0x46, /* mov r3, r1 */
0x00, 0x24, /* movs r4, #0 */
0x0D, 0xE0, /* b ncomp */
/* nbyte: */
0x11, 0x5D, /* ldrb r1, [r2, r4] */
0x09, 0x06, /* lsls r1, r1, #24 */
0x48, 0x40, /* eors r0, r0, r1 */
0x00, 0x25, /* movs r5, #0 */
/* loop: */
0x00, 0x28, /* cmp r0, #0 */
0x02, 0xDA, /* bge notset */
0x40, 0x00, /* lsls r0, r0, #1 */
0x70, 0x40, /* eors r0, r0, r6 */
0x00, 0xE0, /* b cont */
/* notset: */
0x40, 0x00, /* lsls r0, r0, #1 */
/* cont: */
0x01, 0x35, /* adds r5, r5, #1 */
0x08, 0x2D, /* cmp r5, #8 */
0xF6, 0xD1, /* bne loop */
0x01, 0x34, /* adds r4, r4, #1 */
/* ncomp: */
0x9C, 0x42, /* cmp r4, r3 */
0xEF, 0xD1, /* bne nbyte */
0x00, 0xBE, /* bkpt #0 */
0xB7, 0x1D, 0xC1, 0x04 /* CRC32XOR: .word 0x04c11db7 */
};
retval = target_alloc_working_area(target, sizeof(cortex_m3_crc_code), &crc_algorithm);
if (retval != ERROR_OK)
return retval;
retval = target_write_buffer(target, crc_algorithm->address,
sizeof(cortex_m3_crc_code), (uint8_t *)cortex_m3_crc_code);
if (retval != ERROR_OK)
goto cleanup;
armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
armv7m_info.core_mode = ARM_MODE_THREAD;
init_reg_param(&reg_params[0], "r0", 32, PARAM_IN_OUT);
init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
buf_set_u32(reg_params[0].value, 0, 32, address);
buf_set_u32(reg_params[1].value, 0, 32, count);
int timeout = 20000 * (1 + (count / (1024 * 1024)));
retval = target_run_algorithm(target, 0, NULL, 2, reg_params, crc_algorithm->address,
crc_algorithm->address + (sizeof(cortex_m3_crc_code) - 6),
timeout, &armv7m_info);
if (retval == ERROR_OK)
*checksum = buf_get_u32(reg_params[0].value, 0, 32);
else
LOG_ERROR("error executing cortex_m3 crc algorithm");
destroy_reg_param(&reg_params[0]);
destroy_reg_param(&reg_params[1]);
cleanup:
target_free_working_area(target, crc_algorithm);
return retval;
}
/** Checks whether a memory region is zeroed. */
int armv7m_blank_check_memory(struct target *target,
uint32_t address, uint32_t count, uint32_t *blank)
{
struct working_area *erase_check_algorithm;
struct reg_param reg_params[3];
struct armv7m_algorithm armv7m_info;
int retval;
/* see contrib/loaders/erase_check/armv7m_erase_check.s for src */
static const uint8_t erase_check_code[] = {
/* loop: */
0x03, 0x78, /* ldrb r3, [r0] */
0x01, 0x30, /* adds r0, #1 */
0x1A, 0x40, /* ands r2, r2, r3 */
0x01, 0x39, /* subs r1, r1, #1 */
0xFA, 0xD1, /* bne loop */
0x00, 0xBE /* bkpt #0 */
};
/* make sure we have a working area */
if (target_alloc_working_area(target, sizeof(erase_check_code),
&erase_check_algorithm) != ERROR_OK)
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
retval = target_write_buffer(target, erase_check_algorithm->address,
sizeof(erase_check_code), (uint8_t *)erase_check_code);
if (retval != ERROR_OK)
return retval;
armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
armv7m_info.core_mode = ARM_MODE_THREAD;
init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
buf_set_u32(reg_params[0].value, 0, 32, address);
init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
buf_set_u32(reg_params[1].value, 0, 32, count);
init_reg_param(&reg_params[2], "r2", 32, PARAM_IN_OUT);
buf_set_u32(reg_params[2].value, 0, 32, 0xff);
retval = target_run_algorithm(target,
0,
NULL,
3,
reg_params,
erase_check_algorithm->address,
erase_check_algorithm->address + (sizeof(erase_check_code) - 2),
10000,
&armv7m_info);
if (retval == ERROR_OK)
*blank = buf_get_u32(reg_params[2].value, 0, 32);
destroy_reg_param(&reg_params[0]);
destroy_reg_param(&reg_params[1]);
destroy_reg_param(&reg_params[2]);
target_free_working_area(target, erase_check_algorithm);
return retval;
}
int armv7m_maybe_skip_bkpt_inst(struct target *target, bool *inst_found)
{
struct armv7m_common *armv7m = target_to_armv7m(target);
struct reg *r = armv7m->arm.pc;
bool result = false;
/* if we halted last time due to a bkpt instruction
* then we have to manually step over it, otherwise
* the core will break again */
if (target->debug_reason == DBG_REASON_BREAKPOINT) {
uint16_t op;
uint32_t pc = buf_get_u32(r->value, 0, 32);
pc &= ~1;
if (target_read_u16(target, pc, &op) == ERROR_OK) {
if ((op & 0xFF00) == 0xBE00) {
pc = buf_get_u32(r->value, 0, 32) + 2;
buf_set_u32(r->value, 0, 32, pc);
r->dirty = true;
r->valid = true;
result = true;
LOG_DEBUG("Skipping over BKPT instruction");
}
}
}
if (inst_found)
*inst_found = result;
return ERROR_OK;
}
const struct command_registration armv7m_command_handlers[] = {
{
.chain = arm_command_handlers,
},
{
.chain = dap_command_handlers,
},
COMMAND_REGISTRATION_DONE
};

View File

@ -0,0 +1,233 @@
/***************************************************************************
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* Copyright (C) 2006 by Magnus Lundin *
* lundin@mlu.mine.nu *
* *
* Copyright (C) 2008 by Spencer Oliver *
* spen@spen-soft.co.uk *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef ARMV7M_COMMON_H
#define ARMV7M_COMMON_H
#include "arm_adi_v5.h"
#include "arm.h"
/* define for enabling armv7 gdb workarounds */
#if 1
#define ARMV7_GDB_HACKS
#endif
#ifdef ARMV7_GDB_HACKS
extern uint8_t armv7m_gdb_dummy_cpsr_value[];
extern struct reg armv7m_gdb_dummy_cpsr_reg;
#endif
extern const int armv7m_psp_reg_map[];
extern const int armv7m_msp_reg_map[];
char *armv7m_exception_string(int number);
/* offsets into armv7m core register cache */
enum {
/* for convenience, the first set of indices match
* the Cortex-M3/-M4 DCRSR selectors
*/
ARMV7M_R0,
ARMV7M_R1,
ARMV7M_R2,
ARMV7M_R3,
ARMV7M_R4,
ARMV7M_R5,
ARMV7M_R6,
ARMV7M_R7,
ARMV7M_R8,
ARMV7M_R9,
ARMV7M_R10,
ARMV7M_R11,
ARMV7M_R12,
ARMV7M_R13,
ARMV7M_R14,
ARMV7M_PC = 15,
ARMV7M_xPSR = 16,
ARMV7M_MSP,
ARMV7M_PSP,
/* this next set of indices is arbitrary */
ARMV7M_PRIMASK,
ARMV7M_BASEPRI,
ARMV7M_FAULTMASK,
ARMV7M_CONTROL,
/* 32bit Floating-point registers */
ARMV7M_S0,
ARMV7M_S1,
ARMV7M_S2,
ARMV7M_S3,
ARMV7M_S4,
ARMV7M_S5,
ARMV7M_S6,
ARMV7M_S7,
ARMV7M_S8,
ARMV7M_S9,
ARMV7M_S10,
ARMV7M_S11,
ARMV7M_S12,
ARMV7M_S13,
ARMV7M_S14,
ARMV7M_S15,
ARMV7M_S16,
ARMV7M_S17,
ARMV7M_S18,
ARMV7M_S19,
ARMV7M_S20,
ARMV7M_S21,
ARMV7M_S22,
ARMV7M_S23,
ARMV7M_S24,
ARMV7M_S25,
ARMV7M_S26,
ARMV7M_S27,
ARMV7M_S28,
ARMV7M_S29,
ARMV7M_S30,
ARMV7M_S31,
/* 64bit Floating-point registers */
ARMV7M_D0,
ARMV7M_D1,
ARMV7M_D2,
ARMV7M_D3,
ARMV7M_D4,
ARMV7M_D5,
ARMV7M_D6,
ARMV7M_D7,
ARMV7M_D8,
ARMV7M_D9,
ARMV7M_D10,
ARMV7M_D11,
ARMV7M_D12,
ARMV7M_D13,
ARMV7M_D14,
ARMV7M_D15,
/* Floating-point status registers */
ARMV7M_FPSID,
ARMV7M_FPSCR,
ARMV7M_FPEXC,
ARMV7M_LAST_REG,
};
enum {
FP_NONE = 0,
FPv4_SP,
};
#define ARMV7M_COMMON_MAGIC 0x2A452A45
struct armv7m_common {
struct arm arm;
int common_magic;
int exception_number;
struct adiv5_dap dap;
int fp_feature;
uint32_t demcr;
/* stlink is a high level adapter, does not support all functions */
bool stlink;
/* Direct processor core register read and writes */
int (*load_core_reg_u32)(struct target *target, uint32_t num, uint32_t *value);
int (*store_core_reg_u32)(struct target *target, uint32_t num, uint32_t value);
int (*examine_debug_reason)(struct target *target);
int (*post_debug_entry)(struct target *target);
void (*pre_restore_context)(struct target *target);
};
static inline struct armv7m_common *
target_to_armv7m(struct target *target)
{
return container_of(target->arch_info, struct armv7m_common, arm);
}
static inline bool is_armv7m(struct armv7m_common *armv7m)
{
return armv7m->common_magic == ARMV7M_COMMON_MAGIC;
}
struct armv7m_algorithm {
int common_magic;
enum arm_mode core_mode;
uint32_t context[ARMV7M_LAST_REG]; /* ARMV7M_NUM_REGS */
};
struct reg_cache *armv7m_build_reg_cache(struct target *target);
enum armv7m_mode armv7m_number_to_mode(int number);
int armv7m_mode_to_number(enum armv7m_mode mode);
int armv7m_arch_state(struct target *target);
int armv7m_get_gdb_reg_list(struct target *target,
struct reg **reg_list[], int *reg_list_size);
int armv7m_init_arch_info(struct target *target, struct armv7m_common *armv7m);
int armv7m_run_algorithm(struct target *target,
int num_mem_params, struct mem_param *mem_params,
int num_reg_params, struct reg_param *reg_params,
uint32_t entry_point, uint32_t exit_point,
int timeout_ms, void *arch_info);
int armv7m_start_algorithm(struct target *target,
int num_mem_params, struct mem_param *mem_params,
int num_reg_params, struct reg_param *reg_params,
uint32_t entry_point, uint32_t exit_point,
void *arch_info);
int armv7m_wait_algorithm(struct target *target,
int num_mem_params, struct mem_param *mem_params,
int num_reg_params, struct reg_param *reg_params,
uint32_t exit_point, int timeout_ms,
void *arch_info);
int armv7m_invalidate_core_regs(struct target *target);
int armv7m_restore_context(struct target *target);
int armv7m_checksum_memory(struct target *target,
uint32_t address, uint32_t count, uint32_t *checksum);
int armv7m_blank_check_memory(struct target *target,
uint32_t address, uint32_t count, uint32_t *blank);
int armv7m_maybe_skip_bkpt_inst(struct target *target, bool *inst_found);
extern const struct command_registration armv7m_command_handlers[];
#endif /* ARMV7M_H */

View File

@ -0,0 +1,637 @@
/***************************************************************************
* Copyright (C) 2010 by Oleksandr Tymoshenko <gonzo@bluezbox.com> *
* Based on mips_m4k code: *
* Copyright (C) 2008 by Spencer Oliver <spen@spen-soft.co.uk> *
* Copyright (C) 2008 by David T.L. Wong *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "jtag/jtag.h"
#include "register.h"
#include "algorithm.h"
#include "target.h"
#include "breakpoints.h"
#include "target_type.h"
#include "avr32_jtag.h"
#include "avr32_mem.h"
#include "avr32_regs.h"
#include "avr32_ap7k.h"
static char *avr32_core_reg_list[] = {
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8",
"r9", "r10", "r11", "r12", "sp", "lr", "pc", "sr"
};
static struct avr32_core_reg
avr32_core_reg_list_arch_info[AVR32NUMCOREREGS] = {
{0, NULL, NULL},
{1, NULL, NULL},
{2, NULL, NULL},
{3, NULL, NULL},
{4, NULL, NULL},
{5, NULL, NULL},
{6, NULL, NULL},
{7, NULL, NULL},
{8, NULL, NULL},
{9, NULL, NULL},
{10, NULL, NULL},
{11, NULL, NULL},
{12, NULL, NULL},
{13, NULL, NULL},
{14, NULL, NULL},
{15, NULL, NULL},
{16, NULL, NULL},
};
static int avr32_read_core_reg(struct target *target, int num);
static int avr32_write_core_reg(struct target *target, int num);
int avr32_ap7k_save_context(struct target *target)
{
int retval, i;
struct avr32_ap7k_common *ap7k = target_to_ap7k(target);
retval = avr32_jtag_read_regs(&ap7k->jtag, ap7k->core_regs);
if (retval != ERROR_OK)
return retval;
for (i = 0; i < AVR32NUMCOREREGS; i++) {
if (!ap7k->core_cache->reg_list[i].valid)
avr32_read_core_reg(target, i);
}
return ERROR_OK;
}
int avr32_ap7k_restore_context(struct target *target)
{
int i;
/* get pointers to arch-specific information */
struct avr32_ap7k_common *ap7k = target_to_ap7k(target);
for (i = 0; i < AVR32NUMCOREREGS; i++) {
if (ap7k->core_cache->reg_list[i].dirty)
avr32_write_core_reg(target, i);
}
/* write core regs */
avr32_jtag_write_regs(&ap7k->jtag, ap7k->core_regs);
return ERROR_OK;
}
static int avr32_read_core_reg(struct target *target, int num)
{
uint32_t reg_value;
/* get pointers to arch-specific information */
struct avr32_ap7k_common *ap7k = target_to_ap7k(target);
if ((num < 0) || (num >= AVR32NUMCOREREGS))
return ERROR_COMMAND_SYNTAX_ERROR;
reg_value = ap7k->core_regs[num];
buf_set_u32(ap7k->core_cache->reg_list[num].value, 0, 32, reg_value);
ap7k->core_cache->reg_list[num].valid = 1;
ap7k->core_cache->reg_list[num].dirty = 0;
return ERROR_OK;
}
static int avr32_write_core_reg(struct target *target, int num)
{
uint32_t reg_value;
/* get pointers to arch-specific information */
struct avr32_ap7k_common *ap7k = target_to_ap7k(target);
if ((num < 0) || (num >= AVR32NUMCOREREGS))
return ERROR_COMMAND_SYNTAX_ERROR;
reg_value = buf_get_u32(ap7k->core_cache->reg_list[num].value, 0, 32);
ap7k->core_regs[num] = reg_value;
LOG_DEBUG("write core reg %i value 0x%" PRIx32 "", num, reg_value);
ap7k->core_cache->reg_list[num].valid = 1;
ap7k->core_cache->reg_list[num].dirty = 0;
return ERROR_OK;
}
static int avr32_get_core_reg(struct reg *reg)
{
int retval;
struct avr32_core_reg *avr32_reg = reg->arch_info;
struct target *target = avr32_reg->target;
if (target->state != TARGET_HALTED)
return ERROR_TARGET_NOT_HALTED;
retval = avr32_read_core_reg(target, avr32_reg->num);
return retval;
}
static int avr32_set_core_reg(struct reg *reg, uint8_t *buf)
{
struct avr32_core_reg *avr32_reg = reg->arch_info;
struct target *target = avr32_reg->target;
uint32_t value = buf_get_u32(buf, 0, 32);
if (target->state != TARGET_HALTED)
return ERROR_TARGET_NOT_HALTED;
buf_set_u32(reg->value, 0, 32, value);
reg->dirty = 1;
reg->valid = 1;
return ERROR_OK;
}
static const struct reg_arch_type avr32_reg_type = {
.get = avr32_get_core_reg,
.set = avr32_set_core_reg,
};
static struct reg_cache *avr32_build_reg_cache(struct target *target)
{
int num_regs = AVR32NUMCOREREGS;
struct avr32_ap7k_common *ap7k = target_to_ap7k(target);
struct reg_cache **cache_p = register_get_last_cache_p(&target->reg_cache);
struct reg_cache *cache = malloc(sizeof(struct reg_cache));
struct reg *reg_list = malloc(sizeof(struct reg) * num_regs);
struct avr32_core_reg *arch_info =
malloc(sizeof(struct avr32_core_reg) * num_regs);
int i;
/* Build the process context cache */
cache->name = "avr32 registers";
cache->next = NULL;
cache->reg_list = reg_list;
cache->num_regs = num_regs;
(*cache_p) = cache;
ap7k->core_cache = cache;
for (i = 0; i < num_regs; i++) {
arch_info[i] = avr32_core_reg_list_arch_info[i];
arch_info[i].target = target;
arch_info[i].avr32_common = ap7k;
reg_list[i].name = avr32_core_reg_list[i];
reg_list[i].size = 32;
reg_list[i].value = calloc(1, 4);
reg_list[i].dirty = 0;
reg_list[i].valid = 0;
reg_list[i].type = &avr32_reg_type;
reg_list[i].arch_info = &arch_info[i];
}
return cache;
}
static int avr32_ap7k_debug_entry(struct target *target)
{
uint32_t dpc, dinst;
int retval;
struct avr32_ap7k_common *ap7k = target_to_ap7k(target);
retval = avr32_jtag_nexus_read(&ap7k->jtag, AVR32_OCDREG_DPC, &dpc);
if (retval != ERROR_OK)
return retval;
retval = avr32_jtag_nexus_read(&ap7k->jtag, AVR32_OCDREG_DINST, &dinst);
if (retval != ERROR_OK)
return retval;
ap7k->jtag.dpc = dpc;
avr32_ap7k_save_context(target);
return ERROR_OK;
}
static int avr32_ap7k_poll(struct target *target)
{
uint32_t ds;
int retval;
struct avr32_ap7k_common *ap7k = target_to_ap7k(target);
retval = avr32_jtag_nexus_read(&ap7k->jtag, AVR32_OCDREG_DS, &ds);
if (retval != ERROR_OK)
return retval;
/* check for processor halted */
if (ds & OCDREG_DS_DBA) {
if ((target->state == TARGET_RUNNING) || (target->state == TARGET_RESET)) {
target->state = TARGET_HALTED;
retval = avr32_ap7k_debug_entry(target);
if (retval != ERROR_OK)
return retval;
target_call_event_callbacks(target, TARGET_EVENT_HALTED);
} else if (target->state == TARGET_DEBUG_RUNNING) {
target->state = TARGET_HALTED;
retval = avr32_ap7k_debug_entry(target);
if (retval != ERROR_OK)
return retval;
target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED);
}
} else
target->state = TARGET_RUNNING;
return ERROR_OK;
}
static int avr32_ap7k_halt(struct target *target)
{
struct avr32_ap7k_common *ap7k = target_to_ap7k(target);
LOG_DEBUG("target->state: %s",
target_state_name(target));
if (target->state == TARGET_HALTED) {
LOG_DEBUG("target was already halted");
return ERROR_OK;
}
if (target->state == TARGET_UNKNOWN)
LOG_WARNING("target was in unknown state when halt was requested");
if (target->state == TARGET_RESET) {
if ((jtag_get_reset_config() & RESET_SRST_PULLS_TRST) && jtag_get_srst()) {
LOG_ERROR("can't request a halt while in reset if nSRST pulls nTRST");
return ERROR_TARGET_FAILURE;
} else {
target->debug_reason = DBG_REASON_DBGRQ;
return ERROR_OK;
}
}
avr32_ocd_setbits(&ap7k->jtag, AVR32_OCDREG_DC, OCDREG_DC_DBR);
target->debug_reason = DBG_REASON_DBGRQ;
return ERROR_OK;
}
static int avr32_ap7k_assert_reset(struct target *target)
{
LOG_ERROR("%s: implement me", __func__);
return ERROR_OK;
}
static int avr32_ap7k_deassert_reset(struct target *target)
{
LOG_ERROR("%s: implement me", __func__);
return ERROR_OK;
}
static int avr32_ap7k_soft_reset_halt(struct target *target)
{
LOG_ERROR("%s: implement me", __func__);
return ERROR_OK;
}
static int avr32_ap7k_resume(struct target *target, int current,
uint32_t address, int handle_breakpoints, int debug_execution)
{
struct avr32_ap7k_common *ap7k = target_to_ap7k(target);
struct breakpoint *breakpoint = NULL;
uint32_t resume_pc;
int retval;
if (target->state != TARGET_HALTED) {
LOG_WARNING("target not halted");
return ERROR_TARGET_NOT_HALTED;
}
if (!debug_execution) {
target_free_all_working_areas(target);
/*
avr32_ap7k_enable_breakpoints(target);
avr32_ap7k_enable_watchpoints(target);
*/
}
/* current = 1: continue on current pc, otherwise continue at <address> */
if (!current) {
#if 0
if (retval != ERROR_OK)
return retval;
#endif
}
resume_pc = buf_get_u32(ap7k->core_cache->reg_list[AVR32_REG_PC].value, 0, 32);
avr32_ap7k_restore_context(target);
/* the front-end may request us not to handle breakpoints */
if (handle_breakpoints) {
/* Single step past breakpoint at current address */
breakpoint = breakpoint_find(target, resume_pc);
if (breakpoint) {
LOG_DEBUG("unset breakpoint at 0x%8.8" PRIx32 "", breakpoint->address);
#if 0
avr32_ap7k_unset_breakpoint(target, breakpoint);
avr32_ap7k_single_step_core(target);
avr32_ap7k_set_breakpoint(target, breakpoint);
#endif
}
}
#if 0
/* enable interrupts if we are running */
avr32_ap7k_enable_interrupts(target, !debug_execution);
/* exit debug mode */
mips_ejtag_exit_debug(ejtag_info);
#endif
retval = avr32_ocd_clearbits(&ap7k->jtag, AVR32_OCDREG_DC,
OCDREG_DC_DBR);
if (retval != ERROR_OK)
return retval;
retval = avr32_jtag_exec(&ap7k->jtag, RETD);
if (retval != ERROR_OK)
return retval;
target->debug_reason = DBG_REASON_NOTHALTED;
/* registers are now invalid */
register_cache_invalidate(ap7k->core_cache);
if (!debug_execution) {
target->state = TARGET_RUNNING;
target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
LOG_DEBUG("target resumed at 0x%" PRIx32 "", resume_pc);
} else {
target->state = TARGET_DEBUG_RUNNING;
target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED);
LOG_DEBUG("target debug resumed at 0x%" PRIx32 "", resume_pc);
}
return ERROR_OK;
}
static int avr32_ap7k_step(struct target *target, int current,
uint32_t address, int handle_breakpoints)
{
LOG_ERROR("%s: implement me", __func__);
return ERROR_OK;
}
static int avr32_ap7k_add_breakpoint(struct target *target, struct breakpoint *breakpoint)
{
LOG_ERROR("%s: implement me", __func__);
return ERROR_OK;
}
static int avr32_ap7k_remove_breakpoint(struct target *target,
struct breakpoint *breakpoint)
{
LOG_ERROR("%s: implement me", __func__);
return ERROR_OK;
}
static int avr32_ap7k_add_watchpoint(struct target *target, struct watchpoint *watchpoint)
{
LOG_ERROR("%s: implement me", __func__);
return ERROR_OK;
}
static int avr32_ap7k_remove_watchpoint(struct target *target,
struct watchpoint *watchpoint)
{
LOG_ERROR("%s: implement me", __func__);
return ERROR_OK;
}
static int avr32_ap7k_read_memory(struct target *target, uint32_t address,
uint32_t size, uint32_t count, uint8_t *buffer)
{
struct avr32_ap7k_common *ap7k = target_to_ap7k(target);
LOG_DEBUG("address: 0x%8.8" PRIx32 ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32 "",
address,
size,
count);
if (target->state != TARGET_HALTED) {
LOG_WARNING("target not halted");
return ERROR_TARGET_NOT_HALTED;
}
/* sanitize arguments */
if (((size != 4) && (size != 2) && (size != 1)) || (count == 0) || !(buffer))
return ERROR_COMMAND_SYNTAX_ERROR;
if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u)))
return ERROR_TARGET_UNALIGNED_ACCESS;
switch (size) {
case 4:
return avr32_jtag_read_memory32(&ap7k->jtag, address, count,
(uint32_t *)(void *)buffer);
break;
case 2:
return avr32_jtag_read_memory16(&ap7k->jtag, address, count,
(uint16_t *)(void *)buffer);
break;
case 1:
return avr32_jtag_read_memory8(&ap7k->jtag, address, count, buffer);
break;
default:
break;
}
return ERROR_OK;
}
static int avr32_ap7k_write_memory(struct target *target, uint32_t address,
uint32_t size, uint32_t count, const uint8_t *buffer)
{
struct avr32_ap7k_common *ap7k = target_to_ap7k(target);
LOG_DEBUG("address: 0x%8.8" PRIx32 ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32 "",
address,
size,
count);
if (target->state != TARGET_HALTED) {
LOG_WARNING("target not halted");
return ERROR_TARGET_NOT_HALTED;
}
/* sanitize arguments */
if (((size != 4) && (size != 2) && (size != 1)) || (count == 0) || !(buffer))
return ERROR_COMMAND_SYNTAX_ERROR;
if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u)))
return ERROR_TARGET_UNALIGNED_ACCESS;
switch (size) {
case 4:
return avr32_jtag_write_memory32(&ap7k->jtag, address, count,
(uint32_t *)(void *)buffer);
break;
case 2:
return avr32_jtag_write_memory16(&ap7k->jtag, address, count,
(uint16_t *)(void *)buffer);
break;
case 1:
return avr32_jtag_write_memory8(&ap7k->jtag, address, count, buffer);
break;
default:
break;
}
return ERROR_OK;
}
static int avr32_ap7k_init_target(struct command_context *cmd_ctx,
struct target *target)
{
struct avr32_ap7k_common *ap7k = target_to_ap7k(target);
ap7k->jtag.tap = target->tap;
avr32_build_reg_cache(target);
return ERROR_OK;
}
static int avr32_ap7k_target_create(struct target *target, Jim_Interp *interp)
{
struct avr32_ap7k_common *ap7k = calloc(1, sizeof(struct
avr32_ap7k_common));
ap7k->common_magic = AP7k_COMMON_MAGIC;
target->arch_info = ap7k;
return ERROR_OK;
}
static int avr32_ap7k_examine(struct target *target)
{
uint32_t devid, ds;
struct avr32_ap7k_common *ap7k = target_to_ap7k(target);
if (!target_was_examined(target)) {
target_set_examined(target);
avr32_jtag_nexus_read(&ap7k->jtag, AVR32_OCDREG_DID, &devid);
LOG_INFO("device id: %08x", devid);
avr32_ocd_setbits(&ap7k->jtag, AVR32_OCDREG_DC, OCDREG_DC_DBE);
avr32_jtag_nexus_read(&ap7k->jtag, AVR32_OCDREG_DS, &ds);
/* check for processor halted */
if (ds & OCDREG_DS_DBA) {
LOG_INFO("target is halted");
target->state = TARGET_HALTED;
} else
target->state = TARGET_RUNNING;
}
return ERROR_OK;
}
int avr32_ap7k_arch_state(struct target *target)
{
struct avr32_ap7k_common *ap7k = target_to_ap7k(target);
LOG_USER("target halted due to %s, pc: 0x%8.8" PRIx32 "",
debug_reason_name(target), ap7k->jtag.dpc);
return ERROR_OK;
}
int avr32_ap7k_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size)
{
#if 0
/* get pointers to arch-specific information */
int i;
/* include floating point registers */
*reg_list_size = AVR32NUMCOREREGS + AVR32NUMFPREGS;
*reg_list = malloc(sizeof(struct reg *) * (*reg_list_size));
for (i = 0; i < AVR32NUMCOREREGS; i++)
(*reg_list)[i] = &mips32->core_cache->reg_list[i];
/* add dummy floating points regs */
for (i = AVR32NUMCOREREGS; i < (AVR32NUMCOREREGS + AVR32NUMFPREGS); i++)
(*reg_list)[i] = &avr32_ap7k_gdb_dummy_fp_reg;
#endif
LOG_ERROR("%s: implement me", __func__);
return ERROR_FAIL;
}
struct target_type avr32_ap7k_target = {
.name = "avr32_ap7k",
.poll = avr32_ap7k_poll,
.arch_state = avr32_ap7k_arch_state,
.target_request_data = NULL,
.halt = avr32_ap7k_halt,
.resume = avr32_ap7k_resume,
.step = avr32_ap7k_step,
.assert_reset = avr32_ap7k_assert_reset,
.deassert_reset = avr32_ap7k_deassert_reset,
.soft_reset_halt = avr32_ap7k_soft_reset_halt,
.get_gdb_reg_list = avr32_ap7k_get_gdb_reg_list,
.read_memory = avr32_ap7k_read_memory,
.write_memory = avr32_ap7k_write_memory,
/* .checksum_memory = avr32_ap7k_checksum_memory, */
/* .blank_check_memory = avr32_ap7k_blank_check_memory, */
/* .run_algorithm = avr32_ap7k_run_algorithm, */
.add_breakpoint = avr32_ap7k_add_breakpoint,
.remove_breakpoint = avr32_ap7k_remove_breakpoint,
.add_watchpoint = avr32_ap7k_add_watchpoint,
.remove_watchpoint = avr32_ap7k_remove_watchpoint,
.target_create = avr32_ap7k_target_create,
.init_target = avr32_ap7k_init_target,
.examine = avr32_ap7k_examine,
};

View File

@ -0,0 +1,45 @@
/***************************************************************************
* Copyright (C) 2010 by Oleksandr Tymoshenko <gonzo@bluezbox.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 AVR32_AP7K
#define AVR32_AP7K
struct target;
#define AP7k_COMMON_MAGIC 0x4150374b
struct avr32_ap7k_common {
int common_magic;
struct avr32_jtag jtag;
struct reg_cache *core_cache;
uint32_t core_regs[AVR32NUMCOREREGS];
};
static inline struct avr32_ap7k_common *
target_to_ap7k(struct target *target)
{
return (struct avr32_ap7k_common *)target->arch_info;
}
struct avr32_core_reg {
uint32_t num;
struct target *target;
struct avr32_ap7k_common *avr32_common;
};
#endif /*AVR32_AP7K*/

View File

@ -0,0 +1,378 @@
/***************************************************************************
* Copyright (C) 2010 by Oleksandr Tymoshenko <gonzo@bluezbox.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 "target.h"
#include "jtag/jtag.h"
#include "avr32_jtag.h"
static int avr32_jtag_set_instr(struct avr32_jtag *jtag_info, int new_instr)
{
struct jtag_tap *tap;
int busy = 0;
tap = jtag_info->tap;
if (tap == NULL)
return ERROR_FAIL;
if (buf_get_u32(tap->cur_instr, 0, tap->ir_length) != (uint32_t)new_instr) {
do {
struct scan_field field;
uint8_t t[4];
uint8_t ret[4];
field.num_bits = tap->ir_length;
field.out_value = t;
buf_set_u32(t, 0, field.num_bits, new_instr);
field.in_value = ret;
jtag_add_ir_scan(tap, &field, TAP_IDLE);
if (jtag_execute_queue() != ERROR_OK) {
LOG_ERROR("%s: setting address failed", __func__);
return ERROR_FAIL;
}
busy = buf_get_u32(ret, 2, 1);
} while (busy); /* check for busy bit */
}
return ERROR_OK;
}
int avr32_jtag_nexus_set_address(struct avr32_jtag *jtag_info,
uint32_t addr, int mode)
{
struct scan_field fields[2];
uint8_t addr_buf[4];
uint8_t busy_buf[4];
int busy;
memset(fields, 0, sizeof(fields));
do {
memset(addr_buf, 0, sizeof(addr_buf));
memset(busy_buf, 0, sizeof(busy_buf));
buf_set_u32(addr_buf, 0, 1, mode);
buf_set_u32(addr_buf, 1, 7, addr);
fields[0].num_bits = 26;
fields[0].in_value = NULL;
fields[0].out_value = NULL;
fields[1].num_bits = 8;
fields[1].in_value = busy_buf;
fields[1].out_value = addr_buf;
jtag_add_dr_scan(jtag_info->tap, 2, fields, TAP_IDLE);
if (jtag_execute_queue() != ERROR_OK) {
LOG_ERROR("%s: setting address failed", __func__);
return ERROR_FAIL;
}
busy = buf_get_u32(busy_buf, 6, 1);
} while (busy);
return ERROR_OK;
}
int avr32_jtag_nexus_read_data(struct avr32_jtag *jtag_info,
uint32_t *pdata)
{
struct scan_field fields[2];
uint8_t data_buf[4];
uint8_t busy_buf[4];
int busy;
do {
memset(data_buf, 0, sizeof(data_buf));
memset(busy_buf, 0, sizeof(busy_buf));
fields[0].num_bits = 32;
fields[0].out_value = NULL;
fields[0].in_value = data_buf;
fields[1].num_bits = 2;
fields[1].in_value = busy_buf;
fields[1].out_value = NULL;
jtag_add_dr_scan(jtag_info->tap, 2, fields, TAP_IDLE);
if (jtag_execute_queue() != ERROR_OK) {
LOG_ERROR("%s: reading data failed", __func__);
return ERROR_FAIL;
}
busy = buf_get_u32(busy_buf, 0, 1);
} while (busy);
*pdata = buf_get_u32(data_buf, 0, 32);
return ERROR_OK;
}
int avr32_jtag_nexus_write_data(struct avr32_jtag *jtag_info,
uint32_t data)
{
struct scan_field fields[2];
uint8_t data_buf[4];
uint8_t busy_buf[4];
uint8_t dummy_buf[4];
int busy;
do {
memset(data_buf, 0, sizeof(data_buf));
memset(busy_buf, 0, sizeof(busy_buf));
memset(dummy_buf, 0, sizeof(dummy_buf));
fields[0].num_bits = 2;
fields[0].in_value = busy_buf;
fields[0].out_value = dummy_buf;
buf_set_u32(data_buf, 0, 32, data);
fields[1].num_bits = 32;
fields[1].in_value = NULL;
fields[1].out_value = data_buf;
jtag_add_dr_scan(jtag_info->tap, 2, fields, TAP_IDLE);
if (jtag_execute_queue() != ERROR_OK) {
LOG_ERROR("%s: reading data failed", __func__);
return ERROR_FAIL;
}
busy = buf_get_u32(busy_buf, 0, 0);
} while (busy);
return ERROR_OK;
}
int avr32_jtag_nexus_read(struct avr32_jtag *jtag_info,
uint32_t addr, uint32_t *value)
{
avr32_jtag_set_instr(jtag_info, AVR32_INST_NEXUS_ACCESS);
avr32_jtag_nexus_set_address(jtag_info, addr, MODE_READ);
avr32_jtag_nexus_read_data(jtag_info, value);
return ERROR_OK;
}
int avr32_jtag_nexus_write(struct avr32_jtag *jtag_info,
uint32_t addr, uint32_t value)
{
avr32_jtag_set_instr(jtag_info, AVR32_INST_NEXUS_ACCESS);
avr32_jtag_nexus_set_address(jtag_info, addr, MODE_WRITE);
avr32_jtag_nexus_write_data(jtag_info, value);
return ERROR_OK;
}
int avr32_jtag_mwa_set_address(struct avr32_jtag *jtag_info, int slave,
uint32_t addr, int mode)
{
struct scan_field fields[2];
uint8_t addr_buf[4];
uint8_t slave_buf[4];
uint8_t busy_buf[4];
int busy;
memset(fields, 0, sizeof(fields));
do {
memset(addr_buf, 0, sizeof(addr_buf));
memset(busy_buf, 0, sizeof(busy_buf));
memset(slave_buf, 0, sizeof(slave_buf));
buf_set_u32(slave_buf, 0, 4, slave);
buf_set_u32(addr_buf, 0, 1, mode);
buf_set_u32(addr_buf, 1, 30, addr >> 2);
fields[0].num_bits = 31;
fields[0].in_value = NULL;
fields[0].out_value = addr_buf;
fields[1].num_bits = 4;
fields[1].in_value = busy_buf;
fields[1].out_value = slave_buf;
jtag_add_dr_scan(jtag_info->tap, 2, fields, TAP_IDLE);
if (jtag_execute_queue() != ERROR_OK) {
LOG_ERROR("%s: setting address failed", __func__);
return ERROR_FAIL;
}
busy = buf_get_u32(busy_buf, 1, 1);
} while (busy);
return ERROR_OK;
}
int avr32_jtag_mwa_read_data(struct avr32_jtag *jtag_info,
uint32_t *pdata)
{
struct scan_field fields[2];
uint8_t data_buf[4];
uint8_t busy_buf[4];
int busy;
do {
memset(data_buf, 0, sizeof(data_buf));
memset(busy_buf, 0, sizeof(busy_buf));
fields[0].num_bits = 32;
fields[0].out_value = NULL;
fields[0].in_value = data_buf;
fields[1].num_bits = 3;
fields[1].in_value = busy_buf;
fields[1].out_value = NULL;
jtag_add_dr_scan(jtag_info->tap, 2, fields, TAP_IDLE);
if (jtag_execute_queue() != ERROR_OK) {
LOG_ERROR("%s: reading data failed", __func__);
return ERROR_FAIL;
}
busy = buf_get_u32(busy_buf, 0, 1);
} while (busy);
*pdata = buf_get_u32(data_buf, 0, 32);
return ERROR_OK;
}
int avr32_jtag_mwa_write_data(struct avr32_jtag *jtag_info,
uint32_t data)
{
struct scan_field fields[2];
uint8_t data_buf[4];
uint8_t busy_buf[4];
uint8_t zero_buf[4];
int busy;
do {
memset(data_buf, 0, sizeof(data_buf));
memset(busy_buf, 0, sizeof(busy_buf));
memset(zero_buf, 0, sizeof(zero_buf));
buf_set_u32(data_buf, 0, 32, data);
fields[0].num_bits = 3;
fields[0].in_value = busy_buf;
fields[0].out_value = zero_buf;
fields[1].num_bits = 32;
fields[1].out_value = data_buf;
fields[1].in_value = NULL;
jtag_add_dr_scan(jtag_info->tap, 2, fields, TAP_IDLE);
if (jtag_execute_queue() != ERROR_OK) {
LOG_ERROR("%s: reading data failed", __func__);
return ERROR_FAIL;
}
busy = buf_get_u32(busy_buf, 0, 1);
} while (busy);
return ERROR_OK;
}
int avr32_jtag_mwa_read(struct avr32_jtag *jtag_info, int slave,
uint32_t addr, uint32_t *value)
{
avr32_jtag_set_instr(jtag_info, AVR32_INST_MW_ACCESS);
avr32_jtag_mwa_set_address(jtag_info, slave, addr, MODE_READ);
avr32_jtag_mwa_read_data(jtag_info, value);
return ERROR_OK;
}
int avr32_jtag_mwa_write(struct avr32_jtag *jtag_info, int slave,
uint32_t addr, uint32_t value)
{
avr32_jtag_set_instr(jtag_info, AVR32_INST_MW_ACCESS);
avr32_jtag_mwa_set_address(jtag_info, slave, addr, MODE_WRITE);
avr32_jtag_mwa_write_data(jtag_info, value);
return ERROR_OK;
}
int avr32_jtag_exec(struct avr32_jtag *jtag_info, uint32_t inst)
{
int retval;
uint32_t ds;
retval = avr32_jtag_nexus_write(jtag_info, AVR32_OCDREG_DINST, inst);
if (retval != ERROR_OK)
return retval;
do {
retval = avr32_jtag_nexus_read(jtag_info, AVR32_OCDREG_DS, &ds);
if (retval != ERROR_OK)
return retval;
} while ((ds & OCDREG_DS_DBA) && !(ds & OCDREG_DS_INC));
return ERROR_OK;
}
int avr32_ocd_setbits(struct avr32_jtag *jtag, int reg, uint32_t bits)
{
uint32_t value;
int res;
res = avr32_jtag_nexus_read(jtag, reg, &value);
if (res)
return res;
value |= bits;
res = avr32_jtag_nexus_write(jtag, reg, value);
if (res)
return res;
return ERROR_OK;
}
int avr32_ocd_clearbits(struct avr32_jtag *jtag, int reg, uint32_t bits)
{
uint32_t value;
int res;
res = avr32_jtag_nexus_read(jtag, reg, &value);
if (res)
return res;
value &= ~bits;
res = avr32_jtag_nexus_write(jtag, reg, value);
if (res)
return res;
return ERROR_OK;
}

View File

@ -0,0 +1,105 @@
/***************************************************************************
* Copyright (C) 2010 by Oleksandr Tymoshenko <gonzo@bluezbox.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 AVR32_JTAG
#define AVR32_JTAG
#define AVR32NUMCOREREGS 17
/* tap instructions */
#define AVR32_INST_IDCODE 0x01
#define AVR32_INST_NEXUS_ACCESS 0x10
#define AVR32_INST_MW_ACCESS 0x11
#define AVR32_INST_MB_ACCESS 0x12
#define SLAVE_OCD 0x01
#define SLAVE_HSB_CACHED 0x04
#define SLAVE_HSB_UNCACHED 0x05
/*
* Registers
*/
#define AVR32_OCDREG_DID 0x00
#define AVR32_OCDREG_DC 0x02
#define OCDREG_DC_SS (1 << 8)
#define OCDREG_DC_DBR (1 << 12)
#define OCDREG_DC_DBE (1 << 13)
#define OCDREG_DC_SQA (1 << 22)
#define OCDREG_DC_RES (1 << 30)
#define OCDREG_DC_ABORT (1 << 31)
#define AVR32_OCDREG_DS 0x04
#define OCDREG_DS_SSS (1 << 0)
#define OCDREG_DS_SWB (1 << 1)
#define OCDREG_DS_HWB (1 << 2)
#define OCDREG_DS_STP (1 << 4)
#define OCDREG_DS_DBS (1 << 5)
#define OCDREG_DS_BP_SHIFT 8
#define OCDREG_DS_BP_MASK 0xff
#define OCDREG_DS_INC (1 << 24)
#define OCDREG_DS_BOZ (1 << 25)
#define OCDREG_DS_DBA (1 << 26)
#define OCDREG_DS_EXB (1 << 27)
#define OCDREG_DS_NTBF (1 << 28)
#define AVR32_OCDREG_DINST 0x41
#define AVR32_OCDREG_DPC 0x42
#define AVR32_OCDREG_DCCPU 0x44
#define AVR32_OCDREG_DCEMU 0x45
#define AVR32_OCDREG_DCSR 0x46
#define OCDREG_DCSR_CPUD (1 << 0)
#define OCDREG_DCSR_EMUD (1 << 1)
/*
* Direction bit
*/
#define MODE_WRITE 0x00
#define MODE_READ 0x01
/*
* Some instructions
*/
#define RETD 0xd703d623
#define MTDR(dreg, reg) (0xe7b00044 | ((reg) << 16) | dreg)
#define MFDR(reg, dreg) (0xe5b00044 | ((reg) << 16) | dreg)
#define MTSR(sysreg, reg) (0xe3b00002 | ((reg) << 16) | sysreg)
#define MFSR(reg, sysreg) (0xe1b00002 | ((reg) << 16) | sysreg)
struct avr32_jtag {
struct jtag_tap *tap;
uint32_t dpc; /* Debug PC value */
};
int avr32_jtag_nexus_read(struct avr32_jtag *jtag_info,
uint32_t addr, uint32_t *value);
int avr32_jtag_nexus_write(struct avr32_jtag *jtag_info,
uint32_t addr, uint32_t value);
int avr32_jtag_mwa_read(struct avr32_jtag *jtag_info, int slave,
uint32_t addr, uint32_t *value);
int avr32_jtag_mwa_write(struct avr32_jtag *jtag_info, int slave,
uint32_t addr, uint32_t value);
int avr32_ocd_setbits(struct avr32_jtag *jtag, int reg, uint32_t bits);
int avr32_ocd_clearbits(struct avr32_jtag *jtag, int reg, uint32_t bits);
int avr32_jtag_exec(struct avr32_jtag *jtag_info, uint32_t inst);
#endif /* AVR32_JTAG */

View File

@ -0,0 +1,319 @@
/***************************************************************************
* Copyright (C) 2010 by Oleksandr Tymoshenko <gonzo@bluezbox.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 "target.h"
#include "jtag/jtag.h"
#include "avr32_jtag.h"
#include "avr32_mem.h"
int avr32_jtag_read_memory32(struct avr32_jtag *jtag_info,
uint32_t addr, int count, uint32_t *buffer)
{
int i, retval;
uint32_t data;
for (i = 0; i < count; i++) {
retval = avr32_jtag_mwa_read(jtag_info, SLAVE_HSB_UNCACHED,
addr + i*4, &data);
if (retval != ERROR_OK)
return retval;
/* XXX: Assume AVR32 is BE */
buffer[i] = be_to_h_u32((uint8_t *)&data);
}
return ERROR_OK;
}
int avr32_jtag_read_memory16(struct avr32_jtag *jtag_info,
uint32_t addr, int count, uint16_t *buffer)
{
int i, retval;
uint32_t data;
i = 0;
/* any unaligned half-words? */
if (addr & 3) {
retval = avr32_jtag_mwa_read(jtag_info, SLAVE_HSB_UNCACHED,
addr + i*2, &data);
if (retval != ERROR_OK)
return retval;
/* XXX: Assume AVR32 is BE */
data = be_to_h_u32((uint8_t *)&data);
buffer[i] = (data >> 16) & 0xffff;
i++;
}
/* read all complete words */
for (; i < (count & ~1); i += 2) {
retval = avr32_jtag_mwa_read(jtag_info, SLAVE_HSB_UNCACHED,
addr + i*2, &data);
if (retval != ERROR_OK)
return retval;
/* XXX: Assume AVR32 is BE */
data = be_to_h_u32((uint8_t *)&data);
buffer[i] = data & 0xffff;
buffer[i+1] = (data >> 16) & 0xffff;
}
/* last halfword */
if (i < count) {
retval = avr32_jtag_mwa_read(jtag_info, SLAVE_HSB_UNCACHED,
addr + i*2, &data);
if (retval != ERROR_OK)
return retval;
/* XXX: Assume AVR32 is BE */
data = be_to_h_u32((uint8_t *)&data);
buffer[i] = data & 0xffff;
}
return ERROR_OK;
}
int avr32_jtag_read_memory8(struct avr32_jtag *jtag_info,
uint32_t addr, int count, uint8_t *buffer)
{
int i, j, retval;
uint8_t data[4];
i = 0;
/* Do we have non-aligned bytes? */
if (addr & 3) {
retval = avr32_jtag_mwa_read(jtag_info, SLAVE_HSB_UNCACHED,
addr + i, (uint32_t *)(void *)data);
if (retval != ERROR_OK)
return retval;
for (j = addr & 3; (j < 4) && (i < count); j++, i++)
buffer[i] = data[3-j];
}
/* read all complete words */
for (; i < (count & ~3); i += 4) {
retval = avr32_jtag_mwa_read(jtag_info, SLAVE_HSB_UNCACHED,
addr + i, (uint32_t *)(void *)data);
if (retval != ERROR_OK)
return retval;
for (j = 0; j < 4; j++)
buffer[i+j] = data[3-j];
}
/* remaining bytes */
if (i < count) {
retval = avr32_jtag_mwa_read(jtag_info, SLAVE_HSB_UNCACHED,
addr + i, (uint32_t *)(void *)data);
if (retval != ERROR_OK)
return retval;
for (j = 0; i + j < count; j++)
buffer[i+j] = data[3-j];
}
return ERROR_OK;
}
int avr32_jtag_write_memory32(struct avr32_jtag *jtag_info,
uint32_t addr, int count, const uint32_t *buffer)
{
int i, retval;
uint32_t data;
for (i = 0; i < count; i++) {
/* XXX: Assume AVR32 is BE */
h_u32_to_be((uint8_t *)&data, buffer[i]);
retval = avr32_jtag_mwa_write(jtag_info, SLAVE_HSB_UNCACHED,
addr + i*4, data);
if (retval != ERROR_OK)
return retval;
}
return ERROR_OK;
}
int avr32_jtag_write_memory16(struct avr32_jtag *jtag_info,
uint32_t addr, int count, const uint16_t *buffer)
{
int i, retval;
uint32_t data;
uint32_t data_out;
i = 0;
/*
* Do we have any non-aligned half-words?
*/
if (addr & 3) {
/*
* mwa_read will read whole world, no nead to fiddle
* with address. It will be truncated in set_addr
*/
retval = avr32_jtag_mwa_read(jtag_info, SLAVE_HSB_UNCACHED,
addr, &data);
if (retval != ERROR_OK)
return retval;
data = be_to_h_u32((uint8_t *)&data);
data = (buffer[i] << 16) | (data & 0xffff);
h_u32_to_be((uint8_t *)&data_out, data);
retval = avr32_jtag_mwa_write(jtag_info, SLAVE_HSB_UNCACHED,
addr, data_out);
if (retval != ERROR_OK)
return retval;
i++;
}
/* write all complete words */
for (; i < (count & ~1); i += 2) {
/* XXX: Assume AVR32 is BE */
data = (buffer[i+1] << 16) | buffer[i];
h_u32_to_be((uint8_t *)&data_out, data);
retval = avr32_jtag_mwa_write(jtag_info, SLAVE_HSB_UNCACHED,
addr + i*2, data_out);
if (retval != ERROR_OK)
return retval;
}
/* last halfword */
if (i < count) {
retval = avr32_jtag_mwa_read(jtag_info, SLAVE_HSB_UNCACHED,
addr + i*2, &data);
if (retval != ERROR_OK)
return retval;
data = be_to_h_u32((uint8_t *)&data);
data &= ~0xffff;
data |= buffer[i];
h_u32_to_be((uint8_t *)&data_out, data);
retval = avr32_jtag_mwa_write(jtag_info, SLAVE_HSB_UNCACHED,
addr + i*2, data_out);
if (retval != ERROR_OK)
return retval;
}
return ERROR_OK;
}
int avr32_jtag_write_memory8(struct avr32_jtag *jtag_info,
uint32_t addr, int count, const uint8_t *buffer)
{
int i, j, retval;
uint32_t data;
uint32_t data_out;
i = 0;
/*
* Do we have any non-aligned bytes?
*/
if (addr & 3) {
/*
* mwa_read will read whole world, no nead to fiddle
* with address. It will be truncated in set_addr
*/
retval = avr32_jtag_mwa_read(jtag_info, SLAVE_HSB_UNCACHED,
addr, &data);
if (retval != ERROR_OK)
return retval;
data = be_to_h_u32((uint8_t *)&data);
for (j = addr & 3; (j < 4) && (i < count); j++, i++) {
data &= ~(0xff << j*8);
data |= (buffer[i] << j*8);
}
h_u32_to_be((uint8_t *)&data_out, data);
retval = avr32_jtag_mwa_write(jtag_info, SLAVE_HSB_UNCACHED,
addr, data_out);
if (retval != ERROR_OK)
return retval;
}
/* write all complete words */
for (; i < (count & ~3); i += 4) {
data = 0;
for (j = 0; j < 4; j++)
data |= (buffer[j+i] << j*8);
h_u32_to_be((uint8_t *)&data_out, data);
retval = avr32_jtag_mwa_write(jtag_info, SLAVE_HSB_UNCACHED,
addr + i, data_out);
if (retval != ERROR_OK)
return retval;
}
/*
* Write trailing bytes
*/
if (i < count) {
retval = avr32_jtag_mwa_read(jtag_info, SLAVE_HSB_UNCACHED,
addr + i, &data);
if (retval != ERROR_OK)
return retval;
data = be_to_h_u32((uint8_t *)&data);
for (j = 0; i < count; j++, i++) {
data &= ~(0xff << j*8);
data |= (buffer[j+i] << j*8);
}
h_u32_to_be((uint8_t *)&data_out, data);
retval = avr32_jtag_mwa_write(jtag_info, SLAVE_HSB_UNCACHED,
addr+i, data_out);
if (retval != ERROR_OK)
return retval;
}
return ERROR_OK;
}

View File

@ -0,0 +1,37 @@
/***************************************************************************
* Copyright (C) 2010 by Oleksandr Tymoshenko <gonzo@bluezbox.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 AVR32_MEM
#define AVR32_MEM
int avr32_jtag_read_memory32(struct avr32_jtag *jtag_info,
uint32_t addr, int count, uint32_t *buffer);
int avr32_jtag_read_memory16(struct avr32_jtag *jtag_info,
uint32_t addr, int count, uint16_t *buffer);
int avr32_jtag_read_memory8(struct avr32_jtag *jtag_info,
uint32_t addr, int count, uint8_t *buffer);
int avr32_jtag_write_memory32(struct avr32_jtag *jtag_info,
uint32_t addr, int count, const uint32_t *buffer);
int avr32_jtag_write_memory16(struct avr32_jtag *jtag_info,
uint32_t addr, int count, const uint16_t *buffer);
int avr32_jtag_write_memory8(struct avr32_jtag *jtag_info,
uint32_t addr, int count, const uint8_t *buffer);
#endif /* AVR32_MEM */

View File

@ -0,0 +1,116 @@
/***************************************************************************
* Copyright (C) 2010 by Oleksandr Tymoshenko <gonzo@bluezbox.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 "target.h"
#include "jtag/jtag.h"
#include "avr32_jtag.h"
#include "avr32_regs.h"
static int avr32_jtag_read_reg(struct avr32_jtag *jtag_info, int reg,
uint32_t *val)
{
int retval;
uint32_t dcsr;
retval = avr32_jtag_exec(jtag_info, MTDR(AVR32_OCDREG_DCCPU, reg));
if (retval != ERROR_OK)
return retval;
do {
retval = avr32_jtag_nexus_read(jtag_info,
AVR32_OCDREG_DCSR, &dcsr);
if (retval != ERROR_OK)
return retval;
} while (!(dcsr & OCDREG_DCSR_CPUD));
retval = avr32_jtag_nexus_read(jtag_info,
AVR32_OCDREG_DCCPU, val);
return retval;
}
static int avr32_jtag_write_reg(struct avr32_jtag *jtag_info, int reg,
uint32_t val)
{
int retval;
uint32_t dcsr;
/* Restore Status reg */
retval = avr32_jtag_nexus_write(jtag_info,
AVR32_OCDREG_DCEMU, val);
if (retval != ERROR_OK)
return retval;
retval = avr32_jtag_exec(jtag_info, MFDR(reg, AVR32_OCDREG_DCEMU));
if (retval != ERROR_OK)
return retval;
do {
retval = avr32_jtag_nexus_read(jtag_info,
AVR32_OCDREG_DCSR, &dcsr);
} while (!(dcsr & OCDREG_DCSR_EMUD) && (retval == ERROR_OK));
return retval;
}
int avr32_jtag_read_regs(struct avr32_jtag *jtag_info, uint32_t *regs)
{
int i, retval;
/* read core registers */
for (i = 0; i < AVR32NUMCOREREGS - 1; i++)
avr32_jtag_read_reg(jtag_info, i, regs + i);
/* read status register */
retval = avr32_jtag_exec(jtag_info, MFSR(0, 0));
if (retval != ERROR_OK)
return retval;
retval = avr32_jtag_read_reg(jtag_info, 0, regs + AVR32_REG_SR);
return retval;
}
int avr32_jtag_write_regs(struct avr32_jtag *jtag_info, uint32_t *regs)
{
int i, retval;
retval = avr32_jtag_write_reg(jtag_info, 0, regs[AVR32_REG_SR]);
if (retval != ERROR_OK)
return retval;
/* Restore Status reg */
retval = avr32_jtag_exec(jtag_info, MTSR(0, 0));
if (retval != ERROR_OK)
return retval;
/*
* And now the rest of registers
*/
for (i = 0; i < AVR32NUMCOREREGS - 1; i++)
avr32_jtag_write_reg(jtag_info, i, regs[i]);
return ERROR_OK;
}

View File

@ -0,0 +1,46 @@
/***************************************************************************
* Copyright (C) 2010 by Oleksandr Tymoshenko <gonzo@bluezbox.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 AVR32_REGS
#define AVR32_REGS
enum avr32_reg_nums {
AVR32_REG_R0 = 0,
AVR32_REG_R1,
AVR32_REG_R2,
AVR32_REG_R3,
AVR32_REG_R4,
AVR32_REG_R5,
AVR32_REG_R6,
AVR32_REG_R7,
AVR32_REG_R8,
AVR32_REG_R9,
AVR32_REG_R10,
AVR32_REG_R11,
AVR32_REG_R12,
AVR32_REG_SP,
AVR32_REG_LR,
AVR32_REG_PC,
AVR32_REG_SR,
};
int avr32_jtag_read_regs(struct avr32_jtag *jtag_info, uint32_t *regs);
int avr32_jtag_write_regs(struct avr32_jtag *jtag_info, uint32_t *regs);
#endif /* AVR32_REGS */

View File

@ -0,0 +1,235 @@
/***************************************************************************
* Copyright (C) 2009 by Simon Qian *
* SimonQian@SimonQian.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "avrt.h"
#include "target.h"
#include "target_type.h"
#define AVR_JTAG_INS_LEN 4
/* forward declarations */
static int avr_target_create(struct target *target, Jim_Interp *interp);
static int avr_init_target(struct command_context *cmd_ctx, struct target *target);
static int avr_arch_state(struct target *target);
static int avr_poll(struct target *target);
static int avr_halt(struct target *target);
static int avr_resume(struct target *target, int current, uint32_t address,
int handle_breakpoints, int debug_execution);
static int avr_step(struct target *target, int current, uint32_t address,
int handle_breakpoints);
static int avr_assert_reset(struct target *target);
static int avr_deassert_reset(struct target *target);
static int avr_soft_reset_halt(struct target *target);
/* IR and DR functions */
static int mcu_write_ir(struct jtag_tap *tap, uint8_t *ir_in, uint8_t *ir_out, int ir_len, int rti);
static int mcu_write_dr(struct jtag_tap *tap, uint8_t *dr_in, uint8_t *dr_out, int dr_len, int rti);
static int mcu_write_ir_u8(struct jtag_tap *tap, uint8_t *ir_in, uint8_t ir_out, int ir_len, int rti);
static int mcu_write_dr_u32(struct jtag_tap *tap, uint32_t *ir_in, uint32_t ir_out, int dr_len, int rti);
struct target_type avr_target = {
.name = "avr",
.poll = avr_poll,
.arch_state = avr_arch_state,
.target_request_data = NULL,
.halt = avr_halt,
.resume = avr_resume,
.step = avr_step,
.assert_reset = avr_assert_reset,
.deassert_reset = avr_deassert_reset,
.soft_reset_halt = avr_soft_reset_halt,
/*
.get_gdb_reg_list = avr_get_gdb_reg_list,
.read_memory = avr_read_memory,
.write_memory = avr_write_memory,
.bulk_write_memory = avr_bulk_write_memory,
.checksum_memory = avr_checksum_memory,
.blank_check_memory = avr_blank_check_memory,
.run_algorithm = avr_run_algorithm,
.add_breakpoint = avr_add_breakpoint,
.remove_breakpoint = avr_remove_breakpoint,
.add_watchpoint = avr_add_watchpoint,
.remove_watchpoint = avr_remove_watchpoint,
*/
.target_create = avr_target_create,
.init_target = avr_init_target,
};
static int avr_target_create(struct target *target, Jim_Interp *interp)
{
struct avr_common *avr = calloc(1, sizeof(struct avr_common));
avr->jtag_info.tap = target->tap;
target->arch_info = avr;
return ERROR_OK;
}
static int avr_init_target(struct command_context *cmd_ctx, struct target *target)
{
LOG_DEBUG("%s", __func__);
return ERROR_OK;
}
static int avr_arch_state(struct target *target)
{
LOG_DEBUG("%s", __func__);
return ERROR_OK;
}
static int avr_poll(struct target *target)
{
if ((target->state == TARGET_RUNNING) || (target->state == TARGET_DEBUG_RUNNING))
target->state = TARGET_HALTED;
LOG_DEBUG("%s", __func__);
return ERROR_OK;
}
static int avr_halt(struct target *target)
{
LOG_DEBUG("%s", __func__);
return ERROR_OK;
}
static int avr_resume(struct target *target, int current, uint32_t address,
int handle_breakpoints, int debug_execution)
{
LOG_DEBUG("%s", __func__);
return ERROR_OK;
}
static int avr_step(struct target *target, int current, uint32_t address, int handle_breakpoints)
{
LOG_DEBUG("%s", __func__);
return ERROR_OK;
}
static int avr_assert_reset(struct target *target)
{
target->state = TARGET_RESET;
LOG_DEBUG("%s", __func__);
return ERROR_OK;
}
static int avr_deassert_reset(struct target *target)
{
target->state = TARGET_RUNNING;
LOG_DEBUG("%s", __func__);
return ERROR_OK;
}
static int avr_soft_reset_halt(struct target *target)
{
LOG_DEBUG("%s", __func__);
return ERROR_OK;
}
int avr_jtag_senddat(struct jtag_tap *tap, uint32_t* dr_in, uint32_t dr_out,
int len)
{
return mcu_write_dr_u32(tap, dr_in, dr_out, len, 1);
}
int avr_jtag_sendinstr(struct jtag_tap *tap, uint8_t *ir_in, uint8_t ir_out)
{
return mcu_write_ir_u8(tap, ir_in, ir_out, AVR_JTAG_INS_LEN, 1);
}
/* IR and DR functions */
static int mcu_write_ir(struct jtag_tap *tap, uint8_t *ir_in, uint8_t *ir_out,
int ir_len, int rti)
{
if (NULL == tap) {
LOG_ERROR("invalid tap");
return ERROR_FAIL;
}
if (ir_len != tap->ir_length) {
LOG_ERROR("invalid ir_len");
return ERROR_FAIL;
}
{
jtag_add_plain_ir_scan(tap->ir_length, ir_out, ir_in, TAP_IDLE);
}
return ERROR_OK;
}
static int mcu_write_dr(struct jtag_tap *tap, uint8_t *dr_in, uint8_t *dr_out,
int dr_len, int rti)
{
if (NULL == tap) {
LOG_ERROR("invalid tap");
return ERROR_FAIL;
}
{
jtag_add_plain_dr_scan(dr_len, dr_out, dr_in, TAP_IDLE);
}
return ERROR_OK;
}
static int mcu_write_ir_u8(struct jtag_tap *tap, uint8_t *ir_in,
uint8_t ir_out, int ir_len, int rti)
{
if (ir_len > 8) {
LOG_ERROR("ir_len overflow, maxium is 8");
return ERROR_FAIL;
}
mcu_write_ir(tap, ir_in, &ir_out, ir_len, rti);
return ERROR_OK;
}
static int mcu_write_dr_u32(struct jtag_tap *tap, uint32_t *dr_in,
uint32_t dr_out, int dr_len, int rti)
{
if (dr_len > 32) {
LOG_ERROR("dr_len overflow, maxium is 32");
return ERROR_FAIL;
}
mcu_write_dr(tap, (uint8_t *)dr_in, (uint8_t *)&dr_out, dr_len, rti);
return ERROR_OK;
}
int mcu_execute_queue(void)
{
return jtag_execute_queue();
}

View File

@ -0,0 +1,39 @@
/***************************************************************************
* Copyright (C) 2009 by Simon Qian *
* SimonQian@SimonQian.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef AVRT_H
#define AVRT_H
#include <jtag/jtag.h>
struct mcu_jtag {
struct jtag_tap *tap;
};
struct avr_common {
struct mcu_jtag jtag_info;
};
int mcu_execute_queue(void);
int avr_jtag_sendinstr(struct jtag_tap *tap, uint8_t *ir_in, uint8_t ir_out);
int avr_jtag_senddat(struct jtag_tap *tap, uint32_t *dr_in, uint32_t dr_out,
int len);
#endif /* AVRT_H */

View File

@ -0,0 +1,502 @@
/***************************************************************************
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* Copyright (C) ST-Ericsson SA 2011 *
* michel.jaouen@stericsson.com : smp minimum support *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "target.h"
#include <helper/log.h>
#include "breakpoints.h"
static char *breakpoint_type_strings[] = {
"hardware",
"software"
};
static char *watchpoint_rw_strings[] = {
"read",
"write",
"access"
};
/* monotonic counter/id-number for breakpoints and watch points */
static int bpwp_unique_id;
int breakpoint_add_internal(struct target *target,
uint32_t address,
uint32_t length,
enum breakpoint_type type)
{
struct breakpoint *breakpoint = target->breakpoints;
struct breakpoint **breakpoint_p = &target->breakpoints;
char *reason;
int retval;
int n;
n = 0;
while (breakpoint) {
n++;
if (breakpoint->address == address) {
/* FIXME don't assume "same address" means "same
* breakpoint" ... check all the parameters before
* succeeding.
*/
LOG_DEBUG("Duplicate Breakpoint address: 0x%08" PRIx32 " (BP %d)",
address, breakpoint->unique_id);
return ERROR_OK;
}
breakpoint_p = &breakpoint->next;
breakpoint = breakpoint->next;
}
(*breakpoint_p) = malloc(sizeof(struct breakpoint));
(*breakpoint_p)->address = address;
(*breakpoint_p)->asid = 0;
(*breakpoint_p)->length = length;
(*breakpoint_p)->type = type;
(*breakpoint_p)->set = 0;
(*breakpoint_p)->orig_instr = malloc(length);
(*breakpoint_p)->next = NULL;
(*breakpoint_p)->unique_id = bpwp_unique_id++;
retval = target_add_breakpoint(target, *breakpoint_p);
switch (retval) {
case ERROR_OK:
break;
case ERROR_TARGET_RESOURCE_NOT_AVAILABLE:
reason = "resource not available";
goto fail;
case ERROR_TARGET_NOT_HALTED:
reason = "target running";
goto fail;
default:
reason = "unknown reason";
fail:
LOG_ERROR("can't add breakpoint: %s", reason);
free((*breakpoint_p)->orig_instr);
free(*breakpoint_p);
*breakpoint_p = NULL;
return retval;
}
LOG_DEBUG("added %s breakpoint at 0x%8.8" PRIx32 " of length 0x%8.8x, (BPID: %d)",
breakpoint_type_strings[(*breakpoint_p)->type],
(*breakpoint_p)->address, (*breakpoint_p)->length,
(*breakpoint_p)->unique_id);
return ERROR_OK;
}
int context_breakpoint_add_internal(struct target *target,
uint32_t asid,
uint32_t length,
enum breakpoint_type type)
{
struct breakpoint *breakpoint = target->breakpoints;
struct breakpoint **breakpoint_p = &target->breakpoints;
int retval;
int n;
n = 0;
while (breakpoint) {
n++;
if (breakpoint->asid == asid) {
/* FIXME don't assume "same address" means "same
* breakpoint" ... check all the parameters before
* succeeding.
*/
LOG_DEBUG("Duplicate Breakpoint asid: 0x%08" PRIx32 " (BP %d)",
asid, breakpoint->unique_id);
return -1;
}
breakpoint_p = &breakpoint->next;
breakpoint = breakpoint->next;
}
(*breakpoint_p) = malloc(sizeof(struct breakpoint));
(*breakpoint_p)->address = 0;
(*breakpoint_p)->asid = asid;
(*breakpoint_p)->length = length;
(*breakpoint_p)->type = type;
(*breakpoint_p)->set = 0;
(*breakpoint_p)->orig_instr = malloc(length);
(*breakpoint_p)->next = NULL;
(*breakpoint_p)->unique_id = bpwp_unique_id++;
retval = target_add_context_breakpoint(target, *breakpoint_p);
if (retval != ERROR_OK) {
LOG_ERROR("could not add breakpoint");
free((*breakpoint_p)->orig_instr);
free(*breakpoint_p);
*breakpoint_p = NULL;
return retval;
}
LOG_DEBUG("added %s Context breakpoint at 0x%8.8" PRIx32 " of length 0x%8.8x, (BPID: %d)",
breakpoint_type_strings[(*breakpoint_p)->type],
(*breakpoint_p)->asid, (*breakpoint_p)->length,
(*breakpoint_p)->unique_id);
return ERROR_OK;
}
int hybrid_breakpoint_add_internal(struct target *target,
uint32_t address,
uint32_t asid,
uint32_t length,
enum breakpoint_type type)
{
struct breakpoint *breakpoint = target->breakpoints;
struct breakpoint **breakpoint_p = &target->breakpoints;
int retval;
int n;
n = 0;
while (breakpoint) {
n++;
if ((breakpoint->asid == asid) && (breakpoint->address == address)) {
/* FIXME don't assume "same address" means "same
* breakpoint" ... check all the parameters before
* succeeding.
*/
LOG_DEBUG("Duplicate Hybrid Breakpoint asid: 0x%08" PRIx32 " (BP %d)",
asid, breakpoint->unique_id);
return -1;
} else if ((breakpoint->address == address) && (breakpoint->asid == 0)) {
LOG_DEBUG("Duplicate Breakpoint IVA: 0x%08" PRIx32 " (BP %d)",
address, breakpoint->unique_id);
return -1;
}
breakpoint_p = &breakpoint->next;
breakpoint = breakpoint->next;
}
(*breakpoint_p) = malloc(sizeof(struct breakpoint));
(*breakpoint_p)->address = address;
(*breakpoint_p)->asid = asid;
(*breakpoint_p)->length = length;
(*breakpoint_p)->type = type;
(*breakpoint_p)->set = 0;
(*breakpoint_p)->orig_instr = malloc(length);
(*breakpoint_p)->next = NULL;
(*breakpoint_p)->unique_id = bpwp_unique_id++;
retval = target_add_hybrid_breakpoint(target, *breakpoint_p);
if (retval != ERROR_OK) {
LOG_ERROR("could not add breakpoint");
free((*breakpoint_p)->orig_instr);
free(*breakpoint_p);
*breakpoint_p = NULL;
return retval;
}
LOG_DEBUG(
"added %s Hybrid breakpoint at address 0x%8.8" PRIx32 " of length 0x%8.8x, (BPID: %d)",
breakpoint_type_strings[(*breakpoint_p)->type],
(*breakpoint_p)->address,
(*breakpoint_p)->length,
(*breakpoint_p)->unique_id);
return ERROR_OK;
}
int breakpoint_add(struct target *target,
uint32_t address,
uint32_t length,
enum breakpoint_type type)
{
int retval = ERROR_OK;
if (target->smp) {
struct target_list *head;
struct target *curr;
head = target->head;
if (type == BKPT_SOFT)
return breakpoint_add_internal(head->target, address, length, type);
while (head != (struct target_list *)NULL) {
curr = head->target;
retval = breakpoint_add_internal(curr, address, length, type);
if (retval != ERROR_OK)
return retval;
head = head->next;
}
return retval;
} else
return breakpoint_add_internal(target, address, length, type);
}
int context_breakpoint_add(struct target *target,
uint32_t asid,
uint32_t length,
enum breakpoint_type type)
{
int retval = ERROR_OK;
if (target->smp) {
struct target_list *head;
struct target *curr;
head = target->head;
while (head != (struct target_list *)NULL) {
curr = head->target;
retval = context_breakpoint_add_internal(curr, asid, length, type);
if (retval != ERROR_OK)
return retval;
head = head->next;
}
return retval;
} else
return context_breakpoint_add_internal(target, asid, length, type);
}
int hybrid_breakpoint_add(struct target *target,
uint32_t address,
uint32_t asid,
uint32_t length,
enum breakpoint_type type)
{
int retval = ERROR_OK;
if (target->smp) {
struct target_list *head;
struct target *curr;
head = target->head;
while (head != (struct target_list *)NULL) {
curr = head->target;
retval = hybrid_breakpoint_add_internal(curr, address, asid, length, type);
if (retval != ERROR_OK)
return retval;
head = head->next;
}
return retval;
} else
return hybrid_breakpoint_add_internal(target, address, asid, length, type);
}
/* free up a breakpoint */
static void breakpoint_free(struct target *target, struct breakpoint *breakpoint_to_remove)
{
struct breakpoint *breakpoint = target->breakpoints;
struct breakpoint **breakpoint_p = &target->breakpoints;
int retval;
while (breakpoint) {
if (breakpoint == breakpoint_to_remove)
break;
breakpoint_p = &breakpoint->next;
breakpoint = breakpoint->next;
}
if (breakpoint == NULL)
return;
retval = target_remove_breakpoint(target, breakpoint);
LOG_DEBUG("free BPID: %d --> %d", breakpoint->unique_id, retval);
(*breakpoint_p) = breakpoint->next;
free(breakpoint->orig_instr);
free(breakpoint);
}
int breakpoint_remove_internal(struct target *target, uint32_t address)
{
struct breakpoint *breakpoint = target->breakpoints;
while (breakpoint) {
if ((breakpoint->address == address) && (breakpoint->asid == 0))
break;
else if ((breakpoint->address == 0) && (breakpoint->asid == address))
break;
else if ((breakpoint->address == address) && (breakpoint->asid != 0))
break;
breakpoint = breakpoint->next;
}
if (breakpoint) {
breakpoint_free(target, breakpoint);
return 1;
} else {
if (!target->smp)
LOG_ERROR("no breakpoint at address 0x%8.8" PRIx32 " found", address);
return 0;
}
}
void breakpoint_remove(struct target *target, uint32_t address)
{
int found = 0;
if (target->smp) {
struct target_list *head;
struct target *curr;
head = target->head;
while (head != (struct target_list *)NULL) {
curr = head->target;
found += breakpoint_remove_internal(curr, address);
head = head->next;
}
if (found == 0)
LOG_ERROR("no breakpoint at address 0x%8.8" PRIx32 " found", address);
} else
breakpoint_remove_internal(target, address);
}
void breakpoint_clear_target_internal(struct target *target)
{
LOG_DEBUG("Delete all breakpoints for target: %s",
target_name(target));
while (target->breakpoints != NULL)
breakpoint_free(target, target->breakpoints);
}
void breakpoint_clear_target(struct target *target)
{
if (target->smp) {
struct target_list *head;
struct target *curr;
head = target->head;
while (head != (struct target_list *)NULL) {
curr = head->target;
breakpoint_clear_target_internal(curr);
head = head->next;
}
} else
breakpoint_clear_target_internal(target);
}
struct breakpoint *breakpoint_find(struct target *target, uint32_t address)
{
struct breakpoint *breakpoint = target->breakpoints;
while (breakpoint) {
if (breakpoint->address == address)
return breakpoint;
breakpoint = breakpoint->next;
}
return NULL;
}
int watchpoint_add(struct target *target, uint32_t address, uint32_t length,
enum watchpoint_rw rw, uint32_t value, uint32_t mask)
{
struct watchpoint *watchpoint = target->watchpoints;
struct watchpoint **watchpoint_p = &target->watchpoints;
int retval;
char *reason;
while (watchpoint) {
if (watchpoint->address == address) {
if (watchpoint->length != length
|| watchpoint->value != value
|| watchpoint->mask != mask
|| watchpoint->rw != rw) {
LOG_ERROR("address 0x%8.8" PRIx32
"already has watchpoint %d",
address, watchpoint->unique_id);
return ERROR_FAIL;
}
/* ignore duplicate watchpoint */
return ERROR_OK;
}
watchpoint_p = &watchpoint->next;
watchpoint = watchpoint->next;
}
(*watchpoint_p) = calloc(1, sizeof(struct watchpoint));
(*watchpoint_p)->address = address;
(*watchpoint_p)->length = length;
(*watchpoint_p)->value = value;
(*watchpoint_p)->mask = mask;
(*watchpoint_p)->rw = rw;
(*watchpoint_p)->unique_id = bpwp_unique_id++;
retval = target_add_watchpoint(target, *watchpoint_p);
switch (retval) {
case ERROR_OK:
break;
case ERROR_TARGET_RESOURCE_NOT_AVAILABLE:
reason = "resource not available";
goto bye;
case ERROR_TARGET_NOT_HALTED:
reason = "target running";
goto bye;
default:
reason = "unrecognized error";
bye:
LOG_ERROR("can't add %s watchpoint at 0x%8.8" PRIx32 ", %s",
watchpoint_rw_strings[(*watchpoint_p)->rw],
address, reason);
free(*watchpoint_p);
*watchpoint_p = NULL;
return retval;
}
LOG_DEBUG("added %s watchpoint at 0x%8.8" PRIx32
" of length 0x%8.8" PRIx32 " (WPID: %d)",
watchpoint_rw_strings[(*watchpoint_p)->rw],
(*watchpoint_p)->address,
(*watchpoint_p)->length,
(*watchpoint_p)->unique_id);
return ERROR_OK;
}
static void watchpoint_free(struct target *target, struct watchpoint *watchpoint_to_remove)
{
struct watchpoint *watchpoint = target->watchpoints;
struct watchpoint **watchpoint_p = &target->watchpoints;
int retval;
while (watchpoint) {
if (watchpoint == watchpoint_to_remove)
break;
watchpoint_p = &watchpoint->next;
watchpoint = watchpoint->next;
}
if (watchpoint == NULL)
return;
retval = target_remove_watchpoint(target, watchpoint);
LOG_DEBUG("free WPID: %d --> %d", watchpoint->unique_id, retval);
(*watchpoint_p) = watchpoint->next;
free(watchpoint);
}
void watchpoint_remove(struct target *target, uint32_t address)
{
struct watchpoint *watchpoint = target->watchpoints;
while (watchpoint) {
if (watchpoint->address == address)
break;
watchpoint = watchpoint->next;
}
if (watchpoint)
watchpoint_free(target, watchpoint);
else
LOG_ERROR("no watchpoint at address 0x%8.8" PRIx32 " found", address);
}
void watchpoint_clear_target(struct target *target)
{
LOG_DEBUG("Delete all watchpoints for target: %s",
target_name(target));
while (target->watchpoints != NULL)
watchpoint_free(target, target->watchpoints);
}

View File

@ -0,0 +1,75 @@
/***************************************************************************
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef BREAKPOINTS_H
#define BREAKPOINTS_H
struct target;
enum breakpoint_type {
BKPT_HARD,
BKPT_SOFT,
};
enum watchpoint_rw {
WPT_READ = 0, WPT_WRITE = 1, WPT_ACCESS = 2
};
struct breakpoint {
uint32_t address;
uint32_t asid;
int length;
enum breakpoint_type type;
int set;
uint8_t *orig_instr;
struct breakpoint *next;
uint32_t unique_id;
int linked_BRP;
};
struct watchpoint {
uint32_t address;
uint32_t length;
uint32_t mask;
uint32_t value;
enum watchpoint_rw rw;
int set;
struct watchpoint *next;
int unique_id;
};
void breakpoint_clear_target(struct target *target);
int breakpoint_add(struct target *target,
uint32_t address, uint32_t length, enum breakpoint_type type);
int context_breakpoint_add(struct target *target,
uint32_t asid, uint32_t length, enum breakpoint_type type);
int hybrid_breakpoint_add(struct target *target,
uint32_t address, uint32_t asid, uint32_t length, enum breakpoint_type type);
void breakpoint_remove(struct target *target, uint32_t address);
struct breakpoint *breakpoint_find(struct target *target, uint32_t address);
void watchpoint_clear_target(struct target *target);
int watchpoint_add(struct target *target,
uint32_t address, uint32_t length,
enum watchpoint_rw rw, uint32_t value, uint32_t mask);
void watchpoint_remove(struct target *target, uint32_t address);
#endif /* BREAKPOINTS_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,89 @@
/***************************************************************************
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* Copyright (C) 2006 by Magnus Lundin *
* lundin@mlu.mine.nu *
* *
* Copyright (C) 2008 by Spencer Oliver *
* spen@spen-soft.co.uk *
* *
* Copyright (C) 2009 by Dirk Behme *
* dirk.behme@gmail.com - copy from cortex_m3 *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef CORTEX_A8_H
#define CORTEX_A8_H
#include "armv7a.h"
#define CORTEX_A8_COMMON_MAGIC 0x411fc082
#define CPUDBG_CPUID 0xD00
#define CPUDBG_CTYPR 0xD04
#define CPUDBG_TTYPR 0xD0C
#define CPUDBG_LOCKACCESS 0xFB0
#define CPUDBG_LOCKSTATUS 0xFB4
#define BRP_NORMAL 0
#define BRP_CONTEXT 1
#define CORTEX_A8_PADDRDBG_CPU_SHIFT 13
struct cortex_a8_brp {
int used;
int type;
uint32_t value;
uint32_t control;
uint8_t BRPn;
};
struct cortex_a8_common {
int common_magic;
struct arm_jtag jtag_info;
/* Context information */
uint32_t cpudbg_dscr;
/* Saved cp15 registers */
uint32_t cp15_control_reg;
/* latest cp15 register value written and cpsr processor mode */
uint32_t cp15_control_reg_curr;
enum arm_mode curr_mode;
/* Breakpoint register pairs */
int brp_num_context;
int brp_num;
int brp_num_available;
struct cortex_a8_brp *brp_list;
/* Use cortex_a8_read_regs_through_mem for fast register reads */
int fast_reg_read;
struct armv7a_common armv7a_common;
};
static inline struct cortex_a8_common *
target_to_cortex_a8(struct target *target)
{
return container_of(target->arch_info, struct cortex_a8_common, armv7a_common.arm);
}
#endif /* CORTEX_A8_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,201 @@
/***************************************************************************
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* Copyright (C) 2006 by Magnus Lundin *
* lundin@mlu.mine.nu *
* *
* Copyright (C) 2008 by Spencer Oliver *
* spen@spen-soft.co.uk *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef CORTEX_M3_H
#define CORTEX_M3_H
#include "armv7m.h"
#define CORTEX_M3_COMMON_MAGIC 0x1A451A45
#define SYSTEM_CONTROL_BASE 0x400FE000
#define CPUID 0xE000ED00
/* Debug Control Block */
#define DCB_DHCSR 0xE000EDF0
#define DCB_DCRSR 0xE000EDF4
#define DCB_DCRDR 0xE000EDF8
#define DCB_DEMCR 0xE000EDFC
#define DCRSR_WnR (1 << 16)
#define DWT_CTRL 0xE0001000
#define DWT_CYCCNT 0xE0001004
#define DWT_COMP0 0xE0001020
#define DWT_MASK0 0xE0001024
#define DWT_FUNCTION0 0xE0001028
#define FP_CTRL 0xE0002000
#define FP_REMAP 0xE0002004
#define FP_COMP0 0xE0002008
#define FP_COMP1 0xE000200C
#define FP_COMP2 0xE0002010
#define FP_COMP3 0xE0002014
#define FP_COMP4 0xE0002018
#define FP_COMP5 0xE000201C
#define FP_COMP6 0xE0002020
#define FP_COMP7 0xE0002024
#define FPU_CPACR 0xE000ED88
#define FPU_FPCCR 0xE000EF34
#define FPU_FPCAR 0xE000EF38
#define FPU_FPDSCR 0xE000EF3C
/* DCB_DHCSR bit and field definitions */
#define DBGKEY (0xA05F << 16)
#define C_DEBUGEN (1 << 0)
#define C_HALT (1 << 1)
#define C_STEP (1 << 2)
#define C_MASKINTS (1 << 3)
#define S_REGRDY (1 << 16)
#define S_HALT (1 << 17)
#define S_SLEEP (1 << 18)
#define S_LOCKUP (1 << 19)
#define S_RETIRE_ST (1 << 24)
#define S_RESET_ST (1 << 25)
/* DCB_DEMCR bit and field definitions */
#define TRCENA (1 << 24)
#define VC_HARDERR (1 << 10)
#define VC_INTERR (1 << 9)
#define VC_BUSERR (1 << 8)
#define VC_STATERR (1 << 7)
#define VC_CHKERR (1 << 6)
#define VC_NOCPERR (1 << 5)
#define VC_MMERR (1 << 4)
#define VC_CORERESET (1 << 0)
#define NVIC_ICTR 0xE000E004
#define NVIC_ISE0 0xE000E100
#define NVIC_ICSR 0xE000ED04
#define NVIC_AIRCR 0xE000ED0C
#define NVIC_SHCSR 0xE000ED24
#define NVIC_CFSR 0xE000ED28
#define NVIC_MMFSRb 0xE000ED28
#define NVIC_BFSRb 0xE000ED29
#define NVIC_USFSRh 0xE000ED2A
#define NVIC_HFSR 0xE000ED2C
#define NVIC_DFSR 0xE000ED30
#define NVIC_MMFAR 0xE000ED34
#define NVIC_BFAR 0xE000ED38
/* NVIC_AIRCR bits */
#define AIRCR_VECTKEY (0x5FA << 16)
#define AIRCR_SYSRESETREQ (1 << 2)
#define AIRCR_VECTCLRACTIVE (1 << 1)
#define AIRCR_VECTRESET (1 << 0)
/* NVIC_SHCSR bits */
#define SHCSR_BUSFAULTENA (1 << 17)
/* NVIC_DFSR bits */
#define DFSR_HALTED 1
#define DFSR_BKPT 2
#define DFSR_DWTTRAP 4
#define DFSR_VCATCH 8
#define FPCR_CODE 0
#define FPCR_LITERAL 1
#define FPCR_REPLACE_REMAP (0 << 30)
#define FPCR_REPLACE_BKPT_LOW (1 << 30)
#define FPCR_REPLACE_BKPT_HIGH (2 << 30)
#define FPCR_REPLACE_BKPT_BOTH (3 << 30)
struct cortex_m3_fp_comparator {
int used;
int type;
uint32_t fpcr_value;
uint32_t fpcr_address;
};
struct cortex_m3_dwt_comparator {
int used;
uint32_t comp;
uint32_t mask;
uint32_t function;
uint32_t dwt_comparator_address;
};
enum cortex_m3_soft_reset_config {
CORTEX_M3_RESET_SYSRESETREQ,
CORTEX_M3_RESET_VECTRESET,
};
enum cortex_m3_isrmasking_mode {
CORTEX_M3_ISRMASK_AUTO,
CORTEX_M3_ISRMASK_OFF,
CORTEX_M3_ISRMASK_ON,
};
struct cortex_m3_common {
int common_magic;
struct arm_jtag jtag_info;
/* Context information */
uint32_t dcb_dhcsr;
uint32_t nvic_dfsr; /* Debug Fault Status Register - shows reason for debug halt */
uint32_t nvic_icsr; /* Interrupt Control State Register - shows active and pending IRQ */
/* Flash Patch and Breakpoint (FPB) */
int fp_num_lit;
int fp_num_code;
int fp_code_available;
int fpb_enabled;
int auto_bp_type;
struct cortex_m3_fp_comparator *fp_comparator_list;
/* Data Watchpoint and Trace (DWT) */
int dwt_num_comp;
int dwt_comp_available;
struct cortex_m3_dwt_comparator *dwt_comparator_list;
struct reg_cache *dwt_cache;
enum cortex_m3_soft_reset_config soft_reset_config;
enum cortex_m3_isrmasking_mode isrmasking_mode;
struct armv7m_common armv7m;
};
static inline struct cortex_m3_common *
target_to_cm3(struct target *target)
{
return container_of(target->arch_info,
struct cortex_m3_common, armv7m);
}
int cortex_m3_examine(struct target *target);
int cortex_m3_set_breakpoint(struct target *target, struct breakpoint *breakpoint);
int cortex_m3_unset_breakpoint(struct target *target, struct breakpoint *breakpoint);
int cortex_m3_add_breakpoint(struct target *target, struct breakpoint *breakpoint);
int cortex_m3_remove_breakpoint(struct target *target, struct breakpoint *breakpoint);
int cortex_m3_set_watchpoint(struct target *target, struct watchpoint *watchpoint);
int cortex_m3_unset_watchpoint(struct target *target, struct watchpoint *watchpoint);
int cortex_m3_add_watchpoint(struct target *target, struct watchpoint *watchpoint);
int cortex_m3_remove_watchpoint(struct target *target, struct watchpoint *watchpoint);
void cortex_m3_enable_breakpoints(struct target *target);
void cortex_m3_enable_watchpoints(struct target *target);
void cortex_m3_dwt_setup(struct cortex_m3_common *cm3, struct target *target);
#endif /* CORTEX_M3_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,60 @@
/***************************************************************************
* Copyright (C) 2009-2011 by Mathias Kuester *
* mkdorg@users.sourceforge.net *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef DSP563XX_H
#define DSP563XX_H
#include <jtag/jtag.h>
#include <target/dsp563xx_once.h>
#define DSP563XX_NUMCOREREGS 54
#define DSP563XX_NUMONCEREGS 25
struct mcu_jtag {
struct jtag_tap *tap;
};
struct dsp563xx_common {
struct mcu_jtag jtag_info;
struct reg_cache *core_cache;
uint32_t core_regs[DSP563XX_NUMCOREREGS];
struct once_reg once_regs[DSP563XX_NUMONCEREGS];
/* register cache to processor synchronization */
int (*read_core_reg) (struct target *target, int num);
int (*write_core_reg) (struct target *target, int num);
};
struct dsp563xx_core_reg {
uint32_t num;
const char *name;
uint32_t size;
uint8_t eame;
uint32_t instr_mask;
struct target *target;
struct dsp563xx_common *dsp563xx_common;
};
static inline struct dsp563xx_common *target_to_dsp563xx(struct target *target)
{
return target->arch_info;
}
#endif /* DSP563XX_H */

View File

@ -0,0 +1,293 @@
/***************************************************************************
* Copyright (C) 2009 by Mathias Kuester *
* mkdorg@users.sourceforge.net *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <jim.h>
#include "target.h"
#include "target_type.h"
#include "register.h"
#include "dsp563xx.h"
#include "dsp563xx_once.h"
#define JTAG_STATUS_STATIC_MASK 0x03
#define JTAG_STATUS_STATIC_VALUE 0x01
#define JTAG_STATUS_NORMAL 0x01
#define JTAG_STATUS_STOPWAIT 0x05
#define JTAG_STATUS_BUSY 0x09
#define JTAG_STATUS_DEBUG 0x0d
#define JTAG_INSTR_EXTEST 0x00
#define JTAG_INSTR_SAMPLE_PRELOAD 0x01
#define JTAG_INSTR_IDCODE 0x02
#define JTAG_INSTR_HIZ 0x04
#define JTAG_INSTR_CLAMP 0x05
#define JTAG_INSTR_ENABLE_ONCE 0x06
#define JTAG_INSTR_DEBUG_REQUEST 0x07
#define JTAG_INSTR_BYPASS 0x0F
/** */
static inline int dsp563xx_write_dr(struct jtag_tap *tap, uint8_t * dr_in, uint8_t * dr_out, int dr_len, int rti)
{
jtag_add_plain_dr_scan(dr_len, dr_out, dr_in, TAP_IDLE);
return ERROR_OK;
}
/** */
static inline int dsp563xx_write_dr_u8(struct jtag_tap *tap, uint8_t * dr_in, uint8_t dr_out, int dr_len, int rti)
{
return dsp563xx_write_dr(tap, dr_in, &dr_out, dr_len, rti);
}
/** */
static inline int dsp563xx_write_dr_u32(struct jtag_tap *tap, uint32_t * dr_in, uint32_t dr_out, int dr_len, int rti)
{
return dsp563xx_write_dr(tap, (uint8_t *) dr_in, (uint8_t *) &dr_out, dr_len, rti);
}
/** single word instruction */
static inline int dsp563xx_once_ir_exec(struct jtag_tap *tap, int flush, uint8_t instr, uint8_t rw, uint8_t go, uint8_t ex)
{
int err;
err = dsp563xx_write_dr_u8(tap, 0, instr | (ex << 5) | (go << 6) | (rw << 7), 8, 0);
if (err != ERROR_OK)
return err;
if (flush)
err = jtag_execute_queue();
return err;
}
/* IR and DR functions */
static inline int dsp563xx_write_ir(struct jtag_tap *tap, uint8_t * ir_in, uint8_t * ir_out, int ir_len, int rti)
{
jtag_add_plain_ir_scan(tap->ir_length, ir_out, ir_in, TAP_IDLE);
return ERROR_OK;
}
static inline int dsp563xx_write_ir_u8(struct jtag_tap *tap, uint8_t * ir_in, uint8_t ir_out, int ir_len, int rti)
{
return dsp563xx_write_ir(tap, ir_in, &ir_out, ir_len, rti);
}
static inline int dsp563xx_jtag_sendinstr(struct jtag_tap *tap, uint8_t * ir_in, uint8_t ir_out)
{
return dsp563xx_write_ir_u8(tap, ir_in, ir_out, tap->ir_length, 1);
}
/** */
int dsp563xx_once_target_status(struct jtag_tap *tap)
{
int err;
uint8_t jtag_status;
err = dsp563xx_jtag_sendinstr(tap, &jtag_status, JTAG_INSTR_ENABLE_ONCE);
if (err != ERROR_OK)
return TARGET_UNKNOWN;
err = jtag_execute_queue();
if (err != ERROR_OK)
return TARGET_UNKNOWN;
/* verify correct static status pattern */
if ((jtag_status & JTAG_STATUS_STATIC_MASK) != JTAG_STATUS_STATIC_VALUE)
return TARGET_UNKNOWN;
if (jtag_status != JTAG_STATUS_DEBUG)
return TARGET_RUNNING;
return TARGET_HALTED;
}
/** */
int dsp563xx_once_request_debug(struct jtag_tap *tap, int reset_state)
{
int err;
uint8_t ir_in = 0, pattern = 0;
uint32_t retry = 0;
/* in reset state we only get a ACK
* from the interface */
if (reset_state)
pattern = 1;
else
pattern = JTAG_STATUS_DEBUG;
/* wait until we get the ack */
while (ir_in != pattern) {
err = dsp563xx_jtag_sendinstr(tap, &ir_in, JTAG_INSTR_DEBUG_REQUEST);
if (err != ERROR_OK)
return err;
err = jtag_execute_queue();
if (err != ERROR_OK)
return err;
LOG_DEBUG("debug request: %02X", ir_in);
if (retry++ == 100)
return ERROR_TARGET_FAILURE;
}
/* we cant enable the once in reset state */
if (pattern == 1)
return ERROR_OK;
/* try to enable once */
retry = 0;
ir_in = 0;
while (ir_in != pattern) {
err = dsp563xx_jtag_sendinstr(tap, &ir_in, JTAG_INSTR_ENABLE_ONCE);
if (err != ERROR_OK)
return err;
err = jtag_execute_queue();
if (err != ERROR_OK)
return err;
LOG_DEBUG("enable once: %02X", ir_in);
if (retry++ == 100) {
LOG_DEBUG("error");
return ERROR_TARGET_FAILURE;
}
}
if (ir_in != JTAG_STATUS_DEBUG)
return ERROR_TARGET_FAILURE;
return ERROR_OK;
}
/** once read registers */
int dsp563xx_once_read_register(struct jtag_tap *tap, int flush, struct once_reg *regs, int len)
{
int i;
int err = ERROR_OK;
for (i = 0; i < len; i++) {
err = dsp563xx_once_reg_read_ex(tap, flush, regs[i].addr, regs[i].len, &regs[i].reg);
if (err != ERROR_OK)
return err;
}
if (flush)
err = jtag_execute_queue();
return err;
}
/** once read register with register len */
int dsp563xx_once_reg_read_ex(struct jtag_tap *tap, int flush, uint8_t reg, uint8_t len, uint32_t * data)
{
int err;
err = dsp563xx_once_ir_exec(tap, 1, reg, 1, 0, 0);
if (err != ERROR_OK)
return err;
err = dsp563xx_write_dr_u32(tap, data, 0x00, len, 0);
if (err != ERROR_OK)
return err;
if (flush)
err = jtag_execute_queue();
return err;
}
/** once read register */
int dsp563xx_once_reg_read(struct jtag_tap *tap, int flush, uint8_t reg, uint32_t * data)
{
int err;
err = dsp563xx_once_ir_exec(tap, flush, reg, 1, 0, 0);
if (err != ERROR_OK)
return err;
err = dsp563xx_write_dr_u32(tap, data, 0x00, 24, 0);
if (err != ERROR_OK)
return err;
if (flush)
err = jtag_execute_queue();
return err;
}
/** once write register */
int dsp563xx_once_reg_write(struct jtag_tap *tap, int flush, uint8_t reg, uint32_t data)
{
int err;
err = dsp563xx_once_ir_exec(tap, flush, reg, 0, 0, 0);
if (err != ERROR_OK)
return err;
err = dsp563xx_write_dr_u32(tap, 0x00, data, 24, 0);
if (err != ERROR_OK)
return err;
if (flush)
err = jtag_execute_queue();
return err;
}
/** single word instruction */
int dsp563xx_once_execute_sw_ir(struct jtag_tap *tap, int flush, uint32_t opcode)
{
int err;
err = dsp563xx_once_ir_exec(tap, flush, DSP563XX_ONCE_OPDBR, 0, 1, 0);
if (err != ERROR_OK)
return err;
err = dsp563xx_write_dr_u32(tap, 0, opcode, 24, 0);
if (err != ERROR_OK)
return err;
if (flush)
err = jtag_execute_queue();
return err;
}
/** double word instruction */
int dsp563xx_once_execute_dw_ir(struct jtag_tap *tap, int flush, uint32_t opcode, uint32_t operand)
{
int err;
err = dsp563xx_once_ir_exec(tap, flush, DSP563XX_ONCE_OPDBR, 0, 0, 0);
if (err != ERROR_OK)
return err;
err = dsp563xx_write_dr_u32(tap, 0, opcode, 24, 0);
if (err != ERROR_OK)
return err;
if (flush) {
err = jtag_execute_queue();
if (err != ERROR_OK)
return err;
}
err = dsp563xx_once_ir_exec(tap, flush, DSP563XX_ONCE_OPDBR, 0, 1, 0);
if (err != ERROR_OK)
return err;
err = dsp563xx_write_dr_u32(tap, 0, operand, 24, 0);
if (err != ERROR_OK)
return err;
if (flush) {
err = jtag_execute_queue();
if (err != ERROR_OK)
return err;
}
return ERROR_OK;
}

View File

@ -0,0 +1,87 @@
/***************************************************************************
* Copyright (C) 2009 by Mathias Kuester *
* mkdorg@users.sourceforge.net *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef DSP563XX_ONCE_H
#define DSP563XX_ONCE_H
#include <jtag/jtag.h>
#define DSP563XX_ONCE_OCR_EX (1<<5)
#define DSP563XX_ONCE_OCR_GO (1<<6)
#define DSP563XX_ONCE_OCR_RW (1<<7)
#define DSP563XX_ONCE_OSCR_OS1 (1<<7)
#define DSP563XX_ONCE_OSCR_OS0 (1<<6)
#define DSP563XX_ONCE_OSCR_HIT (1<<5)
#define DSP563XX_ONCE_OSCR_TO (1<<4)
#define DSP563XX_ONCE_OSCR_MBO (1<<3)
#define DSP563XX_ONCE_OSCR_SWO (1<<2)
#define DSP563XX_ONCE_OSCR_IME (1<<1)
#define DSP563XX_ONCE_OSCR_TME (1<<0)
#define DSP563XX_ONCE_OSCR_NORMAL_M (0)
#define DSP563XX_ONCE_OSCR_STOPWAIT_M (DSP563XX_ONCE_OSCR_OS0)
#define DSP563XX_ONCE_OSCR_BUSY_M (DSP563XX_ONCE_OSCR_OS1)
#define DSP563XX_ONCE_OSCR_DEBUG_M (DSP563XX_ONCE_OSCR_OS0|DSP563XX_ONCE_OSCR_OS1)
#define DSP563XX_ONCE_OSCR 0x000 /* status/ctrl reg. */
#define DSP563XX_ONCE_OMBC 0x001 /* memory breakp. reg. */
#define DSP563XX_ONCE_OBCR 0x002 /* breakp. ctrl reg */
#define DSP563XX_ONCE_OMLR0 0x005 /* memory limit reg */
#define DSP563XX_ONCE_OMLR1 0x006 /* memory limit reg */
#define DSP563XX_ONCE_OGDBR 0x009 /* gdb reg */
#define DSP563XX_ONCE_OPDBR 0x00A /* pdb reg */
#define DSP563XX_ONCE_OPILR 0x00B /* pil reg */
#define DSP563XX_ONCE_PDBGOTO 0x00C /* pdb to go reg */
#define DSP563XX_ONCE_OTC 0x00D /* trace cnt */
#define DSP563XX_ONCE_TAGB 0x00E /* tags buffer */
#define DSP563XX_ONCE_OPABFR 0x00F /* pab fetch reg */
#define DSP563XX_ONCE_OPABDR 0x010 /* pab decode reg */
#define DSP563XX_ONCE_OPABEX 0x011 /* pab exec reg */
#define DSP563XX_ONCE_OPABF11 0x012 /* trace buffer/inc ptr */
#define DSP563XX_ONCE_NOREG 0x01F /* no register selected */
struct once_reg {
uint8_t num;
uint8_t addr;
uint8_t len;
const char *name;
uint32_t reg;
};
/** */
int dsp563xx_once_request_debug(struct jtag_tap *tap, int reset_state);
/** */
int dsp563xx_once_target_status(struct jtag_tap *tap);
/** once read registers */
int dsp563xx_once_read_register(struct jtag_tap *tap, int flush, struct once_reg *regs, int len);
/** once read register */
int dsp563xx_once_reg_read_ex(struct jtag_tap *tap, int flush, uint8_t reg, uint8_t len, uint32_t * data);
/** once read register */
int dsp563xx_once_reg_read(struct jtag_tap *tap, int flush, uint8_t reg, uint32_t * data);
/** once write register */
int dsp563xx_once_reg_write(struct jtag_tap *tap, int flush, uint8_t reg, uint32_t data);
/** single word instruction */
int dsp563xx_once_execute_sw_ir(struct jtag_tap *tap, int flush, uint32_t opcode);
/** double word instruction */
int dsp563xx_once_execute_dw_ir(struct jtag_tap *tap, int flush, uint32_t opcode, uint32_t operand);
#endif /* DSP563XX_ONCE_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,384 @@
/***************************************************************************
* Copyright (C) 2011 by Rodrigo L. Rosa *
* rodrigorosa.LG@gmail.com *
* *
* Based on dsp563xx_once.h written by Mathias Kuester *
* mkdorg@users.sourceforge.net *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef DSP5680XX_H
#define DSP5680XX_H
#include <jtag/jtag.h>
/**
* @file dsp5680xx.h
* @author Rodrigo Rosa <rodrigorosa.LG@gmail.com>
* @date Thu Jun 9 18:54:38 2011
*
* @brief Basic support for the 5680xx DSP from Freescale.
* The chip has two taps in the JTAG chain, the Master tap and the Core tap.
* In this code the Master tap is only used to unlock the flash memory by executing a JTAG instruction.
*
*/
#define S_FILE_DATA_OFFSET 0x200000
#define TIME_DIV_FREESCALE 0.3
/** ----------------------------------------------------------------
* JTAG
*----------------------------------------------------------------
*/
#define DSP5680XX_JTAG_CORE_TAP_IRLEN 4
#define DSP5680XX_JTAG_MASTER_TAP_IRLEN 8
#define JTAG_STATUS_MASK 0x0F
#define JTAG_STATUS_NORMAL 0x01
#define JTAG_STATUS_STOPWAIT 0x05
#define JTAG_STATUS_BUSY 0x09
#define JTAG_STATUS_DEBUG 0x0D
#define JTAG_STATUS_DEAD 0x0f
#define JTAG_INSTR_EXTEST 0x0
#define JTAG_INSTR_SAMPLE_PRELOAD 0x1
#define JTAG_INSTR_IDCODE 0x2
#define JTAG_INSTR_EXTEST_PULLUP 0x3
#define JTAG_INSTR_HIGHZ 0x4
#define JTAG_INSTR_CLAMP 0x5
#define JTAG_INSTR_ENABLE_ONCE 0x6
#define JTAG_INSTR_DEBUG_REQUEST 0x7
#define JTAG_INSTR_BYPASS 0xF
/**
* ----------------------------------------------------------------
*/
/** ----------------------------------------------------------------
* Master TAP instructions from MC56F8000RM.pdf
* ----------------------------------------------------------------
*/
#define MASTER_TAP_CMD_BYPASS 0xF
#define MASTER_TAP_CMD_IDCODE 0x2
#define MASTER_TAP_CMD_TLM_SEL 0x5
#define MASTER_TAP_CMD_FLASH_ERASE 0x8
/**
* ----------------------------------------------------------------
*/
/** ----------------------------------------------------------------
* EOnCE control register info
* ----------------------------------------------------------------
*/
#define DSP5680XX_ONCE_OCR_EX (1<<5)
/* EX Bit Definition
0 Remain in the Debug Processing State
1 Leave the Debug Processing State */
#define DSP5680XX_ONCE_OCR_GO (1<<6)
/* GO Bit Definition
0 Inactive—No Action Taken
1 Execute Controller Instruction */
#define DSP5680XX_ONCE_OCR_RW (1<<7)
/** RW Bit Definition
* 0 Write To the Register Specified by the RS[4:0] Bits
* 1 ReadFrom the Register Specified by the RS[4:0] Bits
* ----------------------------------------------------------------
*/
/** ----------------------------------------------------------------
* EOnCE Status Register
* ----------------------------------------------------------------
*/
#define DSP5680XX_ONCE_OSCR_OS1 (1<<5)
#define DSP5680XX_ONCE_OSCR_OS0 (1<<4)
/**
* ----------------------------------------------------------------
*/
/** ----------------------------------------------------------------
* EOnCE Core Status - Describes the operating status of the core controller
* ----------------------------------------------------------------
*/
#define DSP5680XX_ONCE_OSCR_NORMAL_M (0)
/* 00 - Normal - Controller Core Executing Instructions or in Reset */
#define DSP5680XX_ONCE_OSCR_STOPWAIT_M (DSP5680XX_ONCE_OSCR_OS0)
/* 01 - Stop/Wait - Controller Core in Stop or Wait Mode */
#define DSP5680XX_ONCE_OSCR_BUSY_M (DSP5680XX_ONCE_OSCR_OS1)
/* 10 - Busy - Controller is Performing External or Peripheral Access (Wait States) */
#define DSP5680XX_ONCE_OSCR_DEBUG_M (DSP5680XX_ONCE_OSCR_OS0|DSP5680XX_ONCE_OSCR_OS1)
/* 11 - Debug - Controller Core Halted and in Debug Mode */
#define EONCE_STAT_MASK 0x30
/**
* ----------------------------------------------------------------
*/
/** ----------------------------------------------------------------
* Register Select Encoding (eonce_rev.1.0_0208081.pdf:14)
* ----------------------------------------------------------------
*/
#define DSP5680XX_ONCE_NOREG 0x00 /* No register selected */
#define DSP5680XX_ONCE_OCR 0x01 /* OnCE Debug Control Register */
#define DSP5680XX_ONCE_OCNTR 0x02 /* OnCE Breakpoint and Trace Counter */
#define DSP5680XX_ONCE_OSR 0x03 /* EOnCE status register */
#define DSP5680XX_ONCE_OBAR 0x04 /* OnCE Breakpoint Address Register */
#define DSP5680XX_ONCE_OBASE 0x05 /* EOnCE Peripheral Base Address register */
#define DSP5680XX_ONCE_OTXRXSR 0x06 /* EOnCE TXRX Status and Control Register (OTXRXSR) */
#define DSP5680XX_ONCE_OTX 0x07 /* EOnCE Transmit register (OTX) */
#define DSP5680XX_ONCE_OPDBR 0x08 /* EOnCE Program Data Bus Register (OPDBR) */
#define DSP5680XX_ONCE_OTX1 0x09 /* EOnCE Upper Transmit register (OTX1) */
#define DSP5680XX_ONCE_OPABFR 0x0A /* OnCE Program Address Register—Fetch cycle */
#define DSP5680XX_ONCE_ORX 0x0B /* EOnCE Receive register (ORX) */
#define DSP5680XX_ONCE_OCNTR_C 0x0C /* Clear OCNTR */
#define DSP5680XX_ONCE_ORX1 0x0D /* EOnCE Upper Receive register (ORX1) */
#define DSP5680XX_ONCE_OTBCR 0x0E /* EOnCE Trace Buffer Control Reg (OTBCR) */
#define DSP5680XX_ONCE_OPABER 0x10 /* OnCE Program Address Register—Execute cycle */
#define DSP5680XX_ONCE_OPFIFO 0x11 /* OnCE Program address FIFO */
#define DSP5680XX_ONCE_OBAR1 0x12 /* EOnCE Breakpoint 1 Unit 0 Address Reg.(OBAR1) */
#define DSP5680XX_ONCE_OPABDR 0x13 /* OnCE Program Address Register—Decode cycle (OPABDR) */
/**
* ----------------------------------------------------------------
*/
#define FLUSH_COUNT_READ_WRITE 8192 /* This value works, higher values (and lower...) may work as well. */
#define FLUSH_COUNT_FLASH 8192
/** ----------------------------------------------------------------
* HFM (flash module) Commands (ref:MC56F801xRM.pdf:159)
* ----------------------------------------------------------------
*/
#define HFM_ERASE_VERIFY 0x05
#define HFM_CALCULATE_DATA_SIGNATURE 0x06
#define HFM_WORD_PROGRAM 0x20
#define HFM_PAGE_ERASE 0x40
#define HFM_MASS_ERASE 0x41
#define HFM_CALCULATE_IFR_BLOCK_SIGNATURE 0x66
/**
* ----------------------------------------------------------------
*/
/** ----------------------------------------------------------------
* Flashing (ref:MC56F801xRM.pdf:159)
* ----------------------------------------------------------------
*/
#define HFM_BASE_ADDR 0x0F400 /** In x: mem. (write to S_FILE_DATA_OFFSET+HFM_BASE_ADDR
* to get data into x: mem.)
*/
/**
* The following are register addresses, not memory
* addresses (though all registers are memory mapped)
*/
#define HFM_CLK_DIV 0x00 /* r/w */
#define HFM_CNFG 0x01 /* r/w */
#define HFM_SECHI 0x03 /* r */
#define HFM_SECLO 0x04 /* r */
#define HFM_PROT 0x10 /* r/w */
#define HFM_PROTB 0x11 /* r/w */
#define HFM_USTAT 0x13 /* r/w */
#define HFM_CMD 0x14 /* r/w */
#define HFM_DATA 0x18 /* r */
#define HFM_OPT1 0x1B /* r */
#define HFM_TSTSIG 0x1D /* r */
#define HFM_EXEC_COMPLETE 0x40
/* User status register (USTAT) masks (MC56F80XXRM.pdf:6.7.5) */
#define HFM_USTAT_MASK_BLANK 0x4
#define HFM_USTAT_MASK_PVIOL_ACCER 0x30
/**
* The value used on for the FM clock is important to prevent flashing errors and to prevent deterioration of the FM.
* This value was calculated using a spreadsheet tool available on the Freescale website under FAQ 25464.
*
*/
#define HFM_CLK_DEFAULT 0x27
/* 0x27 according to freescale cfg, but 0x40 according to freescale spreadsheet... */
#define HFM_FLASH_BASE_ADDR 0x0
#define HFM_SIZE_BYTES 0x4000 /* bytes */
#define HFM_SIZE_WORDS 0x2000 /* words */
#define HFM_SECTOR_SIZE 0x200 /* Size in bytes */
#define HFM_SECTOR_COUNT 0x20
/* A 16K block in pages of 256 words. */
/**
* Writing HFM_LOCK_FLASH to HFM_LOCK_ADDR_L and HFM_LOCK_ADDR_H will enable security on flash after the next reset.
*/
#define HFM_LOCK_FLASH 0xE70A
#define HFM_LOCK_ADDR_L 0x1FF7
#define HFM_LOCK_ADDR_H 0x1FF8
/**
* ----------------------------------------------------------------
*/
/** ----------------------------------------------------------------
* Register Memory Map (eonce_rev.1.0_0208081.pdf:16)
* ----------------------------------------------------------------
*/
#define MC568013_EONCE_OBASE_ADDR 0xFF
/* The following are relative to EONCE_OBASE_ADDR (EONCE_OBASE_ADDR<<16 + ...) */
#define MC568013_EONCE_TX_RX_ADDR 0xFFFE
#define MC568013_EONCE_TX1_RX1_HIGH_ADDR 0xFFFF /* Relative to EONCE_OBASE_ADDR */
#define MC568013_EONCE_OCR 0xFFA0 /* Relative to EONCE_OBASE_ADDR */
/**
* ----------------------------------------------------------------
*/
/** ----------------------------------------------------------------
* SIM addresses & commands (MC56F80xx.h from freescale)
* ----------------------------------------------------------------
*/
#define MC568013_SIM_BASE_ADDR 0xF140
#define MC56803x_2x_SIM_BASE_ADDR 0xF100
#define SIM_CMD_RESET 0x10
/**
* ----------------------------------------------------------------
*/
/**
* ----------------------------------------------------------------
* ERROR codes - enable automatic parsing of output
* ----------------------------------------------------------------
*/
#define DSP5680XX_ERROR_UNKNOWN_OR_ERROR_OPENOCD -100
#define DSP5680XX_ERROR_JTAG_COMM -1
#define DSP5680XX_ERROR_JTAG_RESET -2
#define DSP5680XX_ERROR_JTAG_INVALID_TAP -3
#define DSP5680XX_ERROR_JTAG_DR_LEN_OVERFLOW -4
#define DSP5680XX_ERROR_INVALID_IR_LEN -5
#define DSP5680XX_ERROR_JTAG_TAP_ENABLE_MASTER -6
#define DSP5680XX_ERROR_JTAG_TAP_ENABLE_CORE -7
#define DSP5680XX_ERROR_JTAG_TAP_FIND_MASTER -8
#define DSP5680XX_ERROR_JTAG_TAP_FIND_CORE -9
#define DSP5680XX_ERROR_JTAG_DRSCAN -10
#define DSP5680XX_ERROR_JTAG_IRSCAN -11
#define DSP5680XX_ERROR_ENTER_DEBUG_MODE -12
#define DSP5680XX_ERROR_RESUME -13
#define DSP5680XX_ERROR_WRITE_WITH_TARGET_RUNNING -14
#define DSP5680XX_ERROR_INVALID_DATA_SIZE_UNIT -15
#define DSP5680XX_ERROR_PROTECT_CHECK_INVALID_ARGS -16
#define DSP5680XX_ERROR_FM_BUSY -17
#define DSP5680XX_ERROR_FM_CMD_TIMED_OUT -18
#define DSP5680XX_ERROR_FM_EXEC -19
#define DSP5680XX_ERROR_FM_SET_CLK -20
#define DSP5680XX_ERROR_FLASHING_INVALID_WORD_COUNT -21
#define DSP5680XX_ERROR_FLASHING_CRC -22
#define DSP5680XX_ERROR_FLASHING -23
#define DSP5680XX_ERROR_NOT_IMPLEMENTED_STEP -24
#define DSP5680XX_ERROR_HALT -25
#define DSP5680XX_ERROR_EXIT_DEBUG_MODE -26
#define DSP5680XX_ERROR_TARGET_RUNNING -27
#define DSP5680XX_ERROR_NOT_IN_DEBUG -28
/**
* ----------------------------------------------------------------
*/
struct dsp5680xx_common {
uint32_t stored_pc;
int flush;
bool debug_mode_enabled;
};
extern struct dsp5680xx_common dsp5680xx_context;
static inline struct dsp5680xx_common *target_to_dsp5680xx(struct target
*target)
{
return target->arch_info;
}
/**
* Writes to flash memory.
* Does not check if flash is erased, it's up to the user to erase the flash before running
* this function.
* The flashing algorithm runs from RAM, reading from a register to which this function
* writes to. The algorithm is open loop, there is no control to verify that the FM read
* the register before writing the next data. A closed loop approach was much slower,
* and the current implementation does not fail, and if it did the crc check would detect it,
* allowing to flash again.
*
* @param target
* @param buffer
* @param address Word addressing.
* @param count In bytes.
* @param is_flash_lock
*
* @return
*/
int dsp5680xx_f_wr(struct target *target, uint8_t * buffer, uint32_t address,
uint32_t count, int is_flash_lock);
/**
* The FM has the functionality of checking if the flash array is erased. This function
* executes it. It does not support individual sector analysis.
*
* @param target
* @param erased
* @param sector This parameter is ignored because the FM does not support checking if
* individual sectors are erased.
*
* @return
*/
int dsp5680xx_f_erase_check(struct target *target, uint8_t * erased,
uint32_t sector);
/**
* Erases either a sector or the complete flash array. If either the range first-last covers
* the complete array or if first == 0 and last == 0 then a mass erase command is executed
* on the FM. If not, then individual sectors are erased.
*
* @param target
* @param first
* @param last
*
* @return
*/
int dsp5680xx_f_erase(struct target *target, int first, int last);
/**
* Reads the memory mapped protection register. A 1 implies the sector is protected,
* a 0 implies the sector is not protected.
*
* @param target
* @param protected Data read from the protection register.
*
* @return
*/
int dsp5680xx_f_protect_check(struct target *target, uint16_t * protected);
/**
* Writes the flash security words with a specific value. The chip's security will be
* enabled after the first reset following the execution of this function.
*
* @param target
*
* @return
*/
int dsp5680xx_f_lock(struct target *target);
/**
* Executes a mass erase command. The must be done from the Master tap.
* It is up to the user to select the master tap (jtag tapenable dsp5680xx.chp)
* before running this function.
* The flash array will be unsecured (and erased) after the first reset following
* the execution of this function.
*
* @param target
*
* @return
*/
int dsp5680xx_f_unlock(struct target *target);
#endif /* DSP5680XX_H */

View File

@ -0,0 +1,650 @@
/***************************************************************************
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* Copyright (C) 2007-2010 Øyvind Harboe *
* oyvind.harboe@zylin.com *
* *
* Copyright (C) 2008 by Spencer Oliver *
* spen@spen-soft.co.uk *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "embeddedice.h"
#include "register.h"
/**
* @file
*
* This provides lowlevel glue to the EmbeddedICE (or EmbeddedICE-RT)
* module found on scan chain 2 in ARM7, ARM9, and some other families
* of ARM cores. The module is called "EmbeddedICE-RT" if it has
* monitor mode support.
*
* EmbeddedICE provides basic watchpoint/breakpoint hardware and a Debug
* Communications Channel (DCC) used to read or write 32-bit words to
* OpenOCD-aware code running on the target CPU.
* Newer modules also include vector catch hardware. Some versions
* support hardware single-stepping, "monitor mode" debug (which is not
* currently supported by OpenOCD), or extended reporting on why the
* core entered debug mode.
*/
static int embeddedice_set_reg_w_exec(struct reg *reg, uint8_t *buf);
/*
* From: ARM9E-S TRM, DDI 0165, table C-4 (and similar, for other cores)
*/
static const struct {
char *name;
unsigned short addr;
unsigned short width;
} eice_regs[] = {
[EICE_DBG_CTRL] = {
.name = "debug_ctrl",
.addr = 0,
/* width is assigned based on EICE version */
},
[EICE_DBG_STAT] = {
.name = "debug_status",
.addr = 1,
/* width is assigned based on EICE version */
},
[EICE_COMMS_CTRL] = {
.name = "comms_ctrl",
.addr = 4,
.width = 6,
},
[EICE_COMMS_DATA] = {
.name = "comms_data",
.addr = 5,
.width = 32,
},
[EICE_W0_ADDR_VALUE] = {
.name = "watch_0_addr_value",
.addr = 8,
.width = 32,
},
[EICE_W0_ADDR_MASK] = {
.name = "watch_0_addr_mask",
.addr = 9,
.width = 32,
},
[EICE_W0_DATA_VALUE] = {
.name = "watch_0_data_value",
.addr = 10,
.width = 32,
},
[EICE_W0_DATA_MASK] = {
.name = "watch_0_data_mask",
.addr = 11,
.width = 32,
},
[EICE_W0_CONTROL_VALUE] = {
.name = "watch_0_control_value",
.addr = 12,
.width = 9,
},
[EICE_W0_CONTROL_MASK] = {
.name = "watch_0_control_mask",
.addr = 13,
.width = 8,
},
[EICE_W1_ADDR_VALUE] = {
.name = "watch_1_addr_value",
.addr = 16,
.width = 32,
},
[EICE_W1_ADDR_MASK] = {
.name = "watch_1_addr_mask",
.addr = 17,
.width = 32,
},
[EICE_W1_DATA_VALUE] = {
.name = "watch_1_data_value",
.addr = 18,
.width = 32,
},
[EICE_W1_DATA_MASK] = {
.name = "watch_1_data_mask",
.addr = 19,
.width = 32,
},
[EICE_W1_CONTROL_VALUE] = {
.name = "watch_1_control_value",
.addr = 20,
.width = 9,
},
[EICE_W1_CONTROL_MASK] = {
.name = "watch_1_control_mask",
.addr = 21,
.width = 8,
},
/* vector_catch isn't always present */
[EICE_VEC_CATCH] = {
.name = "vector_catch",
.addr = 2,
.width = 8,
},
};
static int embeddedice_get_reg(struct reg *reg)
{
int retval = embeddedice_read_reg(reg);
if (retval != ERROR_OK) {
LOG_ERROR("error queueing EmbeddedICE register read");
return retval;
}
retval = jtag_execute_queue();
if (retval != ERROR_OK)
LOG_ERROR("EmbeddedICE register read failed");
return retval;
}
static const struct reg_arch_type eice_reg_type = {
.get = embeddedice_get_reg,
.set = embeddedice_set_reg_w_exec,
};
/**
* Probe EmbeddedICE module and set up local records of its registers.
* Different versions of the modules have different capabilities, such as
* hardware support for vector_catch, single stepping, and monitor mode.
*/
struct reg_cache *embeddedice_build_reg_cache(struct target *target,
struct arm7_9_common *arm7_9)
{
int retval;
struct reg_cache *reg_cache = malloc(sizeof(struct reg_cache));
struct reg *reg_list = NULL;
struct embeddedice_reg *arch_info = NULL;
struct arm_jtag *jtag_info = &arm7_9->jtag_info;
int num_regs = ARRAY_SIZE(eice_regs);
int i;
int eice_version = 0;
/* vector_catch isn't always present */
if (!arm7_9->has_vector_catch)
num_regs--;
/* the actual registers are kept in two arrays */
reg_list = calloc(num_regs, sizeof(struct reg));
arch_info = calloc(num_regs, sizeof(struct embeddedice_reg));
/* fill in values for the reg cache */
reg_cache->name = "EmbeddedICE registers";
reg_cache->next = NULL;
reg_cache->reg_list = reg_list;
reg_cache->num_regs = num_regs;
/* FIXME the second watchpoint unit on Feroceon and Dragonite
* seems not to work ... we should have a way to not set up
* its four registers here!
*/
/* set up registers */
for (i = 0; i < num_regs; i++) {
reg_list[i].name = eice_regs[i].name;
reg_list[i].size = eice_regs[i].width;
reg_list[i].dirty = 0;
reg_list[i].valid = 0;
reg_list[i].value = calloc(1, 4);
reg_list[i].arch_info = &arch_info[i];
reg_list[i].type = &eice_reg_type;
arch_info[i].addr = eice_regs[i].addr;
arch_info[i].jtag_info = jtag_info;
}
/* identify EmbeddedICE version by reading DCC control register */
embeddedice_read_reg(&reg_list[EICE_COMMS_CTRL]);
retval = jtag_execute_queue();
if (retval != ERROR_OK) {
for (i = 0; i < num_regs; i++)
free(reg_list[i].value);
free(reg_list);
free(reg_cache);
free(arch_info);
return NULL;
}
eice_version = buf_get_u32(reg_list[EICE_COMMS_CTRL].value, 28, 4);
LOG_INFO("Embedded ICE version %d", eice_version);
switch (eice_version) {
case 1:
/* ARM7TDMI r3, ARM7TDMI-S r3
*
* REVISIT docs say ARM7TDMI-S r4 uses version 1 but
* that it has 6-bit CTRL and 5-bit STAT... doc bug?
* ARM7TDMI r4 docs say EICE v4.
*/
reg_list[EICE_DBG_CTRL].size = 3;
reg_list[EICE_DBG_STAT].size = 5;
break;
case 2:
/* ARM9TDMI */
reg_list[EICE_DBG_CTRL].size = 4;
reg_list[EICE_DBG_STAT].size = 5;
arm7_9->has_single_step = 1;
break;
case 3:
LOG_ERROR("EmbeddedICE v%d handling might be broken",
eice_version);
reg_list[EICE_DBG_CTRL].size = 6;
reg_list[EICE_DBG_STAT].size = 5;
arm7_9->has_single_step = 1;
arm7_9->has_monitor_mode = 1;
break;
case 4:
/* ARM7TDMI r4 */
reg_list[EICE_DBG_CTRL].size = 6;
reg_list[EICE_DBG_STAT].size = 5;
arm7_9->has_monitor_mode = 1;
break;
case 5:
/* ARM9E-S rev 1 */
reg_list[EICE_DBG_CTRL].size = 6;
reg_list[EICE_DBG_STAT].size = 5;
arm7_9->has_single_step = 1;
arm7_9->has_monitor_mode = 1;
break;
case 6:
/* ARM7EJ-S, ARM9E-S rev 2, ARM9EJ-S */
reg_list[EICE_DBG_CTRL].size = 6;
reg_list[EICE_DBG_STAT].size = 10;
/* DBG_STAT has MOE bits */
arm7_9->has_monitor_mode = 1;
break;
case 7:
LOG_ERROR("EmbeddedICE v%d handling might be broken",
eice_version);
reg_list[EICE_DBG_CTRL].size = 6;
reg_list[EICE_DBG_STAT].size = 5;
arm7_9->has_monitor_mode = 1;
break;
default:
/*
* The Feroceon implementation has the version number
* in some unusual bits. Let feroceon.c validate it
* and do the appropriate setup itself.
*/
if (strcmp(target_type_name(target), "feroceon") == 0 ||
strcmp(target_type_name(target), "dragonite") == 0)
break;
LOG_ERROR("unknown EmbeddedICE version "
"(comms ctrl: 0x%8.8" PRIx32 ")",
buf_get_u32(reg_list[EICE_COMMS_CTRL].value, 0, 32));
}
/* On Feroceon and Dragonite the second unit is seemingly missing. */
LOG_INFO("%s: hardware has %d breakpoint/watchpoint unit%s",
target_name(target), arm7_9->wp_available_max,
(arm7_9->wp_available_max != 1) ? "s" : "");
return reg_cache;
}
/**
* Initialize EmbeddedICE module, if needed.
*/
int embeddedice_setup(struct target *target)
{
int retval;
struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
/* Explicitly disable monitor mode. For now we only support halting
* debug ... we don't know how to talk with a resident debug monitor
* that manages break requests. ARM's "Angel Debug Monitor" is one
* common example of such code.
*/
if (arm7_9->has_monitor_mode) {
struct reg *dbg_ctrl = &arm7_9->eice_cache->reg_list[EICE_DBG_CTRL];
embeddedice_read_reg(dbg_ctrl);
retval = jtag_execute_queue();
if (retval != ERROR_OK)
return retval;
buf_set_u32(dbg_ctrl->value, 4, 1, 0);
embeddedice_set_reg_w_exec(dbg_ctrl, dbg_ctrl->value);
}
return jtag_execute_queue();
}
/**
* Queue a read for an EmbeddedICE register into the register cache,
* optionally checking the value read.
* Note that at this level, all registers are 32 bits wide.
*/
int embeddedice_read_reg_w_check(struct reg *reg,
uint8_t *check_value, uint8_t *check_mask)
{
struct embeddedice_reg *ice_reg = reg->arch_info;
uint8_t reg_addr = ice_reg->addr & 0x1f;
struct scan_field fields[3];
uint8_t field1_out[1];
uint8_t field2_out[1];
int retval;
retval = arm_jtag_scann(ice_reg->jtag_info, 0x2, TAP_IDLE);
if (retval != ERROR_OK)
return retval;
retval = arm_jtag_set_instr(ice_reg->jtag_info,
ice_reg->jtag_info->intest_instr, NULL, TAP_IDLE);
if (retval != ERROR_OK)
return retval;
/* bits 31:0 -- data (ignored here) */
fields[0].num_bits = 32;
fields[0].out_value = reg->value;
fields[0].in_value = NULL;
fields[0].check_value = NULL;
fields[0].check_mask = NULL;
/* bits 36:32 -- register */
fields[1].num_bits = 5;
fields[1].out_value = field1_out;
field1_out[0] = reg_addr;
fields[1].in_value = NULL;
fields[1].check_value = NULL;
fields[1].check_mask = NULL;
/* bit 37 -- 0/read */
fields[2].num_bits = 1;
fields[2].out_value = field2_out;
field2_out[0] = 0;
fields[2].in_value = NULL;
fields[2].check_value = NULL;
fields[2].check_mask = NULL;
/* traverse Update-DR, setting address for the next read */
jtag_add_dr_scan(ice_reg->jtag_info->tap, 3, fields, TAP_IDLE);
/* bits 31:0 -- the data we're reading (and maybe checking) */
fields[0].in_value = reg->value;
fields[0].check_value = check_value;
fields[0].check_mask = check_mask;
/* when reading the DCC data register, leaving the address field set to
* EICE_COMMS_DATA would read the register twice
* reading the control register is safe
*/
field1_out[0] = eice_regs[EICE_COMMS_CTRL].addr;
/* traverse Update-DR, reading but with no other side effects */
jtag_add_dr_scan_check(ice_reg->jtag_info->tap, 3, fields, TAP_IDLE);
return ERROR_OK;
}
/**
* Receive a block of size 32-bit words from the DCC.
* We assume the target is always going to be fast enough (relative to
* the JTAG clock) that the debugger won't need to poll the handshake
* bit. The JTAG clock is usually at least six times slower than the
* functional clock, so the 50+ JTAG clocks needed to receive the word
* allow hundreds of instruction cycles (per word) in the target.
*/
int embeddedice_receive(struct arm_jtag *jtag_info, uint32_t *data, uint32_t size)
{
struct scan_field fields[3];
uint8_t field1_out[1];
uint8_t field2_out[1];
int retval;
retval = arm_jtag_scann(jtag_info, 0x2, TAP_IDLE);
if (retval != ERROR_OK)
return retval;
retval = arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL, TAP_IDLE);
if (retval != ERROR_OK)
return retval;
fields[0].num_bits = 32;
fields[0].out_value = NULL;
fields[0].in_value = NULL;
fields[1].num_bits = 5;
fields[1].out_value = field1_out;
field1_out[0] = eice_regs[EICE_COMMS_DATA].addr;
fields[1].in_value = NULL;
fields[2].num_bits = 1;
fields[2].out_value = field2_out;
field2_out[0] = 0;
fields[2].in_value = NULL;
jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE);
while (size > 0) {
/* when reading the last item, set the register address to the DCC control reg,
* to avoid reading additional data from the DCC data reg
*/
if (size == 1)
field1_out[0] = eice_regs[EICE_COMMS_CTRL].addr;
fields[0].in_value = (uint8_t *)data;
jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE);
jtag_add_callback(arm_le_to_h_u32, (jtag_callback_data_t)data);
data++;
size--;
}
return jtag_execute_queue();
}
/**
* Queue a read for an EmbeddedICE register into the register cache,
* not checking the value read.
*/
int embeddedice_read_reg(struct reg *reg)
{
return embeddedice_read_reg_w_check(reg, NULL, NULL);
}
/**
* Queue a write for an EmbeddedICE register, updating the register cache.
* Uses embeddedice_write_reg().
*/
void embeddedice_set_reg(struct reg *reg, uint32_t value)
{
embeddedice_write_reg(reg, value);
buf_set_u32(reg->value, 0, reg->size, value);
reg->valid = 1;
reg->dirty = 0;
}
/**
* Write an EmbeddedICE register, updating the register cache.
* Uses embeddedice_set_reg(); not queued.
*/
static int embeddedice_set_reg_w_exec(struct reg *reg, uint8_t *buf)
{
int retval;
embeddedice_set_reg(reg, buf_get_u32(buf, 0, reg->size));
retval = jtag_execute_queue();
if (retval != ERROR_OK)
LOG_ERROR("register write failed");
return retval;
}
/**
* Queue a write for an EmbeddedICE register, bypassing the register cache.
*/
void embeddedice_write_reg(struct reg *reg, uint32_t value)
{
struct embeddedice_reg *ice_reg = reg->arch_info;
LOG_DEBUG("%i: 0x%8.8" PRIx32 "", ice_reg->addr, value);
arm_jtag_scann(ice_reg->jtag_info, 0x2, TAP_IDLE);
arm_jtag_set_instr(ice_reg->jtag_info, ice_reg->jtag_info->intest_instr, NULL, TAP_IDLE);
uint8_t reg_addr = ice_reg->addr & 0x1f;
embeddedice_write_reg_inner(ice_reg->jtag_info->tap, reg_addr, value);
}
/**
* Queue a write for an EmbeddedICE register, using cached value.
* Uses embeddedice_write_reg().
*/
void embeddedice_store_reg(struct reg *reg)
{
embeddedice_write_reg(reg, buf_get_u32(reg->value, 0, reg->size));
}
/**
* Send a block of size 32-bit words to the DCC.
* We assume the target is always going to be fast enough (relative to
* the JTAG clock) that the debugger won't need to poll the handshake
* bit. The JTAG clock is usually at least six times slower than the
* functional clock, so the 50+ JTAG clocks needed to receive the word
* allow hundreds of instruction cycles (per word) in the target.
*/
int embeddedice_send(struct arm_jtag *jtag_info, uint32_t *data, uint32_t size)
{
struct scan_field fields[3];
uint8_t field0_out[4];
uint8_t field1_out[1];
uint8_t field2_out[1];
int retval;
retval = arm_jtag_scann(jtag_info, 0x2, TAP_IDLE);
if (retval != ERROR_OK)
return retval;
retval = arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL, TAP_IDLE);
if (retval != ERROR_OK)
return retval;
fields[0].num_bits = 32;
fields[0].out_value = field0_out;
fields[0].in_value = NULL;
fields[1].num_bits = 5;
fields[1].out_value = field1_out;
field1_out[0] = eice_regs[EICE_COMMS_DATA].addr;
fields[1].in_value = NULL;
fields[2].num_bits = 1;
fields[2].out_value = field2_out;
field2_out[0] = 1;
fields[2].in_value = NULL;
while (size > 0) {
buf_set_u32(field0_out, 0, 32, *data);
jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE);
data++;
size--;
}
/* call to jtag_execute_queue() intentionally omitted */
return ERROR_OK;
}
/**
* Poll DCC control register until read or write handshake completes.
*/
int embeddedice_handshake(struct arm_jtag *jtag_info, int hsbit, uint32_t timeout)
{
struct scan_field fields[3];
uint8_t field0_in[4];
uint8_t field1_out[1];
uint8_t field2_out[1];
int retval;
uint32_t hsact;
struct timeval lap;
struct timeval now;
if (hsbit == EICE_COMM_CTRL_WBIT)
hsact = 1;
else if (hsbit == EICE_COMM_CTRL_RBIT)
hsact = 0;
else {
LOG_ERROR("Invalid arguments");
return ERROR_COMMAND_SYNTAX_ERROR;
}
retval = arm_jtag_scann(jtag_info, 0x2, TAP_IDLE);
if (retval != ERROR_OK)
return retval;
retval = arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL, TAP_IDLE);
if (retval != ERROR_OK)
return retval;
fields[0].num_bits = 32;
fields[0].out_value = NULL;
fields[0].in_value = field0_in;
fields[1].num_bits = 5;
fields[1].out_value = field1_out;
field1_out[0] = eice_regs[EICE_COMMS_DATA].addr;
fields[1].in_value = NULL;
fields[2].num_bits = 1;
fields[2].out_value = field2_out;
field2_out[0] = 0;
fields[2].in_value = NULL;
jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE);
gettimeofday(&lap, NULL);
do {
jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE);
retval = jtag_execute_queue();
if (retval != ERROR_OK)
return retval;
if (buf_get_u32(field0_in, hsbit, 1) == hsact)
return ERROR_OK;
gettimeofday(&now, NULL);
} while ((uint32_t)((now.tv_sec - lap.tv_sec) * 1000
+ (now.tv_usec - lap.tv_usec) / 1000) <= timeout);
LOG_ERROR("embeddedice handshake timeout");
return ERROR_TARGET_TIMEOUT;
}
#ifndef HAVE_JTAG_MINIDRIVER_H
/**
* This is an inner loop of the open loop DCC write of data to target
*/
void embeddedice_write_dcc(struct jtag_tap *tap,
int reg_addr, const uint8_t *buffer, int little, int count)
{
int i;
for (i = 0; i < count; i++) {
embeddedice_write_reg_inner(tap, reg_addr,
fast_target_buffer_get_u32(buffer, little));
buffer += 4;
}
}
#else
/* provided by minidriver */
#endif

View File

@ -0,0 +1,127 @@
/***************************************************************************
* Copyright (C) 2005, 2006 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* Copyright (C) 2007,2008 Øyvind Harboe *
* oyvind.harboe@zylin.com *
* *
* Copyright (C) 2008 by Spencer Oliver *
* spen@spen-soft.co.uk *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef EMBEDDED_ICE_H
#define EMBEDDED_ICE_H
#include "arm7_9_common.h"
enum {
EICE_DBG_CTRL = 0,
EICE_DBG_STAT = 1,
EICE_COMMS_CTRL = 2,
EICE_COMMS_DATA = 3,
EICE_W0_ADDR_VALUE = 4,
EICE_W0_ADDR_MASK = 5,
EICE_W0_DATA_VALUE = 6,
EICE_W0_DATA_MASK = 7,
EICE_W0_CONTROL_VALUE = 8,
EICE_W0_CONTROL_MASK = 9,
EICE_W1_ADDR_VALUE = 10,
EICE_W1_ADDR_MASK = 11,
EICE_W1_DATA_VALUE = 12,
EICE_W1_DATA_MASK = 13,
EICE_W1_CONTROL_VALUE = 14,
EICE_W1_CONTROL_MASK = 15,
EICE_VEC_CATCH = 16
};
enum {
EICE_DBG_CONTROL_ICEDIS = 5,
EICE_DBG_CONTROL_MONEN = 4,
EICE_DBG_CONTROL_INTDIS = 2,
EICE_DBG_CONTROL_DBGRQ = 1,
EICE_DBG_CONTROL_DBGACK = 0,
};
enum {
EICE_DBG_STATUS_IJBIT = 5,
EICE_DBG_STATUS_ITBIT = 4,
EICE_DBG_STATUS_SYSCOMP = 3,
EICE_DBG_STATUS_IFEN = 2,
EICE_DBG_STATUS_DBGRQ = 1,
EICE_DBG_STATUS_DBGACK = 0
};
enum {
EICE_W_CTRL_ENABLE = 0x100,
EICE_W_CTRL_RANGE = 0x80,
EICE_W_CTRL_CHAIN = 0x40,
EICE_W_CTRL_EXTERN = 0x20,
EICE_W_CTRL_nTRANS = 0x10,
EICE_W_CTRL_nOPC = 0x8,
EICE_W_CTRL_MAS = 0x6,
EICE_W_CTRL_ITBIT = 0x2,
EICE_W_CTRL_nRW = 0x1
};
enum {
EICE_COMM_CTRL_WBIT = 1,
EICE_COMM_CTRL_RBIT = 0
};
struct embeddedice_reg {
int addr;
struct arm_jtag *jtag_info;
};
struct reg_cache *embeddedice_build_reg_cache(struct target *target,
struct arm7_9_common *arm7_9);
int embeddedice_setup(struct target *target);
int embeddedice_read_reg(struct reg *reg);
int embeddedice_read_reg_w_check(struct reg *reg,
uint8_t *check_value, uint8_t *check_mask);
void embeddedice_write_reg(struct reg *reg, uint32_t value);
void embeddedice_store_reg(struct reg *reg);
void embeddedice_set_reg(struct reg *reg, uint32_t value);
int embeddedice_receive(struct arm_jtag *jtag_info, uint32_t *data, uint32_t size);
int embeddedice_send(struct arm_jtag *jtag_info, uint32_t *data, uint32_t size);
int embeddedice_handshake(struct arm_jtag *jtag_info, int hsbit, uint32_t timeout);
/* If many embeddedice_write_reg() follow eachother, then the >1 invocations can be
* this faster version of embeddedice_write_reg
*/
static inline void embeddedice_write_reg_inner(struct jtag_tap *tap, int reg_addr, uint32_t value)
{
static const int embeddedice_num_bits[] = {32, 6};
uint32_t values[2];
values[0] = value;
values[1] = (1 << 5) | reg_addr;
jtag_add_dr_out(tap, 2, embeddedice_num_bits, values, TAP_IDLE);
}
void embeddedice_write_dcc(struct jtag_tap *tap, int reg_addr, const uint8_t *buffer,
int little, int count);
#endif /* EMBEDDED_ICE_H */

View File

@ -0,0 +1,706 @@
/***************************************************************************
* Copyright (C) 2007 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "arm.h"
#include "etm.h"
#include "etb.h"
#include "register.h"
static char *etb_reg_list[] = {
"ETB_identification",
"ETB_ram_depth",
"ETB_ram_width",
"ETB_status",
"ETB_ram_data",
"ETB_ram_read_pointer",
"ETB_ram_write_pointer",
"ETB_trigger_counter",
"ETB_control",
};
static int etb_get_reg(struct reg *reg);
static int etb_set_instr(struct etb *etb, uint32_t new_instr)
{
struct jtag_tap *tap;
tap = etb->tap;
if (tap == NULL)
return ERROR_FAIL;
if (buf_get_u32(tap->cur_instr, 0, tap->ir_length) != new_instr) {
struct scan_field field;
field.num_bits = tap->ir_length;
void *t = calloc(DIV_ROUND_UP(field.num_bits, 8), 1);
field.out_value = t;
buf_set_u32(t, 0, field.num_bits, new_instr);
field.in_value = NULL;
jtag_add_ir_scan(tap, &field, TAP_IDLE);
free(t);
}
return ERROR_OK;
}
static int etb_scann(struct etb *etb, uint32_t new_scan_chain)
{
if (etb->cur_scan_chain != new_scan_chain) {
struct scan_field field;
field.num_bits = 5;
void *t = calloc(DIV_ROUND_UP(field.num_bits, 8), 1);
field.out_value = t;
buf_set_u32(t, 0, field.num_bits, new_scan_chain);
field.in_value = NULL;
/* select INTEST instruction */
etb_set_instr(etb, 0x2);
jtag_add_dr_scan(etb->tap, 1, &field, TAP_IDLE);
etb->cur_scan_chain = new_scan_chain;
free(t);
}
return ERROR_OK;
}
static int etb_read_reg_w_check(struct reg *, uint8_t *, uint8_t *);
static int etb_set_reg_w_exec(struct reg *, uint8_t *);
static int etb_read_reg(struct reg *reg)
{
return etb_read_reg_w_check(reg, NULL, NULL);
}
static int etb_get_reg(struct reg *reg)
{
int retval;
retval = etb_read_reg(reg);
if (retval != ERROR_OK) {
LOG_ERROR("BUG: error scheduling ETB register read");
return retval;
}
retval = jtag_execute_queue();
if (retval != ERROR_OK) {
LOG_ERROR("ETB register read failed");
return retval;
}
return ERROR_OK;
}
static const struct reg_arch_type etb_reg_type = {
.get = etb_get_reg,
.set = etb_set_reg_w_exec,
};
struct reg_cache *etb_build_reg_cache(struct etb *etb)
{
struct reg_cache *reg_cache = malloc(sizeof(struct reg_cache));
struct reg *reg_list = NULL;
struct etb_reg *arch_info = NULL;
int num_regs = 9;
int i;
/* the actual registers are kept in two arrays */
reg_list = calloc(num_regs, sizeof(struct reg));
arch_info = calloc(num_regs, sizeof(struct etb_reg));
/* fill in values for the reg cache */
reg_cache->name = "etb registers";
reg_cache->next = NULL;
reg_cache->reg_list = reg_list;
reg_cache->num_regs = num_regs;
/* set up registers */
for (i = 0; i < num_regs; i++) {
reg_list[i].name = etb_reg_list[i];
reg_list[i].size = 32;
reg_list[i].dirty = 0;
reg_list[i].valid = 0;
reg_list[i].value = calloc(1, 4);
reg_list[i].arch_info = &arch_info[i];
reg_list[i].type = &etb_reg_type;
reg_list[i].size = 32;
arch_info[i].addr = i;
arch_info[i].etb = etb;
}
return reg_cache;
}
static void etb_getbuf(jtag_callback_data_t arg)
{
uint8_t *in = (uint8_t *)arg;
*((uint32_t *)arg) = buf_get_u32(in, 0, 32);
}
static int etb_read_ram(struct etb *etb, uint32_t *data, int num_frames)
{
struct scan_field fields[3];
int i;
etb_scann(etb, 0x0);
etb_set_instr(etb, 0xc);
fields[0].num_bits = 32;
fields[0].out_value = NULL;
fields[0].in_value = NULL;
fields[1].num_bits = 7;
uint8_t temp1;
fields[1].out_value = &temp1;
buf_set_u32(&temp1, 0, 7, 4);
fields[1].in_value = NULL;
fields[2].num_bits = 1;
uint8_t temp2;
fields[2].out_value = &temp2;
buf_set_u32(&temp2, 0, 1, 0);
fields[2].in_value = NULL;
jtag_add_dr_scan(etb->tap, 3, fields, TAP_IDLE);
for (i = 0; i < num_frames; i++) {
/* ensure nR/W reamins set to read */
buf_set_u32(&temp2, 0, 1, 0);
/* address remains set to 0x4 (RAM data) until we read the last frame */
if (i < num_frames - 1)
buf_set_u32(&temp1, 0, 7, 4);
else
buf_set_u32(&temp1, 0, 7, 0);
fields[0].in_value = (uint8_t *)(data + i);
jtag_add_dr_scan(etb->tap, 3, fields, TAP_IDLE);
jtag_add_callback(etb_getbuf, (jtag_callback_data_t)(data + i));
}
jtag_execute_queue();
return ERROR_OK;
}
static int etb_read_reg_w_check(struct reg *reg,
uint8_t *check_value, uint8_t *check_mask)
{
struct etb_reg *etb_reg = reg->arch_info;
uint8_t reg_addr = etb_reg->addr & 0x7f;
struct scan_field fields[3];
LOG_DEBUG("%i", (int)(etb_reg->addr));
etb_scann(etb_reg->etb, 0x0);
etb_set_instr(etb_reg->etb, 0xc);
fields[0].num_bits = 32;
fields[0].out_value = reg->value;
fields[0].in_value = NULL;
fields[0].check_value = NULL;
fields[0].check_mask = NULL;
fields[1].num_bits = 7;
uint8_t temp1;
fields[1].out_value = &temp1;
buf_set_u32(&temp1, 0, 7, reg_addr);
fields[1].in_value = NULL;
fields[1].check_value = NULL;
fields[1].check_mask = NULL;
fields[2].num_bits = 1;
uint8_t temp2;
fields[2].out_value = &temp2;
buf_set_u32(&temp2, 0, 1, 0);
fields[2].in_value = NULL;
fields[2].check_value = NULL;
fields[2].check_mask = NULL;
jtag_add_dr_scan(etb_reg->etb->tap, 3, fields, TAP_IDLE);
/* read the identification register in the second run, to make sure we
* don't read the ETB data register twice, skipping every second entry
*/
buf_set_u32(&temp1, 0, 7, 0x0);
fields[0].in_value = reg->value;
fields[0].check_value = check_value;
fields[0].check_mask = check_mask;
jtag_add_dr_scan_check(etb_reg->etb->tap, 3, fields, TAP_IDLE);
return ERROR_OK;
}
static int etb_write_reg(struct reg *, uint32_t);
static int etb_set_reg(struct reg *reg, uint32_t value)
{
int retval;
retval = etb_write_reg(reg, value);
if (retval != ERROR_OK) {
LOG_ERROR("BUG: error scheduling ETB register write");
return retval;
}
buf_set_u32(reg->value, 0, reg->size, value);
reg->valid = 1;
reg->dirty = 0;
return ERROR_OK;
}
static int etb_set_reg_w_exec(struct reg *reg, uint8_t *buf)
{
int retval;
etb_set_reg(reg, buf_get_u32(buf, 0, reg->size));
retval = jtag_execute_queue();
if (retval != ERROR_OK) {
LOG_ERROR("ETB: register write failed");
return retval;
}
return ERROR_OK;
}
static int etb_write_reg(struct reg *reg, uint32_t value)
{
struct etb_reg *etb_reg = reg->arch_info;
uint8_t reg_addr = etb_reg->addr & 0x7f;
struct scan_field fields[3];
LOG_DEBUG("%i: 0x%8.8" PRIx32 "", (int)(etb_reg->addr), value);
etb_scann(etb_reg->etb, 0x0);
etb_set_instr(etb_reg->etb, 0xc);
fields[0].num_bits = 32;
uint8_t temp0[4];
fields[0].out_value = temp0;
buf_set_u32(&temp0, 0, 32, value);
fields[0].in_value = NULL;
fields[1].num_bits = 7;
uint8_t temp1;
fields[1].out_value = &temp1;
buf_set_u32(&temp1, 0, 7, reg_addr);
fields[1].in_value = NULL;
fields[2].num_bits = 1;
uint8_t temp2;
fields[2].out_value = &temp2;
buf_set_u32(&temp2, 0, 1, 1);
fields[2].in_value = NULL;
jtag_add_dr_scan(etb_reg->etb->tap, 3, fields, TAP_IDLE);
return ERROR_OK;
}
COMMAND_HANDLER(handle_etb_config_command)
{
struct target *target;
struct jtag_tap *tap;
struct arm *arm;
if (CMD_ARGC != 2)
return ERROR_COMMAND_SYNTAX_ERROR;
target = get_target(CMD_ARGV[0]);
if (!target) {
LOG_ERROR("ETB: target '%s' not defined", CMD_ARGV[0]);
return ERROR_FAIL;
}
arm = target_to_arm(target);
if (!is_arm(arm)) {
command_print(CMD_CTX, "ETB: '%s' isn't an ARM", CMD_ARGV[0]);
return ERROR_FAIL;
}
tap = jtag_tap_by_string(CMD_ARGV[1]);
if (tap == NULL) {
command_print(CMD_CTX, "ETB: TAP %s does not exist", CMD_ARGV[1]);
return ERROR_FAIL;
}
if (arm->etm) {
struct etb *etb = malloc(sizeof(struct etb));
arm->etm->capture_driver_priv = etb;
etb->tap = tap;
etb->cur_scan_chain = 0xffffffff;
etb->reg_cache = NULL;
etb->ram_width = 0;
etb->ram_depth = 0;
} else {
LOG_ERROR("ETM: target has no ETM defined, ETB left unconfigured");
return ERROR_FAIL;
}
return ERROR_OK;
}
COMMAND_HANDLER(handle_etb_trigger_percent_command)
{
struct target *target;
struct arm *arm;
struct etm_context *etm;
struct etb *etb;
target = get_current_target(CMD_CTX);
arm = target_to_arm(target);
if (!is_arm(arm)) {
command_print(CMD_CTX, "ETB: current target isn't an ARM");
return ERROR_FAIL;
}
etm = arm->etm;
if (!etm) {
command_print(CMD_CTX, "ETB: target has no ETM configured");
return ERROR_FAIL;
}
if (etm->capture_driver != &etb_capture_driver) {
command_print(CMD_CTX, "ETB: target not using ETB");
return ERROR_FAIL;
}
etb = arm->etm->capture_driver_priv;
if (CMD_ARGC > 0) {
uint32_t new_value;
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], new_value);
if ((new_value < 2) || (new_value > 100))
command_print(CMD_CTX,
"valid percentages are 2%% to 100%%");
else
etb->trigger_percent = (unsigned) new_value;
}
command_print(CMD_CTX, "%d percent of tracebuffer fills after trigger",
etb->trigger_percent);
return ERROR_OK;
}
static const struct command_registration etb_config_command_handlers[] = {
{
/* NOTE: with ADIv5, ETBs are accessed using DAP operations,
* possibly over SWD, not through separate TAPs...
*/
.name = "config",
.handler = handle_etb_config_command,
.mode = COMMAND_CONFIG,
.help = "Associate ETB with target and JTAG TAP.",
.usage = "target tap",
},
{
.name = "trigger_percent",
.handler = handle_etb_trigger_percent_command,
.mode = COMMAND_EXEC,
.help = "Set percent of trace buffer to be filled "
"after the trigger occurs (2..100).",
.usage = "[percent]",
},
COMMAND_REGISTRATION_DONE
};
static const struct command_registration etb_command_handlers[] = {
{
.name = "etb",
.mode = COMMAND_ANY,
.help = "Emebdded Trace Buffer command group",
.chain = etb_config_command_handlers,
},
COMMAND_REGISTRATION_DONE
};
static int etb_init(struct etm_context *etm_ctx)
{
struct etb *etb = etm_ctx->capture_driver_priv;
etb->etm_ctx = etm_ctx;
/* identify ETB RAM depth and width */
etb_read_reg(&etb->reg_cache->reg_list[ETB_RAM_DEPTH]);
etb_read_reg(&etb->reg_cache->reg_list[ETB_RAM_WIDTH]);
jtag_execute_queue();
etb->ram_depth = buf_get_u32(etb->reg_cache->reg_list[ETB_RAM_DEPTH].value, 0, 32);
etb->ram_width = buf_get_u32(etb->reg_cache->reg_list[ETB_RAM_WIDTH].value, 0, 32);
etb->trigger_percent = 50;
return ERROR_OK;
}
static trace_status_t etb_status(struct etm_context *etm_ctx)
{
struct etb *etb = etm_ctx->capture_driver_priv;
struct reg *control = &etb->reg_cache->reg_list[ETB_CTRL];
struct reg *status = &etb->reg_cache->reg_list[ETB_STATUS];
trace_status_t retval = 0;
int etb_timeout = 100;
etb->etm_ctx = etm_ctx;
/* read control and status registers */
etb_read_reg(control);
etb_read_reg(status);
jtag_execute_queue();
/* See if it's (still) active */
retval = buf_get_u32(control->value, 0, 1) ? TRACE_RUNNING : TRACE_IDLE;
/* check Full bit to identify wraparound/overflow */
if (buf_get_u32(status->value, 0, 1) == 1)
retval |= TRACE_OVERFLOWED;
/* check Triggered bit to identify trigger condition */
if (buf_get_u32(status->value, 1, 1) == 1)
retval |= TRACE_TRIGGERED;
/* check AcqComp to see if trigger counter dropped to zero */
if (buf_get_u32(status->value, 2, 1) == 1) {
/* wait for DFEmpty */
while (etb_timeout-- && buf_get_u32(status->value, 3, 1) == 0)
etb_get_reg(status);
if (etb_timeout == 0)
LOG_ERROR("ETB: DFEmpty won't go high, status 0x%02x",
(unsigned) buf_get_u32(status->value, 0, 4));
if (!(etm_ctx->capture_status & TRACE_TRIGGERED))
LOG_WARNING("ETB: trace complete without triggering?");
retval |= TRACE_COMPLETED;
}
/* NOTE: using a trigger is optional; and at least ETB11 has a mode
* where it can ignore the trigger counter.
*/
/* update recorded state */
etm_ctx->capture_status = retval;
return retval;
}
static int etb_read_trace(struct etm_context *etm_ctx)
{
struct etb *etb = etm_ctx->capture_driver_priv;
int first_frame = 0;
int num_frames = etb->ram_depth;
uint32_t *trace_data = NULL;
int i, j;
etb_read_reg(&etb->reg_cache->reg_list[ETB_STATUS]);
etb_read_reg(&etb->reg_cache->reg_list[ETB_RAM_WRITE_POINTER]);
jtag_execute_queue();
/* check if we overflowed, and adjust first frame of the trace accordingly
* if we didn't overflow, read only up to the frame that would be written next,
* i.e. don't read invalid entries
*/
if (buf_get_u32(etb->reg_cache->reg_list[ETB_STATUS].value, 0, 1))
first_frame = buf_get_u32(etb->reg_cache->reg_list[ETB_RAM_WRITE_POINTER].value,
0,
32);
else
num_frames = buf_get_u32(etb->reg_cache->reg_list[ETB_RAM_WRITE_POINTER].value,
0,
32);
etb_write_reg(&etb->reg_cache->reg_list[ETB_RAM_READ_POINTER], first_frame);
/* read data into temporary array for unpacking */
trace_data = malloc(sizeof(uint32_t) * num_frames);
etb_read_ram(etb, trace_data, num_frames);
if (etm_ctx->trace_depth > 0)
free(etm_ctx->trace_data);
if ((etm_ctx->control & ETM_PORT_WIDTH_MASK) == ETM_PORT_4BIT)
etm_ctx->trace_depth = num_frames * 3;
else if ((etm_ctx->control & ETM_PORT_WIDTH_MASK) == ETM_PORT_8BIT)
etm_ctx->trace_depth = num_frames * 2;
else
etm_ctx->trace_depth = num_frames;
etm_ctx->trace_data = malloc(sizeof(struct etmv1_trace_data) * etm_ctx->trace_depth);
for (i = 0, j = 0; i < num_frames; i++) {
if ((etm_ctx->control & ETM_PORT_WIDTH_MASK) == ETM_PORT_4BIT) {
/* trace word j */
etm_ctx->trace_data[j].pipestat = trace_data[i] & 0x7;
etm_ctx->trace_data[j].packet = (trace_data[i] & 0x78) >> 3;
etm_ctx->trace_data[j].flags = 0;
if ((trace_data[i] & 0x80) >> 7)
etm_ctx->trace_data[j].flags |= ETMV1_TRACESYNC_CYCLE;
if (etm_ctx->trace_data[j].pipestat == STAT_TR) {
etm_ctx->trace_data[j].pipestat = etm_ctx->trace_data[j].packet &
0x7;
etm_ctx->trace_data[j].flags |= ETMV1_TRIGGER_CYCLE;
}
/* trace word j + 1 */
etm_ctx->trace_data[j + 1].pipestat = (trace_data[i] & 0x100) >> 8;
etm_ctx->trace_data[j + 1].packet = (trace_data[i] & 0x7800) >> 11;
etm_ctx->trace_data[j + 1].flags = 0;
if ((trace_data[i] & 0x8000) >> 15)
etm_ctx->trace_data[j + 1].flags |= ETMV1_TRACESYNC_CYCLE;
if (etm_ctx->trace_data[j + 1].pipestat == STAT_TR) {
etm_ctx->trace_data[j +
1].pipestat = etm_ctx->trace_data[j + 1].packet & 0x7;
etm_ctx->trace_data[j + 1].flags |= ETMV1_TRIGGER_CYCLE;
}
/* trace word j + 2 */
etm_ctx->trace_data[j + 2].pipestat = (trace_data[i] & 0x10000) >> 16;
etm_ctx->trace_data[j + 2].packet = (trace_data[i] & 0x780000) >> 19;
etm_ctx->trace_data[j + 2].flags = 0;
if ((trace_data[i] & 0x800000) >> 23)
etm_ctx->trace_data[j + 2].flags |= ETMV1_TRACESYNC_CYCLE;
if (etm_ctx->trace_data[j + 2].pipestat == STAT_TR) {
etm_ctx->trace_data[j +
2].pipestat = etm_ctx->trace_data[j + 2].packet & 0x7;
etm_ctx->trace_data[j + 2].flags |= ETMV1_TRIGGER_CYCLE;
}
j += 3;
} else if ((etm_ctx->control & ETM_PORT_WIDTH_MASK) == ETM_PORT_8BIT) {
/* trace word j */
etm_ctx->trace_data[j].pipestat = trace_data[i] & 0x7;
etm_ctx->trace_data[j].packet = (trace_data[i] & 0x7f8) >> 3;
etm_ctx->trace_data[j].flags = 0;
if ((trace_data[i] & 0x800) >> 11)
etm_ctx->trace_data[j].flags |= ETMV1_TRACESYNC_CYCLE;
if (etm_ctx->trace_data[j].pipestat == STAT_TR) {
etm_ctx->trace_data[j].pipestat = etm_ctx->trace_data[j].packet &
0x7;
etm_ctx->trace_data[j].flags |= ETMV1_TRIGGER_CYCLE;
}
/* trace word j + 1 */
etm_ctx->trace_data[j + 1].pipestat = (trace_data[i] & 0x7000) >> 12;
etm_ctx->trace_data[j + 1].packet = (trace_data[i] & 0x7f8000) >> 15;
etm_ctx->trace_data[j + 1].flags = 0;
if ((trace_data[i] & 0x800000) >> 23)
etm_ctx->trace_data[j + 1].flags |= ETMV1_TRACESYNC_CYCLE;
if (etm_ctx->trace_data[j + 1].pipestat == STAT_TR) {
etm_ctx->trace_data[j +
1].pipestat = etm_ctx->trace_data[j + 1].packet & 0x7;
etm_ctx->trace_data[j + 1].flags |= ETMV1_TRIGGER_CYCLE;
}
j += 2;
} else {
/* trace word j */
etm_ctx->trace_data[j].pipestat = trace_data[i] & 0x7;
etm_ctx->trace_data[j].packet = (trace_data[i] & 0x7fff8) >> 3;
etm_ctx->trace_data[j].flags = 0;
if ((trace_data[i] & 0x80000) >> 19)
etm_ctx->trace_data[j].flags |= ETMV1_TRACESYNC_CYCLE;
if (etm_ctx->trace_data[j].pipestat == STAT_TR) {
etm_ctx->trace_data[j].pipestat = etm_ctx->trace_data[j].packet &
0x7;
etm_ctx->trace_data[j].flags |= ETMV1_TRIGGER_CYCLE;
}
j += 1;
}
}
free(trace_data);
return ERROR_OK;
}
static int etb_start_capture(struct etm_context *etm_ctx)
{
struct etb *etb = etm_ctx->capture_driver_priv;
uint32_t etb_ctrl_value = 0x1;
uint32_t trigger_count;
if ((etm_ctx->control & ETM_PORT_MODE_MASK) == ETM_PORT_DEMUXED) {
if ((etm_ctx->control & ETM_PORT_WIDTH_MASK) != ETM_PORT_8BIT) {
LOG_ERROR("ETB can't run in demultiplexed mode with a 4 or 16 bit port");
return ERROR_ETM_PORTMODE_NOT_SUPPORTED;
}
etb_ctrl_value |= 0x2;
}
if ((etm_ctx->control & ETM_PORT_MODE_MASK) == ETM_PORT_MUXED) {
LOG_ERROR("ETB: can't run in multiplexed mode");
return ERROR_ETM_PORTMODE_NOT_SUPPORTED;
}
trigger_count = (etb->ram_depth * etb->trigger_percent) / 100;
etb_write_reg(&etb->reg_cache->reg_list[ETB_TRIGGER_COUNTER], trigger_count);
etb_write_reg(&etb->reg_cache->reg_list[ETB_RAM_WRITE_POINTER], 0x0);
etb_write_reg(&etb->reg_cache->reg_list[ETB_CTRL], etb_ctrl_value);
jtag_execute_queue();
/* we're starting a new trace, initialize capture status */
etm_ctx->capture_status = TRACE_RUNNING;
return ERROR_OK;
}
static int etb_stop_capture(struct etm_context *etm_ctx)
{
struct etb *etb = etm_ctx->capture_driver_priv;
struct reg *etb_ctrl_reg = &etb->reg_cache->reg_list[ETB_CTRL];
etb_write_reg(etb_ctrl_reg, 0x0);
jtag_execute_queue();
/* trace stopped, just clear running flag, but preserve others */
etm_ctx->capture_status &= ~TRACE_RUNNING;
return ERROR_OK;
}
struct etm_capture_driver etb_capture_driver = {
.name = "etb",
.commands = etb_command_handlers,
.init = etb_init,
.status = etb_status,
.start_capture = etb_start_capture,
.stop_capture = etb_stop_capture,
.read_trace = etb_read_trace,
};

View File

@ -0,0 +1,60 @@
/***************************************************************************
* Copyright (C) 2007 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef ETB_H
#define ETB_H
/* ETB registers */
enum {
ETB_ID = 0x00,
ETB_RAM_DEPTH = 0x01,
ETB_RAM_WIDTH = 0x02,
ETB_STATUS = 0x03,
ETB_RAM_DATA = 0x04,
ETB_RAM_READ_POINTER = 0x05,
ETB_RAM_WRITE_POINTER = 0x06,
ETB_TRIGGER_COUNTER = 0x07,
ETB_CTRL = 0x08,
};
struct etb {
struct etm_context *etm_ctx;
struct jtag_tap *tap;
uint32_t cur_scan_chain;
struct reg_cache *reg_cache;
/* ETB parameters */
uint32_t ram_depth;
uint32_t ram_width;
/** how much trace buffer to fill after trigger */
unsigned trigger_percent;
};
struct etb_reg {
uint32_t addr;
struct etb *etb;
};
extern struct etm_capture_driver etb_capture_driver;
struct reg_cache *etb_build_reg_cache(struct etb *etb);
#endif /* ETB_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,226 @@
/***************************************************************************
* Copyright (C) 2005, 2007 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* Copyright (C) 2007 by Vincent Palatin *
* vincent.palatin_openocd@m4x.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef ETM_H
#define ETM_H
#include "trace.h"
#include "arm_jtag.h"
struct image;
/* ETM registers (JTAG protocol) */
enum {
ETM_CTRL = 0x00,
ETM_CONFIG = 0x01,
ETM_TRIG_EVENT = 0x02,
ETM_ASIC_CTRL = 0x03,
ETM_STATUS = 0x04,
ETM_SYS_CONFIG = 0x05,
ETM_TRACE_RESOURCE_CTRL = 0x06,
ETM_TRACE_EN_CTRL2 = 0x07,
ETM_TRACE_EN_EVENT = 0x08,
ETM_TRACE_EN_CTRL1 = 0x09,
/* optional FIFOFULL */
ETM_FIFOFULL_REGION = 0x0a,
ETM_FIFOFULL_LEVEL = 0x0b,
/* viewdata support */
ETM_VIEWDATA_EVENT = 0x0c,
ETM_VIEWDATA_CTRL1 = 0x0d,
ETM_VIEWDATA_CTRL2 = 0x0e, /* optional */
ETM_VIEWDATA_CTRL3 = 0x0f,
/* N pairs of ADDR_{COMPARATOR,ACCESS} registers */
ETM_ADDR_COMPARATOR_VALUE = 0x10,
ETM_ADDR_ACCESS_TYPE = 0x20,
/* N pairs of DATA_COMPARATOR_{VALUE,MASK} registers */
ETM_DATA_COMPARATOR_VALUE = 0x30,
ETM_DATA_COMPARATOR_MASK = 0x40,
/* N quads of COUNTER_{RELOAD_{VALUE,EVENT},ENABLE,VALUE} registers */
ETM_COUNTER_RELOAD_VALUE = 0x50,
ETM_COUNTER_ENABLE = 0x54,
ETM_COUNTER_RELOAD_EVENT = 0x58,
ETM_COUNTER_VALUE = 0x5c,
/* 6 sequencer event transitions */
ETM_SEQUENCER_EVENT = 0x60,
ETM_SEQUENCER_STATE = 0x67,
/* N triggered outputs */
ETM_EXTERNAL_OUTPUT = 0x68,
/* N task contexts */
ETM_CONTEXTID_COMPARATOR_VALUE = 0x6c,
ETM_CONTEXTID_COMPARATOR_MASK = 0x6f,
ETM_ID = 0x79,
};
struct etm_reg {
uint32_t value;
const struct etm_reg_info *reg_info;
struct arm_jtag *jtag_info;
};
/* Subset of ETM_CTRL bit assignments. Many of these
* control the configuration of trace output, which
* hooks up either to ETB or to an external device.
*
* NOTE that these have evolved since the ~v1.3 defns ...
*/
enum {
ETM_CTRL_POWERDOWN = (1 << 0),
ETM_CTRL_MONITOR_CPRT = (1 << 1),
/* bits 3:2 == trace type */
ETM_CTRL_TRACE_DATA = (1 << 2),
ETM_CTRL_TRACE_ADDR = (2 << 2),
ETM_CTRL_TRACE_MASK = (3 << 2),
/* Port width (bits 21 and 6:4) */
ETM_PORT_4BIT = 0x00,
ETM_PORT_8BIT = 0x10,
ETM_PORT_16BIT = 0x20,
ETM_PORT_24BIT = 0x30,
ETM_PORT_32BIT = 0x40,
ETM_PORT_48BIT = 0x50,
ETM_PORT_64BIT = 0x60,
ETM_PORT_1BIT = 0x00 | (1 << 21),
ETM_PORT_2BIT = 0x10 | (1 << 21),
ETM_PORT_WIDTH_MASK = 0x70 | (1 << 21),
ETM_CTRL_FIFOFULL_STALL = (1 << 7),
ETM_CTRL_BRANCH_OUTPUT = (1 << 8),
ETM_CTRL_DBGRQ = (1 << 9),
ETM_CTRL_ETM_PROG = (1 << 10),
ETM_CTRL_ETMEN = (1 << 11),
ETM_CTRL_CYCLE_ACCURATE = (1 << 12),
/* Clocking modes -- up to v2.1, bit 13 */
ETM_PORT_FULL_CLOCK = (0 << 13),
ETM_PORT_HALF_CLOCK = (1 << 13),
ETM_PORT_CLOCK_MASK = (1 << 13),
/* bits 15:14 == context ID size used in tracing */
ETM_CTRL_CONTEXTID_NONE = (0 << 14),
ETM_CTRL_CONTEXTID_8 = (1 << 14),
ETM_CTRL_CONTEXTID_16 = (2 << 14),
ETM_CTRL_CONTEXTID_32 = (3 << 14),
ETM_CTRL_CONTEXTID_MASK = (3 << 14),
/* Port modes -- bits 17:16, tied to clocking mode */
ETM_PORT_NORMAL = (0 << 16),
ETM_PORT_MUXED = (1 << 16),
ETM_PORT_DEMUXED = (2 << 16),
ETM_PORT_MODE_MASK = (3 << 16),
/* bits 31:18 defined in v3.0 and later (e.g. ARM11+) */
};
/* forward-declare ETM context */
struct etm_context;
struct etm_capture_driver {
const char *name;
const struct command_registration *commands;
int (*init)(struct etm_context *etm_ctx);
trace_status_t (*status)(struct etm_context *etm_ctx);
int (*read_trace)(struct etm_context *etm_ctx);
int (*start_capture)(struct etm_context *etm_ctx);
int (*stop_capture)(struct etm_context *etm_ctx);
};
enum {
ETMV1_TRACESYNC_CYCLE = 0x1,
ETMV1_TRIGGER_CYCLE = 0x2,
};
struct etmv1_trace_data {
uint8_t pipestat; /* bits 0-2 pipeline status */
uint16_t packet; /* packet data (4, 8 or 16 bit) */
int flags; /* ETMV1_TRACESYNC_CYCLE, ETMV1_TRIGGER_CYCLE */
};
/* describe a trace context
* if support for ETMv2 or ETMv3 is to be implemented,
* this will have to be split into version independent elements
* and a version specific part
*/
struct etm_context {
struct target *target; /* target this ETM is connected to */
struct reg_cache *reg_cache; /* ETM register cache */
struct etm_capture_driver *capture_driver; /* driver used to access ETM data */
void *capture_driver_priv; /* capture driver private data */
trace_status_t capture_status; /* current state of capture run */
struct etmv1_trace_data *trace_data; /* trace data */
uint32_t trace_depth; /* number of cycles to be analyzed, 0 if no data available */
uint32_t control; /* shadow of ETM_CTRL */
int /*arm_state*/ core_state; /* current core state */
struct image *image; /* source for target opcodes */
uint32_t pipe_index; /* current trace cycle */
uint32_t data_index; /* cycle holding next data packet */
bool data_half; /* port half on a 16 bit port */
bool pc_ok; /* full PC has been acquired */
bool ptr_ok; /* whether last_ptr is valid */
uint8_t bcd_vers; /* e.g. 0x13 == ETMv1.3 */
uint32_t config; /* cache of ETM_CONFIG value */
uint32_t id; /* cache of ETM_ID value, or 0 */
uint32_t current_pc; /* current program counter */
uint32_t last_branch; /* last branch address output */
uint32_t last_branch_reason; /* type of last branch encountered */
uint32_t last_ptr; /* address of the last data access */
uint32_t last_instruction; /* index of last executed (to calc timings) */
};
/* PIPESTAT values */
typedef enum {
STAT_IE = 0x0,
STAT_ID = 0x1,
STAT_IN = 0x2,
STAT_WT = 0x3,
STAT_BE = 0x4,
STAT_BD = 0x5,
STAT_TR = 0x6,
STAT_TD = 0x7
} etmv1_pipestat_t;
/* branch reason values */
typedef enum {
BR_NORMAL = 0x0, /* Normal PC change : periodic synchro (ETMv1.1) */
BR_ENABLE = 0x1, /* Trace has been enabled */
BR_RESTART = 0x2, /* Trace restarted after a FIFO overflow */
BR_NODEBUG = 0x3, /* ARM has exited for debug state */
BR_PERIOD = 0x4, /* Peridioc synchronization point (ETM >= v1.2)*/
BR_RSVD5 = 0x5, /* reserved */
BR_RSVD6 = 0x6, /* reserved */
BR_RSVD7 = 0x7, /* reserved */
} etmv1_branch_reason_t;
struct reg_cache *etm_build_reg_cache(struct target *target,
struct arm_jtag *jtag_info, struct etm_context *etm_ctx);
int etm_setup(struct target *target);
extern const struct command_registration etm_command_handlers[];
#define ERROR_ETM_INVALID_DRIVER (-1300)
#define ERROR_ETM_PORTMODE_NOT_SUPPORTED (-1301)
#define ERROR_ETM_CAPTURE_INIT_FAILED (-1302)
#define ERROR_ETM_ANALYSIS_FAILED (-1303)
#endif /* ETM_H */

View File

@ -0,0 +1,108 @@
/***************************************************************************
* Copyright (C) 2007 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "arm.h"
#include "etm_dummy.h"
COMMAND_HANDLER(handle_etm_dummy_config_command)
{
struct target *target;
struct arm *arm;
target = get_target(CMD_ARGV[0]);
if (!target) {
LOG_ERROR("target '%s' not defined", CMD_ARGV[0]);
return ERROR_FAIL;
}
arm = target_to_arm(target);
if (!is_arm(arm)) {
command_print(CMD_CTX, "target '%s' isn't an ARM", CMD_ARGV[0]);
return ERROR_FAIL;
}
if (arm->etm)
arm->etm->capture_driver_priv = NULL;
else {
LOG_ERROR("target has no ETM defined, ETM dummy left unconfigured");
return ERROR_FAIL;
}
return ERROR_OK;
}
static const struct command_registration etm_dummy_config_command_handlers[] = {
{
.name = "config",
.handler = handle_etm_dummy_config_command,
.mode = COMMAND_CONFIG,
.usage = "target",
},
COMMAND_REGISTRATION_DONE
};
static const struct command_registration etm_dummy_command_handlers[] = {
{
.name = "etm_dummy",
.mode = COMMAND_ANY,
.help = "Dummy ETM capture driver command group",
.chain = etm_dummy_config_command_handlers,
},
COMMAND_REGISTRATION_DONE
};
static int etm_dummy_init(struct etm_context *etm_ctx)
{
return ERROR_OK;
}
static trace_status_t etm_dummy_status(struct etm_context *etm_ctx)
{
return TRACE_IDLE;
}
static int etm_dummy_read_trace(struct etm_context *etm_ctx)
{
return ERROR_OK;
}
static int etm_dummy_start_capture(struct etm_context *etm_ctx)
{
return ERROR_ETM_PORTMODE_NOT_SUPPORTED;
}
static int etm_dummy_stop_capture(struct etm_context *etm_ctx)
{
return ERROR_OK;
}
struct etm_capture_driver etm_dummy_capture_driver = {
.name = "dummy",
.commands = etm_dummy_command_handlers,
.init = etm_dummy_init,
.status = etm_dummy_status,
.start_capture = etm_dummy_start_capture,
.stop_capture = etm_dummy_stop_capture,
.read_trace = etm_dummy_read_trace,
};

View File

@ -0,0 +1,28 @@
/***************************************************************************
* Copyright (C) 2007 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef ETM_DUMMY_H
#define ETM_DUMMY_H
#include "etm.h"
extern struct etm_capture_driver etm_dummy_capture_driver;
#endif /* ETB_H */

View File

@ -0,0 +1,387 @@
/***************************************************************************
* Copyright (C) 2009 by Paulius Zaleckas *
* paulius.zaleckas@gmail.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
/*
* FA526 is very similar to ARM920T with following differences:
*
* - execution pipeline is 6 steps
* - Unified TLB
* - has Branch Target Buffer
* - does not support reading of I/D cache contents
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "arm920t.h"
#include "target_type.h"
#include "arm_opcodes.h"
static void fa526_change_to_arm(struct target *target, uint32_t *r0, uint32_t *pc)
{
LOG_ERROR("%s: there is no Thumb state on FA526", __func__);
}
static void fa526_read_core_regs(struct target *target,
uint32_t mask, uint32_t *core_regs[16])
{
int i;
struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
struct arm_jtag *jtag_info = &arm7_9->jtag_info;
/* STMIA r0-15, [r0] at debug speed
* register values will start to appear on 4th DCLK
*/
arm9tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask & 0xffff, 0, 0), 0, NULL, 0);
/* fetch NOP, STM in DECODE stage */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* fetch NOP, STM in SHIFT stage */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* fetch NOP, STM in EXECUTE stage (1st cycle) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
for (i = 0; i <= 15; i++) {
if (mask & (1 << i))
/* nothing fetched, STM in MEMORY (i'th cycle) */
arm9tdmi_clock_data_in(jtag_info, core_regs[i]);
}
}
static void fa526_read_core_regs_target_buffer(struct target *target,
uint32_t mask, void *buffer, int size)
{
int i;
struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
struct arm_jtag *jtag_info = &arm7_9->jtag_info;
int be = (target->endianness == TARGET_BIG_ENDIAN) ? 1 : 0;
uint32_t *buf_u32 = buffer;
uint16_t *buf_u16 = buffer;
uint8_t *buf_u8 = buffer;
/* STMIA r0-15, [r0] at debug speed
* register values will start to appear on 4th DCLK
*/
arm9tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask & 0xffff, 0, 0), 0, NULL, 0);
/* fetch NOP, STM in DECODE stage */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* fetch NOP, STM in SHIFT stage */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* fetch NOP, STM in EXECUTE stage (1st cycle) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
for (i = 0; i <= 15; i++) {
if (mask & (1 << i))
/* nothing fetched, STM in MEMORY (i'th cycle) */
switch (size) {
case 4:
arm9tdmi_clock_data_in_endianness(jtag_info, buf_u32++, 4, be);
break;
case 2:
arm9tdmi_clock_data_in_endianness(jtag_info, buf_u16++, 2, be);
break;
case 1:
arm9tdmi_clock_data_in_endianness(jtag_info, buf_u8++, 1, be);
break;
}
}
}
static void fa526_read_xpsr(struct target *target, uint32_t *xpsr, int spsr)
{
struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
struct arm_jtag *jtag_info = &arm7_9->jtag_info;
/* MRS r0, cpsr */
arm9tdmi_clock_out(jtag_info, ARMV4_5_MRS(0, spsr & 1), 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* STR r0, [r15] */
arm9tdmi_clock_out(jtag_info, ARMV4_5_STR(0, 15), 0, NULL, 0);
/* fetch NOP, STR in DECODE stage */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* fetch NOP, STR in SHIFT stage */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* fetch NOP, STR in EXECUTE stage (1st cycle) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* nothing fetched, STR in MEMORY */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, xpsr, 0);
}
static void fa526_write_xpsr(struct target *target, uint32_t xpsr, int spsr)
{
struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
struct arm_jtag *jtag_info = &arm7_9->jtag_info;
LOG_DEBUG("xpsr: %8.8" PRIx32 ", spsr: %i", xpsr, spsr);
/* MSR1 fetched */
arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM(xpsr & 0xff, 0, 1, spsr), 0, NULL, 0);
/* MSR2 fetched, MSR1 in DECODE */
arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff00) >> 8, 0xc, 2, spsr), 0, NULL, 0);
/* MSR3 fetched, MSR1 in SHIFT, MSR2 in DECODE */
arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff0000) >> 16, 0x8, 4, spsr), 0, NULL, 0);
/* MSR4 fetched, MSR1 in EXECUTE (1), MSR2 in SHIFT, MSR3 in DECODE */
arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff000000) >> 24, 0x4, 8, spsr), 0, NULL, 0);
/* nothing fetched, MSR1 in EXECUTE (2) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* nothing fetched, MSR1 in EXECUTE (3) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* nothing fetched, MSR2 in EXECUTE (1), MSR3 in SHIFT, MSR4 in DECODE */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* nothing fetched, MSR2 in EXECUTE (2) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* nothing fetched, MSR2 in EXECUTE (3) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* NOP fetched, MSR3 in EXECUTE (1), MSR4 in SHIFT */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* nothing fetched, MSR3 in EXECUTE (2) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* nothing fetched, MSR3 in EXECUTE (3) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* NOP fetched, MSR4 in EXECUTE (1) */
/* last MSR writes flags, which takes only one cycle */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
}
static void fa526_write_xpsr_im8(struct target *target,
uint8_t xpsr_im, int rot, int spsr)
{
struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
struct arm_jtag *jtag_info = &arm7_9->jtag_info;
LOG_DEBUG("xpsr_im: %2.2x, rot: %i, spsr: %i", xpsr_im, rot, spsr);
/* MSR fetched */
arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM(xpsr_im, rot, 1, spsr), 0, NULL, 0);
/* NOP fetched, MSR in DECODE */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* NOP fetched, MSR in SHIFT */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* NOP fetched, MSR in EXECUTE (1) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* rot == 4 writes flags, which takes only one cycle */
if (rot != 4) {
/* nothing fetched, MSR in EXECUTE (2) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* nothing fetched, MSR in EXECUTE (3) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
}
}
static void fa526_write_core_regs(struct target *target,
uint32_t mask, uint32_t core_regs[16])
{
int i;
struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
struct arm_jtag *jtag_info = &arm7_9->jtag_info;
/* LDMIA r0-15, [r0] at debug speed
* register values will start to appear on 4th DCLK
*/
arm9tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, mask & 0xffff, 0, 0), 0, NULL, 0);
/* fetch NOP, LDM in DECODE stage */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* fetch NOP, LDM in SHIFT stage */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* fetch NOP, LDM in EXECUTE stage (1st cycle) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
for (i = 0; i <= 15; i++) {
if (mask & (1 << i))
/* nothing fetched, LDM still in EXECUTE (1 + i cycle) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, core_regs[i], NULL, 0);
}
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
}
static void fa526_write_pc(struct target *target, uint32_t pc)
{
struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
struct arm_jtag *jtag_info = &arm7_9->jtag_info;
/* LDMIA r0-15, [r0] at debug speed
* register values will start to appear on 4th DCLK
*/
arm9tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, 0x8000, 0, 0), 0, NULL, 0);
/* fetch NOP, LDM in DECODE stage */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* fetch NOP, LDM in SHIFT stage */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* fetch NOP, LDM in EXECUTE stage (1st cycle) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* nothing fetched, LDM in EXECUTE stage (2nd cycle) (output data) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, pc, NULL, 0);
/* nothing fetched, LDM in EXECUTE stage (3rd cycle) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* fetch NOP, LDM in EXECUTE stage (4th cycle) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
/* fetch NOP, LDM in EXECUTE stage (5th cycle) */
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
}
static void fa526_branch_resume_thumb(struct target *target)
{
LOG_ERROR("%s: there is no Thumb state on FA526", __func__);
}
static int fa526_init_arch_info_2(struct target *target,
struct arm7_9_common *arm7_9, struct jtag_tap *tap)
{
/* prepare JTAG information for the new target */
arm7_9->jtag_info.tap = tap;
arm7_9->jtag_info.scann_size = 5;
/* register arch-specific functions */
arm7_9->examine_debug_reason = arm9tdmi_examine_debug_reason;
arm7_9->change_to_arm = fa526_change_to_arm;
arm7_9->read_core_regs = fa526_read_core_regs;
arm7_9->read_core_regs_target_buffer = fa526_read_core_regs_target_buffer;
arm7_9->read_xpsr = fa526_read_xpsr;
arm7_9->write_xpsr = fa526_write_xpsr;
arm7_9->write_xpsr_im8 = fa526_write_xpsr_im8;
arm7_9->write_core_regs = fa526_write_core_regs;
arm7_9->load_word_regs = arm9tdmi_load_word_regs;
arm7_9->load_hword_reg = arm9tdmi_load_hword_reg;
arm7_9->load_byte_reg = arm9tdmi_load_byte_reg;
arm7_9->store_word_regs = arm9tdmi_store_word_regs;
arm7_9->store_hword_reg = arm9tdmi_store_hword_reg;
arm7_9->store_byte_reg = arm9tdmi_store_byte_reg;
arm7_9->write_pc = fa526_write_pc;
arm7_9->branch_resume = arm9tdmi_branch_resume;
arm7_9->branch_resume_thumb = fa526_branch_resume_thumb;
arm7_9->enable_single_step = arm9tdmi_enable_single_step;
arm7_9->disable_single_step = arm9tdmi_disable_single_step;
arm7_9->post_debug_entry = NULL;
arm7_9->pre_restore_context = NULL;
/* initialize arch-specific breakpoint handling */
arm7_9->arm_bkpt = 0xdeeedeee;
arm7_9->thumb_bkpt = 0xdeee;
arm7_9->dbgreq_adjust_pc = 3;
arm7_9_init_arch_info(target, arm7_9);
/* override use of DBGRQ, this is safe on ARM9TDMI */
arm7_9->use_dbgrq = 1;
/* all ARM9s have the vector catch register */
arm7_9->has_vector_catch = 1;
return ERROR_OK;
}
static int fa526_init_arch_info(struct target *target,
struct arm920t_common *arm920t, struct jtag_tap *tap)
{
struct arm7_9_common *arm7_9 = &arm920t->arm7_9_common;
/* initialize arm7/arm9 specific info (including armv4_5) */
fa526_init_arch_info_2(target, arm7_9, tap);
arm920t->common_magic = ARM920T_COMMON_MAGIC;
arm7_9->post_debug_entry = arm920t_post_debug_entry;
arm7_9->pre_restore_context = arm920t_pre_restore_context;
arm920t->armv4_5_mmu.armv4_5_cache.ctype = -1;
arm920t->armv4_5_mmu.get_ttb = arm920t_get_ttb;
arm920t->armv4_5_mmu.read_memory = arm7_9_read_memory;
arm920t->armv4_5_mmu.write_memory = arm7_9_write_memory;
arm920t->armv4_5_mmu.disable_mmu_caches = arm920t_disable_mmu_caches;
arm920t->armv4_5_mmu.enable_mmu_caches = arm920t_enable_mmu_caches;
arm920t->armv4_5_mmu.has_tiny_pages = 1;
arm920t->armv4_5_mmu.mmu_enabled = 0;
/* disabling linefills leads to lockups, so keep them enabled for now
* this doesn't affect correctness, but might affect timing issues, if
* important data is evicted from the cache during the debug session
* */
arm920t->preserve_cache = 0;
/* override hw single-step capability from ARM9TDMI */
arm7_9->has_single_step = 1;
return ERROR_OK;
}
static int fa526_target_create(struct target *target, Jim_Interp *interp)
{
struct arm920t_common *arm920t = calloc(1, sizeof(struct arm920t_common));
return fa526_init_arch_info(target, arm920t, target->tap);
}
/** Holds methods for FA526 targets. */
struct target_type fa526_target = {
.name = "fa526",
.poll = arm7_9_poll,
.arch_state = arm920t_arch_state,
.target_request_data = arm7_9_target_request_data,
.halt = arm7_9_halt,
.resume = arm7_9_resume,
.step = arm7_9_step,
.assert_reset = arm7_9_assert_reset,
.deassert_reset = arm7_9_deassert_reset,
.soft_reset_halt = arm920t_soft_reset_halt,
.get_gdb_reg_list = arm_get_gdb_reg_list,
.read_memory = arm920t_read_memory,
.write_memory = arm920t_write_memory,
.bulk_write_memory = arm7_9_bulk_write_memory,
.checksum_memory = arm_checksum_memory,
.blank_check_memory = arm_blank_check_memory,
.run_algorithm = armv4_5_run_algorithm,
.add_breakpoint = arm7_9_add_breakpoint,
.remove_breakpoint = arm7_9_remove_breakpoint,
.add_watchpoint = arm7_9_add_watchpoint,
.remove_watchpoint = arm7_9_remove_watchpoint,
.commands = arm920t_command_handlers,
.target_create = fa526_target_create,
.init_target = arm9tdmi_init_target,
.examine = arm7_9_examine,
.check_reset = arm7_9_check_reset,
};

View File

@ -0,0 +1,753 @@
/***************************************************************************
* Copyright (C) 2008-2009 by Marvell Semiconductors, Inc. *
* Written by Nicolas Pitre <nico@marvell.com> *
* *
* Copyright (C) 2008 by Hongtao Zheng *
* hontor@126.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
/*
* Marvell Feroceon/Dragonite support.
*
* The Feroceon core, as found in the Orion and Kirkwood SoCs amongst others,
* mimics the ARM926 ICE interface with the following differences:
*
* - the MOE (method of entry) reporting is not implemented
*
* - breakpoint/watchpoint comparator #1 is seemingly not implemented
*
* - due to a different pipeline implementation, some injected debug
* instruction sequences have to be somewhat different
*
* Other issues:
*
* - asserting DBGRQ doesn't work if target is looping on the undef vector
*
* - the EICE version signature in the COMMS_CTL reg is next to the flow bits
* not at the top, and rather meaningless due to existing discrepencies
*
* - the DCC channel is half duplex (only one FIFO for both directions) with
* seemingly no proper flow control.
*
* The Dragonite core is the non-mmu version based on the ARM966 model, and
* it shares the above issues as well.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "arm926ejs.h"
#include "arm966e.h"
#include "target_type.h"
#include "register.h"
#include "arm_opcodes.h"
static int feroceon_assert_reset(struct target *target)
{
struct arm *arm = target->arch_info;
struct arm7_9_common *arm7_9 = arm->arch_info;
int ud = arm7_9->use_dbgrq;
arm7_9->use_dbgrq = 0;
if (target->reset_halt)
arm7_9_halt(target);
arm7_9->use_dbgrq = ud;
return arm7_9_assert_reset(target);
}
static int feroceon_dummy_clock_out(struct arm_jtag *jtag_info, uint32_t instr)
{
struct scan_field fields[3];
uint8_t out_buf[4];
uint8_t instr_buf[4];
uint8_t sysspeed_buf = 0x0;
int retval;
/* prepare buffer */
buf_set_u32(out_buf, 0, 32, 0);
buf_set_u32(instr_buf, 0, 32, flip_u32(instr, 32));
retval = arm_jtag_scann(jtag_info, 0x1, TAP_DRPAUSE);
if (retval != ERROR_OK)
return retval;
retval = arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL, TAP_DRPAUSE);
if (retval != ERROR_OK)
return retval;
fields[0].num_bits = 32;
fields[0].out_value = out_buf;
fields[0].in_value = NULL;
fields[1].num_bits = 3;
fields[1].out_value = &sysspeed_buf;
fields[1].in_value = NULL;
fields[2].num_bits = 32;
fields[2].out_value = instr_buf;
fields[2].in_value = NULL;
jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_DRPAUSE);
/* no jtag_add_runtest(0, TAP_DRPAUSE) here */
return ERROR_OK;
}
static void feroceon_change_to_arm(struct target *target, uint32_t *r0,
uint32_t *pc)
{
struct arm *arm = target->arch_info;
struct arm7_9_common *arm7_9 = arm->arch_info;
struct arm_jtag *jtag_info = &arm7_9->jtag_info;
/*
* save r0 before using it and put system in ARM state
* to allow common handling of ARM and THUMB debugging
*/
feroceon_dummy_clock_out(jtag_info, ARMV4_5_T_NOP);
feroceon_dummy_clock_out(jtag_info, ARMV4_5_T_NOP);
feroceon_dummy_clock_out(jtag_info, ARMV4_5_T_NOP);
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_STR(0, 0), 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, r0, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_MOV(0, 15), 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_STR(0, 0), 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, pc, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_BX(15), 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
jtag_execute_queue();
/*
* fix program counter:
* MOV R0, PC was the 7th instruction (+12)
* reading PC in Thumb state gives address of instruction + 4
*/
*pc -= (12 + 4);
}
static void feroceon_read_core_regs(struct target *target,
uint32_t mask, uint32_t *core_regs[16])
{
int i;
struct arm *arm = target->arch_info;
struct arm7_9_common *arm7_9 = arm->arch_info;
struct arm_jtag *jtag_info = &arm7_9->jtag_info;
arm9tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask & 0xffff, 0, 0), 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
for (i = 0; i <= 15; i++)
if (mask & (1 << i))
arm9tdmi_clock_data_in(jtag_info, core_regs[i]);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
}
static void feroceon_read_core_regs_target_buffer(struct target *target,
uint32_t mask, void *buffer, int size)
{
int i;
struct arm *arm = target->arch_info;
struct arm7_9_common *arm7_9 = arm->arch_info;
struct arm_jtag *jtag_info = &arm7_9->jtag_info;
int be = (target->endianness == TARGET_BIG_ENDIAN) ? 1 : 0;
uint32_t *buf_u32 = buffer;
uint16_t *buf_u16 = buffer;
uint8_t *buf_u8 = buffer;
arm9tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask & 0xffff, 0, 0), 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
for (i = 0; i <= 15; i++) {
if (mask & (1 << i)) {
switch (size) {
case 4:
arm9tdmi_clock_data_in_endianness(jtag_info, buf_u32++, 4, be);
break;
case 2:
arm9tdmi_clock_data_in_endianness(jtag_info, buf_u16++, 2, be);
break;
case 1:
arm9tdmi_clock_data_in_endianness(jtag_info, buf_u8++, 1, be);
break;
}
}
}
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
}
static void feroceon_read_xpsr(struct target *target, uint32_t *xpsr, int spsr)
{
struct arm *arm = target->arch_info;
struct arm7_9_common *arm7_9 = arm->arch_info;
struct arm_jtag *jtag_info = &arm7_9->jtag_info;
arm9tdmi_clock_out(jtag_info, ARMV4_5_MRS(0, spsr & 1), 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, 1, 0, 0), 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, xpsr, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
}
static void feroceon_write_xpsr(struct target *target, uint32_t xpsr, int spsr)
{
struct arm *arm = target->arch_info;
struct arm7_9_common *arm7_9 = arm->arch_info;
struct arm_jtag *jtag_info = &arm7_9->jtag_info;
LOG_DEBUG("xpsr: %8.8" PRIx32 ", spsr: %i", xpsr, spsr);
arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM(xpsr & 0xff, 0, 1, spsr), 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff00) >> 8, 0xc, 2, spsr), 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff0000) >> 16, 0x8, 4, spsr), 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff000000) >> 24, 0x4, 8, spsr), 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
}
static void feroceon_write_xpsr_im8(struct target *target,
uint8_t xpsr_im, int rot, int spsr)
{
struct arm *arm = target->arch_info;
struct arm7_9_common *arm7_9 = arm->arch_info;
struct arm_jtag *jtag_info = &arm7_9->jtag_info;
LOG_DEBUG("xpsr_im: %2.2x, rot: %i, spsr: %i", xpsr_im, rot, spsr);
arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM(xpsr_im, rot, 1, spsr), 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
}
static void feroceon_write_core_regs(struct target *target,
uint32_t mask, uint32_t core_regs[16])
{
int i;
struct arm *arm = target->arch_info;
struct arm7_9_common *arm7_9 = arm->arch_info;
struct arm_jtag *jtag_info = &arm7_9->jtag_info;
arm9tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, mask & 0xffff, 0, 0), 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
for (i = 0; i <= 15; i++)
if (mask & (1 << i))
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, core_regs[i], NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
}
static void feroceon_branch_resume(struct target *target)
{
struct arm *arm = target->arch_info;
struct arm7_9_common *arm7_9 = arm->arch_info;
struct arm_jtag *jtag_info = &arm7_9->jtag_info;
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_B(0xfffff9, 0), 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1);
arm7_9->need_bypass_before_restart = 1;
}
static void feroceon_branch_resume_thumb(struct target *target)
{
LOG_DEBUG("-");
struct arm *arm = target->arch_info;
struct arm7_9_common *arm7_9 = arm->arch_info;
struct arm_jtag *jtag_info = &arm7_9->jtag_info;
uint32_t r0 = buf_get_u32(arm->core_cache->reg_list[0].value, 0, 32);
uint32_t pc = buf_get_u32(arm->pc->value, 0, 32);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, 0xE28F0001, 0, NULL, 0); /* add r0,pc,#1 */
arm9tdmi_clock_out(jtag_info, ARMV4_5_BX(0), 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_LDMIA(0, 0x1), 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, r0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
pc = (pc & 2) >> 1;
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_B(0x7e9 + pc), 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 1);
arm7_9->need_bypass_before_restart = 1;
}
static int feroceon_read_cp15(struct target *target, uint32_t op1,
uint32_t op2, uint32_t CRn, uint32_t CRm, uint32_t *value)
{
struct arm *arm = target->arch_info;
struct arm7_9_common *arm7_9 = arm->arch_info;
struct arm_jtag *jtag_info = &arm7_9->jtag_info;
int err;
arm9tdmi_clock_out(jtag_info, ARMV4_5_MRC(15, op1, 0, CRn, CRm, op2), 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1);
err = arm7_9_execute_sys_speed(target);
if (err != ERROR_OK)
return err;
arm9tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, 1, 0, 0), 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, value, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
return jtag_execute_queue();
}
static int feroceon_write_cp15(struct target *target, uint32_t op1,
uint32_t op2, uint32_t CRn, uint32_t CRm, uint32_t value)
{
struct arm *arm = target->arch_info;
struct arm7_9_common *arm7_9 = arm->arch_info;
struct arm_jtag *jtag_info = &arm7_9->jtag_info;
arm9tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, 1, 0, 0), 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, value, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_MCR(15, op1, 0, CRn, CRm, op2), 0, NULL, 0);
arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1);
return arm7_9_execute_sys_speed(target);
}
static void feroceon_set_dbgrq(struct target *target)
{
struct arm *arm = target->arch_info;
struct arm7_9_common *arm7_9 = arm->arch_info;
struct reg *dbg_ctrl = &arm7_9->eice_cache->reg_list[EICE_DBG_CTRL];
buf_set_u32(dbg_ctrl->value, 0, 8, 2);
embeddedice_store_reg(dbg_ctrl);
}
static void feroceon_enable_single_step(struct target *target, uint32_t next_pc)
{
struct arm *arm = target->arch_info;
struct arm7_9_common *arm7_9 = arm->arch_info;
/* set a breakpoint there */
embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_ADDR_VALUE], next_pc);
embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_ADDR_MASK], 0);
embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_DATA_MASK], 0xffffffff);
embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_VALUE], 0x100);
embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_MASK], 0xf7);
}
static void feroceon_disable_single_step(struct target *target)
{
struct arm *arm = target->arch_info;
struct arm7_9_common *arm7_9 = arm->arch_info;
embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_W0_ADDR_VALUE]);
embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_W0_ADDR_MASK]);
embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_W0_DATA_MASK]);
embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_MASK]);
embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_VALUE]);
}
static int feroceon_examine_debug_reason(struct target *target)
{
/* the MOE is not implemented */
if (target->debug_reason != DBG_REASON_SINGLESTEP)
target->debug_reason = DBG_REASON_DBGRQ;
return ERROR_OK;
}
static int feroceon_bulk_write_memory(struct target *target,
uint32_t address, uint32_t count, const uint8_t *buffer)
{
int retval;
struct arm *arm = target->arch_info;
struct arm7_9_common *arm7_9 = arm->arch_info;
enum arm_state core_state = arm->core_state;
uint32_t x, flip, shift, save[7];
uint32_t i;
/*
* We can't use the dcc flow control bits, so let's transfer data
* with 31 bits and flip the MSB each time a new data word is sent.
*/
static uint32_t dcc_code[] = {
0xee115e10, /* 3: mrc p14, 0, r5, c1, c0, 0 */
0xe3a0301e, /* 1: mov r3, #30 */
0xe3a04002, /* mov r4, #2 */
0xee111e10, /* 2: mrc p14, 0, r1, c1, c0, 0 */
0xe1310005, /* teq r1, r5 */
0x0afffffc, /* beq 1b */
0xe1a05001, /* mov r5, r1 */
0xe1a01081, /* mov r1, r1, lsl #1 */
0xee112e10, /* 3: mrc p14, 0, r2, c1, c0, 0 */
0xe1320005, /* teq r2, r5 */
0x0afffffc, /* beq 3b */
0xe1a05002, /* mov r5, r2 */
0xe3c22102, /* bic r2, r2, #0x80000000 */
0xe1811332, /* orr r1, r1, r2, lsr r3 */
0xe2533001, /* subs r3, r3, #1 */
0xe4801004, /* str r1, [r0], #4 */
0xe1a01412, /* mov r1, r2, lsl r4 */
0xe2844001, /* add r4, r4, #1 */
0x4affffed, /* bmi 1b */
0xeafffff3, /* b 3b */
};
uint32_t dcc_size = sizeof(dcc_code);
if (!arm7_9->dcc_downloads)
return target_write_memory(target, address, 4, count, buffer);
/* regrab previously allocated working_area, or allocate a new one */
if (!arm7_9->dcc_working_area) {
uint8_t dcc_code_buf[dcc_size];
/* make sure we have a working area */
if (target_alloc_working_area(target, dcc_size, &arm7_9->dcc_working_area) != ERROR_OK) {
LOG_INFO("no working area available, falling back to memory writes");
return target_write_memory(target, address, 4, count, buffer);
}
/* copy target instructions to target endianness */
for (i = 0; i < dcc_size/4; i++)
target_buffer_set_u32(target, dcc_code_buf + i*4, dcc_code[i]);
/* write DCC code to working area */
retval = target_write_memory(target,
arm7_9->dcc_working_area->address, 4, dcc_size/4, dcc_code_buf);
if (retval != ERROR_OK)
return retval;
}
/* backup clobbered processor state */
for (i = 0; i <= 5; i++)
save[i] = buf_get_u32(arm->core_cache->reg_list[i].value, 0, 32);
save[i] = buf_get_u32(arm->pc->value, 0, 32);
/* set up target address in r0 */
buf_set_u32(arm->core_cache->reg_list[0].value, 0, 32, address);
arm->core_cache->reg_list[0].valid = 1;
arm->core_cache->reg_list[0].dirty = 1;
arm->core_state = ARM_STATE_ARM;
embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_COMMS_DATA], 0);
arm7_9_resume(target, 0, arm7_9->dcc_working_area->address, 1, 1);
/* send data over */
x = 0;
flip = 0;
shift = 1;
for (i = 0; i < count; i++) {
uint32_t y = target_buffer_get_u32(target, buffer);
uint32_t z = (x >> 1) | (y >> shift) | (flip ^= 0x80000000);
embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_COMMS_DATA], z);
x = y << (32 - shift);
if (++shift >= 32 || i + 1 >= count) {
z = (x >> 1) | (flip ^= 0x80000000);
embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_COMMS_DATA], z);
x = 0;
shift = 1;
}
buffer += 4;
}
retval = target_halt(target);
if (retval == ERROR_OK)
retval = target_wait_state(target, TARGET_HALTED, 500);
if (retval == ERROR_OK) {
uint32_t endaddress =
buf_get_u32(arm->core_cache->reg_list[0].value, 0, 32);
if (endaddress != address + count*4) {
LOG_ERROR("DCC write failed,"
" expected end address 0x%08" PRIx32
" got 0x%0" PRIx32 "",
address + count*4, endaddress);
retval = ERROR_FAIL;
}
}
/* restore target state */
for (i = 0; i <= 5; i++) {
buf_set_u32(arm->core_cache->reg_list[i].value, 0, 32, save[i]);
arm->core_cache->reg_list[i].valid = 1;
arm->core_cache->reg_list[i].dirty = 1;
}
buf_set_u32(arm->pc->value, 0, 32, save[i]);
arm->pc->valid = 1;
arm->pc->dirty = 1;
arm->core_state = core_state;
return retval;
}
static int feroceon_init_target(struct command_context *cmd_ctx,
struct target *target)
{
arm9tdmi_init_target(cmd_ctx, target);
return ERROR_OK;
}
static void feroceon_common_setup(struct target *target)
{
struct arm *arm = target->arch_info;
struct arm7_9_common *arm7_9 = arm->arch_info;
/* override some insn sequence functions */
arm7_9->change_to_arm = feroceon_change_to_arm;
arm7_9->read_core_regs = feroceon_read_core_regs;
arm7_9->read_core_regs_target_buffer = feroceon_read_core_regs_target_buffer;
arm7_9->read_xpsr = feroceon_read_xpsr;
arm7_9->write_xpsr = feroceon_write_xpsr;
arm7_9->write_xpsr_im8 = feroceon_write_xpsr_im8;
arm7_9->write_core_regs = feroceon_write_core_regs;
arm7_9->branch_resume = feroceon_branch_resume;
arm7_9->branch_resume_thumb = feroceon_branch_resume_thumb;
/* must be implemented with only one comparator */
arm7_9->enable_single_step = feroceon_enable_single_step;
arm7_9->disable_single_step = feroceon_disable_single_step;
/* MOE is not implemented */
arm7_9->examine_debug_reason = feroceon_examine_debug_reason;
/* Note: asserting DBGRQ might not win over the undef exception.
If that happens then just use "arm7_9 dbgrq disable". */
arm7_9->use_dbgrq = 1;
arm7_9->set_special_dbgrq = feroceon_set_dbgrq;
/* only one working comparator */
arm7_9->wp_available_max = 1;
arm7_9->wp1_used_default = -1;
}
static int feroceon_target_create(struct target *target, Jim_Interp *interp)
{
struct arm926ejs_common *arm926ejs = calloc(1, sizeof(struct arm926ejs_common));
arm926ejs_init_arch_info(target, arm926ejs, target->tap);
feroceon_common_setup(target);
/* the standard ARM926 methods don't always work (don't ask...) */
arm926ejs->read_cp15 = feroceon_read_cp15;
arm926ejs->write_cp15 = feroceon_write_cp15;
return ERROR_OK;
}
static int dragonite_target_create(struct target *target, Jim_Interp *interp)
{
struct arm966e_common *arm966e = calloc(1, sizeof(struct arm966e_common));
arm966e_init_arch_info(target, arm966e, target->tap);
feroceon_common_setup(target);
return ERROR_OK;
}
static int feroceon_examine(struct target *target)
{
struct arm *arm;
struct arm7_9_common *arm7_9;
int retval;
retval = arm7_9_examine(target);
if (retval != ERROR_OK)
return retval;
arm = target->arch_info;
arm7_9 = arm->arch_info;
/* the COMMS_CTRL bits are all contiguous */
if (buf_get_u32(arm7_9->eice_cache->reg_list[EICE_COMMS_CTRL].value, 2, 4) != 6)
LOG_ERROR("unexpected Feroceon EICE version signature");
arm7_9->eice_cache->reg_list[EICE_DBG_CTRL].size = 6;
arm7_9->eice_cache->reg_list[EICE_DBG_STAT].size = 5;
arm7_9->has_monitor_mode = 1;
/* vector catch reg is not initialized on reset */
embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_VEC_CATCH], 0);
/* clear monitor mode, enable comparators */
embeddedice_read_reg(&arm7_9->eice_cache->reg_list[EICE_DBG_CTRL]);
jtag_execute_queue();
buf_set_u32(arm7_9->eice_cache->reg_list[EICE_DBG_CTRL].value, 4, 1, 0);
buf_set_u32(arm7_9->eice_cache->reg_list[EICE_DBG_CTRL].value, 5, 1, 0);
embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_DBG_CTRL]);
return ERROR_OK;
}
struct target_type feroceon_target = {
.name = "feroceon",
.poll = arm7_9_poll,
.arch_state = arm926ejs_arch_state,
.target_request_data = arm7_9_target_request_data,
.halt = arm7_9_halt,
.resume = arm7_9_resume,
.step = arm7_9_step,
.assert_reset = feroceon_assert_reset,
.deassert_reset = arm7_9_deassert_reset,
.soft_reset_halt = arm926ejs_soft_reset_halt,
.get_gdb_reg_list = arm_get_gdb_reg_list,
.read_memory = arm7_9_read_memory,
.write_memory = arm926ejs_write_memory,
.bulk_write_memory = feroceon_bulk_write_memory,
.checksum_memory = arm_checksum_memory,
.blank_check_memory = arm_blank_check_memory,
.run_algorithm = armv4_5_run_algorithm,
.add_breakpoint = arm7_9_add_breakpoint,
.remove_breakpoint = arm7_9_remove_breakpoint,
.add_watchpoint = arm7_9_add_watchpoint,
.remove_watchpoint = arm7_9_remove_watchpoint,
.commands = arm926ejs_command_handlers,
.target_create = feroceon_target_create,
.init_target = feroceon_init_target,
.examine = feroceon_examine,
};
struct target_type dragonite_target = {
.name = "dragonite",
.poll = arm7_9_poll,
.arch_state = arm_arch_state,
.target_request_data = arm7_9_target_request_data,
.halt = arm7_9_halt,
.resume = arm7_9_resume,
.step = arm7_9_step,
.assert_reset = feroceon_assert_reset,
.deassert_reset = arm7_9_deassert_reset,
.soft_reset_halt = arm7_9_soft_reset_halt,
.get_gdb_reg_list = arm_get_gdb_reg_list,
.read_memory = arm7_9_read_memory,
.write_memory = arm7_9_write_memory,
.bulk_write_memory = feroceon_bulk_write_memory,
.checksum_memory = arm_checksum_memory,
.blank_check_memory = arm_blank_check_memory,
.run_algorithm = armv4_5_run_algorithm,
.add_breakpoint = arm7_9_add_breakpoint,
.remove_breakpoint = arm7_9_remove_breakpoint,
.add_watchpoint = arm7_9_add_watchpoint,
.remove_watchpoint = arm7_9_remove_watchpoint,
.commands = arm966e_command_handlers,
.target_create = dragonite_target_create,
.init_target = feroceon_init_target,
.examine = feroceon_examine,
};

View File

@ -0,0 +1,822 @@
/***************************************************************************
* Copyright (C) 2011 by Mathias Kuester *
* Mathias Kuester <kesmtp@freenet.de> *
* *
* Copyright (C) 2011 by Spencer Oliver *
* spen@spen-soft.co.uk *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "jtag/jtag.h"
#include "jtag/hla/hla_transport.h"
#include "jtag/hla/hla_interface.h"
#include "jtag/hla/hla_layout.h"
#include "register.h"
#include "algorithm.h"
#include "target.h"
#include "breakpoints.h"
#include "target_type.h"
#include "armv7m.h"
#include "cortex_m.h"
#include "arm_semihosting.h"
#define ARMV7M_SCS_DCRSR 0xe000edf4
#define ARMV7M_SCS_DCRDR 0xe000edf8
static inline struct hl_interface_s *target_to_adapter(struct target *target)
{
return target->tap->priv;
}
static int adapter_load_core_reg_u32(struct target *target,
uint32_t num, uint32_t *value)
{
int retval;
struct hl_interface_s *adapter = target_to_adapter(target);
LOG_DEBUG("%s", __func__);
/* NOTE: we "know" here that the register identifiers used
* in the v7m header match the Cortex-M3 Debug Core Register
* Selector values for R0..R15, xPSR, MSP, and PSP.
*/
switch (num) {
case 0 ... 18:
/* read a normal core register */
retval = adapter->layout->api->read_reg(adapter->fd, num, value);
if (retval != ERROR_OK) {
LOG_ERROR("JTAG failure %i", retval);
return ERROR_JTAG_DEVICE_ERROR;
}
LOG_DEBUG("load from core reg %i value 0x%" PRIx32 "", (int)num, *value);
break;
case ARMV7M_FPSID:
case ARMV7M_FPEXC:
*value = 0;
break;
case ARMV7M_FPSCR:
/* Floating-point Status and Registers */
retval = target_write_u32(target, ARMV7M_SCS_DCRSR, 33);
if (retval != ERROR_OK)
return retval;
retval = target_read_u32(target, ARMV7M_SCS_DCRDR, value);
if (retval != ERROR_OK)
return retval;
LOG_DEBUG("load from core reg %i value 0x%" PRIx32 "", (int)num, *value);
break;
case ARMV7M_S0 ... ARMV7M_S31:
/* Floating-point Status and Registers */
retval = target_write_u32(target, ARMV7M_SCS_DCRSR, num-ARMV7M_S0+64);
if (retval != ERROR_OK)
return retval;
retval = target_read_u32(target, ARMV7M_SCS_DCRDR, value);
if (retval != ERROR_OK)
return retval;
LOG_DEBUG("load from core reg %i value 0x%" PRIx32 "", (int)num, *value);
break;
case ARMV7M_D0 ... ARMV7M_D15:
value = 0;
break;
case ARMV7M_PRIMASK:
case ARMV7M_BASEPRI:
case ARMV7M_FAULTMASK:
case ARMV7M_CONTROL:
/* Cortex-M3 packages these four registers as bitfields
* in one Debug Core register. So say r0 and r2 docs;
* it was removed from r1 docs, but still works.
*/
retval = adapter->layout->api->read_reg(adapter->fd, 20, value);
if (retval != ERROR_OK)
return retval;
switch (num) {
case ARMV7M_PRIMASK:
*value = buf_get_u32((uint8_t *) value, 0, 1);
break;
case ARMV7M_BASEPRI:
*value = buf_get_u32((uint8_t *) value, 8, 8);
break;
case ARMV7M_FAULTMASK:
*value = buf_get_u32((uint8_t *) value, 16, 1);
break;
case ARMV7M_CONTROL:
*value = buf_get_u32((uint8_t *) value, 24, 2);
break;
}
LOG_DEBUG("load from special reg %i value 0x%" PRIx32 "",
(int)num, *value);
break;
default:
return ERROR_COMMAND_SYNTAX_ERROR;
}
return ERROR_OK;
}
static int adapter_store_core_reg_u32(struct target *target,
uint32_t num, uint32_t value)
{
int retval;
uint32_t reg;
struct armv7m_common *armv7m = target_to_armv7m(target);
struct hl_interface_s *adapter = target_to_adapter(target);
LOG_DEBUG("%s", __func__);
#ifdef ARMV7_GDB_HACKS
/* If the LR register is being modified, make sure it will put us
* in "thumb" mode, or an INVSTATE exception will occur. This is a
* hack to deal with the fact that gdb will sometimes "forge"
* return addresses, and doesn't set the LSB correctly (i.e., when
* printing expressions containing function calls, it sets LR = 0.)
* Valid exception return codes have bit 0 set too.
*/
if (num == ARMV7M_R14)
value |= 0x01;
#endif
/* NOTE: we "know" here that the register identifiers used
* in the v7m header match the Cortex-M3 Debug Core Register
* Selector values for R0..R15, xPSR, MSP, and PSP.
*/
switch (num) {
case 0 ... 18:
retval = adapter->layout->api->write_reg(adapter->fd, num, value);
if (retval != ERROR_OK) {
struct reg *r;
LOG_ERROR("JTAG failure");
r = armv7m->arm.core_cache->reg_list + num;
r->dirty = r->valid;
return ERROR_JTAG_DEVICE_ERROR;
}
LOG_DEBUG("write core reg %i value 0x%" PRIx32 "", (int)num, value);
break;
case ARMV7M_FPSID:
case ARMV7M_FPEXC:
break;
case ARMV7M_FPSCR:
/* Floating-point Status and Registers */
retval = target_write_u32(target, ARMV7M_SCS_DCRDR, value);
if (retval != ERROR_OK)
return retval;
retval = target_write_u32(target, ARMV7M_SCS_DCRSR, 33 | (1<<16));
if (retval != ERROR_OK)
return retval;
LOG_DEBUG("write core reg %i value 0x%" PRIx32 "", (int)num, value);
break;
case ARMV7M_S0 ... ARMV7M_S31:
/* Floating-point Status and Registers */
retval = target_write_u32(target, ARMV7M_SCS_DCRDR, value);
if (retval != ERROR_OK)
return retval;
retval = target_write_u32(target, ARMV7M_SCS_DCRSR, (num-ARMV7M_S0+64) | (1<<16));
if (retval != ERROR_OK)
return retval;
LOG_DEBUG("write core reg %i value 0x%" PRIx32 "", (int)num, value);
break;
case ARMV7M_D0 ... ARMV7M_D15:
break;
case ARMV7M_PRIMASK:
case ARMV7M_BASEPRI:
case ARMV7M_FAULTMASK:
case ARMV7M_CONTROL:
/* Cortex-M3 packages these four registers as bitfields
* in one Debug Core register. So say r0 and r2 docs;
* it was removed from r1 docs, but still works.
*/
adapter->layout->api->read_reg(adapter->fd, 20, &reg);
switch (num) {
case ARMV7M_PRIMASK:
buf_set_u32((uint8_t *) &reg, 0, 1, value);
break;
case ARMV7M_BASEPRI:
buf_set_u32((uint8_t *) &reg, 8, 8, value);
break;
case ARMV7M_FAULTMASK:
buf_set_u32((uint8_t *) &reg, 16, 1, value);
break;
case ARMV7M_CONTROL:
buf_set_u32((uint8_t *) &reg, 24, 2, value);
break;
}
adapter->layout->api->write_reg(adapter->fd, 20, reg);
LOG_DEBUG("write special reg %i value 0x%" PRIx32 " ", (int)num, value);
break;
default:
return ERROR_COMMAND_SYNTAX_ERROR;
}
return ERROR_OK;
}
static int adapter_examine_debug_reason(struct target *target)
{
if ((target->debug_reason != DBG_REASON_DBGRQ)
&& (target->debug_reason != DBG_REASON_SINGLESTEP)) {
target->debug_reason = DBG_REASON_BREAKPOINT;
}
return ERROR_OK;
}
static int adapter_init_arch_info(struct target *target,
struct cortex_m3_common *cortex_m3,
struct jtag_tap *tap)
{
struct armv7m_common *armv7m;
LOG_DEBUG("%s", __func__);
armv7m = &cortex_m3->armv7m;
armv7m_init_arch_info(target, armv7m);
armv7m->load_core_reg_u32 = adapter_load_core_reg_u32;
armv7m->store_core_reg_u32 = adapter_store_core_reg_u32;
armv7m->examine_debug_reason = adapter_examine_debug_reason;
armv7m->stlink = true;
return ERROR_OK;
}
static int adapter_init_target(struct command_context *cmd_ctx,
struct target *target)
{
LOG_DEBUG("%s", __func__);
armv7m_build_reg_cache(target);
return ERROR_OK;
}
static int adapter_target_create(struct target *target,
Jim_Interp *interp)
{
LOG_DEBUG("%s", __func__);
struct cortex_m3_common *cortex_m3 = calloc(1, sizeof(struct cortex_m3_common));
if (!cortex_m3)
return ERROR_COMMAND_SYNTAX_ERROR;
adapter_init_arch_info(target, cortex_m3, target->tap);
return ERROR_OK;
}
static int adapter_load_context(struct target *target)
{
struct armv7m_common *armv7m = target_to_armv7m(target);
int num_regs = armv7m->arm.core_cache->num_regs;
for (int i = 0; i < num_regs; i++) {
struct reg *r = &armv7m->arm.core_cache->reg_list[i];
if (!r->valid)
armv7m->arm.read_core_reg(target, r, i, ARM_MODE_ANY);
}
return ERROR_OK;
}
static int adapter_debug_entry(struct target *target)
{
struct hl_interface_s *adapter = target_to_adapter(target);
struct armv7m_common *armv7m = target_to_armv7m(target);
struct arm *arm = &armv7m->arm;
struct reg *r;
uint32_t xPSR;
int retval;
retval = armv7m->examine_debug_reason(target);
if (retval != ERROR_OK)
return retval;
adapter_load_context(target);
/* make sure we clear the vector catch bit */
adapter->layout->api->write_debug_reg(adapter->fd, DCB_DEMCR, TRCENA);
r = arm->core_cache->reg_list + ARMV7M_xPSR;
xPSR = buf_get_u32(r->value, 0, 32);
/* Are we in an exception handler */
if (xPSR & 0x1FF) {
armv7m->exception_number = (xPSR & 0x1FF);
arm->core_mode = ARM_MODE_HANDLER;
arm->map = armv7m_msp_reg_map;
} else {
unsigned control = buf_get_u32(arm->core_cache
->reg_list[ARMV7M_CONTROL].value, 0, 2);
/* is this thread privileged? */
arm->core_mode = control & 1
? ARM_MODE_USER_THREAD
: ARM_MODE_THREAD;
/* which stack is it using? */
if (control & 2)
arm->map = armv7m_psp_reg_map;
else
arm->map = armv7m_msp_reg_map;
armv7m->exception_number = 0;
}
LOG_DEBUG("entered debug state in core mode: %s at PC 0x%08" PRIx32 ", target->state: %s",
arm_mode_name(arm->core_mode),
*(uint32_t *)(arm->pc->value),
target_state_name(target));
return retval;
}
static int adapter_poll(struct target *target)
{
enum target_state state;
struct hl_interface_s *adapter = target_to_adapter(target);
struct armv7m_common *armv7m = target_to_armv7m(target);
enum target_state prev_target_state = target->state;
state = adapter->layout->api->state(adapter->fd);
if (state == TARGET_UNKNOWN) {
LOG_ERROR("jtag status contains invalid mode value - communication failure");
return ERROR_TARGET_FAILURE;
}
if (target->state == state)
return ERROR_OK;
if (state == TARGET_HALTED) {
target->state = state;
int retval = adapter_debug_entry(target);
if (retval != ERROR_OK)
return retval;
if (prev_target_state == TARGET_DEBUG_RUNNING) {
target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED);
} else {
if (arm_semihosting(target, &retval) != 0)
return retval;
target_call_event_callbacks(target, TARGET_EVENT_HALTED);
}
LOG_DEBUG("halted: PC: 0x%08x", buf_get_u32(armv7m->arm.pc->value, 0, 32));
}
return ERROR_OK;
}
static int adapter_assert_reset(struct target *target)
{
int res = ERROR_OK;
struct hl_interface_s *adapter = target_to_adapter(target);
struct armv7m_common *armv7m = target_to_armv7m(target);
bool use_srst_fallback = true;
LOG_DEBUG("%s", __func__);
enum reset_types jtag_reset_config = jtag_get_reset_config();
bool srst_asserted = false;
if (jtag_reset_config & RESET_SRST_NO_GATING) {
jtag_add_reset(0, 1);
res = adapter->layout->api->assert_srst(adapter->fd, 0);
srst_asserted = true;
}
adapter->layout->api->write_debug_reg(adapter->fd, DCB_DHCSR, DBGKEY|C_DEBUGEN);
/* only set vector catch if halt is requested */
if (target->reset_halt)
adapter->layout->api->write_debug_reg(adapter->fd, DCB_DEMCR, TRCENA|VC_CORERESET);
else
adapter->layout->api->write_debug_reg(adapter->fd, DCB_DEMCR, TRCENA);
if (jtag_reset_config & RESET_HAS_SRST) {
if (!srst_asserted) {
jtag_add_reset(0, 1);
res = adapter->layout->api->assert_srst(adapter->fd, 0);
}
if (res == ERROR_COMMAND_NOTFOUND)
LOG_ERROR("Hardware srst not supported, falling back to software reset");
else if (res == ERROR_OK) {
/* hardware srst supported */
use_srst_fallback = false;
}
}
if (use_srst_fallback) {
/* stlink v1 api does not support hardware srst, so we use a software reset fallback */
adapter->layout->api->write_debug_reg(adapter->fd, NVIC_AIRCR, AIRCR_VECTKEY | AIRCR_SYSRESETREQ);
}
res = adapter->layout->api->reset(adapter->fd);
if (res != ERROR_OK)
return res;
/* registers are now invalid */
register_cache_invalidate(armv7m->arm.core_cache);
if (target->reset_halt) {
target->state = TARGET_RESET;
target->debug_reason = DBG_REASON_DBGRQ;
} else {
target->state = TARGET_HALTED;
}
return ERROR_OK;
}
static int adapter_deassert_reset(struct target *target)
{
int res;
struct hl_interface_s *adapter = target_to_adapter(target);
enum reset_types jtag_reset_config = jtag_get_reset_config();
LOG_DEBUG("%s", __func__);
if (jtag_reset_config & RESET_HAS_SRST)
adapter->layout->api->assert_srst(adapter->fd, 1);
/* virtual deassert reset, we need it for the internal
* jtag state machine
*/
jtag_add_reset(0, 0);
if (!target->reset_halt) {
res = target_resume(target, 1, 0, 0, 0);
if (res != ERROR_OK)
return res;
}
return ERROR_OK;
}
static int adapter_soft_reset_halt(struct target *target)
{
LOG_DEBUG("%s", __func__);
return ERROR_OK;
}
static int adapter_halt(struct target *target)
{
int res;
struct hl_interface_s *adapter = target_to_adapter(target);
LOG_DEBUG("%s", __func__);
if (target->state == TARGET_HALTED) {
LOG_DEBUG("target was already halted");
return ERROR_OK;
}
if (target->state == TARGET_UNKNOWN)
LOG_WARNING("target was in unknown state when halt was requested");
res = adapter->layout->api->halt(adapter->fd);
if (res != ERROR_OK)
return res;
target->debug_reason = DBG_REASON_DBGRQ;
return ERROR_OK;
}
static int adapter_resume(struct target *target, int current,
uint32_t address, int handle_breakpoints,
int debug_execution)
{
int res;
struct hl_interface_s *adapter = target_to_adapter(target);
struct armv7m_common *armv7m = target_to_armv7m(target);
uint32_t resume_pc;
struct breakpoint *breakpoint = NULL;
struct reg *pc;
LOG_DEBUG("%s %d 0x%08x %d %d", __func__, current, address,
handle_breakpoints, debug_execution);
if (target->state != TARGET_HALTED) {
LOG_WARNING("target not halted");
return ERROR_TARGET_NOT_HALTED;
}
if (!debug_execution) {
target_free_all_working_areas(target);
cortex_m3_enable_breakpoints(target);
cortex_m3_enable_watchpoints(target);
}
pc = armv7m->arm.pc;
if (!current) {
buf_set_u32(pc->value, 0, 32, address);
pc->dirty = true;
pc->valid = true;
}
if (!breakpoint_find(target, buf_get_u32(pc->value, 0, 32))
&& !debug_execution) {
armv7m_maybe_skip_bkpt_inst(target, NULL);
}
resume_pc = buf_get_u32(pc->value, 0, 32);
/* write any user vector flags */
res = target_write_u32(target, DCB_DEMCR, TRCENA | armv7m->demcr);
if (res != ERROR_OK)
return res;
armv7m_restore_context(target);
/* registers are now invalid */
register_cache_invalidate(armv7m->arm.core_cache);
/* the front-end may request us not to handle breakpoints */
if (handle_breakpoints) {
/* Single step past breakpoint at current address */
breakpoint = breakpoint_find(target, resume_pc);
if (breakpoint) {
LOG_DEBUG("unset breakpoint at 0x%8.8" PRIx32 " (ID: %d)",
breakpoint->address,
breakpoint->unique_id);
cortex_m3_unset_breakpoint(target, breakpoint);
res = adapter->layout->api->step(adapter->fd);
if (res != ERROR_OK)
return res;
cortex_m3_set_breakpoint(target, breakpoint);
}
}
res = adapter->layout->api->run(adapter->fd);
if (res != ERROR_OK)
return res;
target->debug_reason = DBG_REASON_NOTHALTED;
if (!debug_execution) {
target->state = TARGET_RUNNING;
target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
} else {
target->state = TARGET_DEBUG_RUNNING;
target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED);
}
return ERROR_OK;
}
static int adapter_step(struct target *target, int current,
uint32_t address, int handle_breakpoints)
{
int res;
struct hl_interface_s *adapter = target_to_adapter(target);
struct armv7m_common *armv7m = target_to_armv7m(target);
struct breakpoint *breakpoint = NULL;
struct reg *pc = armv7m->arm.pc;
bool bkpt_inst_found = false;
LOG_DEBUG("%s", __func__);
if (target->state != TARGET_HALTED) {
LOG_WARNING("target not halted");
return ERROR_TARGET_NOT_HALTED;
}
if (!current) {
buf_set_u32(pc->value, 0, 32, address);
pc->dirty = true;
pc->valid = true;
}
uint32_t pc_value = buf_get_u32(pc->value, 0, 32);
/* the front-end may request us not to handle breakpoints */
if (handle_breakpoints) {
breakpoint = breakpoint_find(target, pc_value);
if (breakpoint)
cortex_m3_unset_breakpoint(target, breakpoint);
}
armv7m_maybe_skip_bkpt_inst(target, &bkpt_inst_found);
target->debug_reason = DBG_REASON_SINGLESTEP;
armv7m_restore_context(target);
target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
res = adapter->layout->api->step(adapter->fd);
if (res != ERROR_OK)
return res;
/* registers are now invalid */
register_cache_invalidate(armv7m->arm.core_cache);
if (breakpoint)
cortex_m3_set_breakpoint(target, breakpoint);
adapter_debug_entry(target);
target_call_event_callbacks(target, TARGET_EVENT_HALTED);
LOG_INFO("halted: PC: 0x%08x", buf_get_u32(armv7m->arm.pc->value, 0, 32));
return ERROR_OK;
}
static int adapter_read_memory(struct target *target, uint32_t address,
uint32_t size, uint32_t count,
uint8_t *buffer)
{
struct hl_interface_s *adapter = target_to_adapter(target);
int res;
uint32_t buffer_threshold = (adapter->param.max_buffer / 4);
uint32_t addr_increment = 4;
uint32_t c;
if (!count || !buffer)
return ERROR_COMMAND_SYNTAX_ERROR;
LOG_DEBUG("%s 0x%08x %d %d", __func__, address, size, count);
/* prepare byte count, buffer threshold
* and address increment for none 32bit access
*/
if (size != 4) {
count *= size;
buffer_threshold = (adapter->param.max_buffer / 4) / 2;
addr_increment = 1;
}
while (count) {
if (count > buffer_threshold)
c = buffer_threshold;
else
c = count;
if (size != 4)
res = adapter->layout->api->read_mem8(adapter->fd,
address, c, buffer);
else
res = adapter->layout->api->read_mem32(adapter->fd,
address, c, buffer);
if (res != ERROR_OK)
return res;
address += (c * addr_increment);
buffer += (c * addr_increment);
count -= c;
}
return ERROR_OK;
}
static int adapter_write_memory(struct target *target, uint32_t address,
uint32_t size, uint32_t count,
const uint8_t *buffer)
{
struct hl_interface_s *adapter = target_to_adapter(target);
int res;
uint32_t buffer_threshold = (adapter->param.max_buffer / 4);
uint32_t addr_increment = 4;
uint32_t c;
if (!count || !buffer)
return ERROR_COMMAND_SYNTAX_ERROR;
LOG_DEBUG("%s 0x%08x %d %d", __func__, address, size, count);
/* prepare byte count, buffer threshold
* and address increment for none 32bit access
*/
if (size != 4) {
count *= size;
buffer_threshold = (adapter->param.max_buffer / 4) / 2;
addr_increment = 1;
}
while (count) {
if (count > buffer_threshold)
c = buffer_threshold;
else
c = count;
if (size != 4)
res = adapter->layout->api->write_mem8(adapter->fd,
address, c, buffer);
else
res = adapter->layout->api->write_mem32(adapter->fd,
address, c, buffer);
if (res != ERROR_OK)
return res;
address += (c * addr_increment);
buffer += (c * addr_increment);
count -= c;
}
return ERROR_OK;
}
static const struct command_registration adapter_command_handlers[] = {
{
.chain = arm_command_handlers,
},
COMMAND_REGISTRATION_DONE
};
struct target_type hla_target = {
.name = "hla_target",
.deprecated_name = "stm32_stlink",
.init_target = adapter_init_target,
.target_create = adapter_target_create,
.examine = cortex_m3_examine,
.commands = adapter_command_handlers,
.poll = adapter_poll,
.arch_state = armv7m_arch_state,
.assert_reset = adapter_assert_reset,
.deassert_reset = adapter_deassert_reset,
.soft_reset_halt = adapter_soft_reset_halt,
.halt = adapter_halt,
.resume = adapter_resume,
.step = adapter_step,
.get_gdb_reg_list = armv7m_get_gdb_reg_list,
.read_memory = adapter_read_memory,
.write_memory = adapter_write_memory,
.checksum_memory = armv7m_checksum_memory,
.blank_check_memory = armv7m_blank_check_memory,
.run_algorithm = armv7m_run_algorithm,
.start_algorithm = armv7m_start_algorithm,
.wait_algorithm = armv7m_wait_algorithm,
.add_breakpoint = cortex_m3_add_breakpoint,
.remove_breakpoint = cortex_m3_remove_breakpoint,
.add_watchpoint = cortex_m3_add_watchpoint,
.remove_watchpoint = cortex_m3_remove_watchpoint,
};

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,112 @@
/***************************************************************************
* Copyright (C) 2007 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* Copyright (C) 2007,2008 Øyvind Harboe *
* oyvind.harboe@zylin.com *
* *
* Copyright (C) 2008 by Spencer Oliver *
* spen@spen-soft.co.uk *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef IMAGE_H
#define IMAGE_H
#include <helper/fileio.h>
#ifdef HAVE_ELF_H
#include <elf.h>
#endif
#define IMAGE_MAX_ERROR_STRING (256)
#define IMAGE_MAX_SECTIONS (512)
#define IMAGE_MEMORY_CACHE_SIZE (2048)
enum image_type {
IMAGE_BINARY, /* plain binary */
IMAGE_IHEX, /* intel hex-record format */
IMAGE_MEMORY, /* target-memory pseudo-image */
IMAGE_ELF, /* ELF binary */
IMAGE_SRECORD, /* motorola s19 */
IMAGE_BUILDER, /* when building a new image */
};
struct imagesection {
uint32_t base_address;
uint32_t size;
int flags;
void *private; /* private data */
};
struct image {
enum image_type type; /* image type (plain, ihex, ...) */
void *type_private; /* type private data */
int num_sections; /* number of sections contained in the image */
struct imagesection *sections; /* array of sections */
int base_address_set; /* whether the image has a base address set (for relocation purposes) */
long long base_address; /* base address, if one is set */
int start_address_set; /* whether the image has a start address (entry point) associated */
uint32_t start_address; /* start address, if one is set */
};
struct image_binary {
struct fileio fileio;
};
struct image_ihex {
struct fileio fileio;
uint8_t *buffer;
};
struct image_memory {
struct target *target;
uint8_t *cache;
uint32_t cache_address;
};
struct image_elf {
struct fileio fileio;
Elf32_Ehdr *header;
Elf32_Phdr *segments;
uint32_t segment_count;
uint8_t endianness;
};
struct image_mot {
struct fileio fileio;
uint8_t *buffer;
};
int image_open(struct image *image, const char *url, const char *type_string);
int image_read_section(struct image *image, int section, uint32_t offset,
uint32_t size, uint8_t *buffer, size_t *size_read);
void image_close(struct image *image);
int image_add_section(struct image *image, uint32_t base, uint32_t size,
int flags, uint8_t *data);
int image_calculate_checksum(uint8_t *buffer, uint32_t nbytes,
uint32_t *checksum);
#define ERROR_IMAGE_FORMAT_ERROR (-1400)
#define ERROR_IMAGE_TYPE_UNKNOWN (-1401)
#define ERROR_IMAGE_TEMPORARILY_UNAVAILABLE (-1402)
#define ERROR_IMAGE_CHECKSUM (-1403)
#endif /* IMAGE_H */

View File

@ -0,0 +1,835 @@
/***************************************************************************
* Copyright (C) 2008 by Spencer Oliver *
* spen@spen-soft.co.uk *
* *
* Copyright (C) 2008 by David T.L. Wong *
* *
* Copyright (C) 2007,2008 Øyvind Harboe *
* oyvind.harboe@zylin.com *
* *
* Copyright (C) 2011 by Drasko DRASKOVIC *
* drasko.draskovic@gmail.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "mips32.h"
#include "breakpoints.h"
#include "algorithm.h"
#include "register.h"
static char *mips32_core_reg_list[] = {
"zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
"t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
"s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
"t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra",
"status", "lo", "hi", "badvaddr", "cause", "pc"
};
static const char *mips_isa_strings[] = {
"MIPS32", "MIPS16e"
};
static struct mips32_core_reg mips32_core_reg_list_arch_info[MIPS32NUMCOREREGS] = {
{0, NULL, NULL},
{1, NULL, NULL},
{2, NULL, NULL},
{3, NULL, NULL},
{4, NULL, NULL},
{5, NULL, NULL},
{6, NULL, NULL},
{7, NULL, NULL},
{8, NULL, NULL},
{9, NULL, NULL},
{10, NULL, NULL},
{11, NULL, NULL},
{12, NULL, NULL},
{13, NULL, NULL},
{14, NULL, NULL},
{15, NULL, NULL},
{16, NULL, NULL},
{17, NULL, NULL},
{18, NULL, NULL},
{19, NULL, NULL},
{20, NULL, NULL},
{21, NULL, NULL},
{22, NULL, NULL},
{23, NULL, NULL},
{24, NULL, NULL},
{25, NULL, NULL},
{26, NULL, NULL},
{27, NULL, NULL},
{28, NULL, NULL},
{29, NULL, NULL},
{30, NULL, NULL},
{31, NULL, NULL},
{32, NULL, NULL},
{33, NULL, NULL},
{34, NULL, NULL},
{35, NULL, NULL},
{36, NULL, NULL},
{37, NULL, NULL},
};
/* number of mips dummy fp regs fp0 - fp31 + fsr and fir
* we also add 18 unknown registers to handle gdb requests */
#define MIPS32NUMFPREGS (34 + 18)
static uint8_t mips32_gdb_dummy_fp_value[] = {0, 0, 0, 0};
static struct reg mips32_gdb_dummy_fp_reg = {
.name = "GDB dummy floating-point register",
.value = mips32_gdb_dummy_fp_value,
.dirty = 0,
.valid = 1,
.size = 32,
.arch_info = NULL,
};
static int mips32_get_core_reg(struct reg *reg)
{
int retval;
struct mips32_core_reg *mips32_reg = reg->arch_info;
struct target *target = mips32_reg->target;
struct mips32_common *mips32_target = target_to_mips32(target);
if (target->state != TARGET_HALTED)
return ERROR_TARGET_NOT_HALTED;
retval = mips32_target->read_core_reg(target, mips32_reg->num);
return retval;
}
static int mips32_set_core_reg(struct reg *reg, uint8_t *buf)
{
struct mips32_core_reg *mips32_reg = reg->arch_info;
struct target *target = mips32_reg->target;
uint32_t value = buf_get_u32(buf, 0, 32);
if (target->state != TARGET_HALTED)
return ERROR_TARGET_NOT_HALTED;
buf_set_u32(reg->value, 0, 32, value);
reg->dirty = 1;
reg->valid = 1;
return ERROR_OK;
}
static int mips32_read_core_reg(struct target *target, int num)
{
uint32_t reg_value;
/* get pointers to arch-specific information */
struct mips32_common *mips32 = target_to_mips32(target);
if ((num < 0) || (num >= MIPS32NUMCOREREGS))
return ERROR_COMMAND_SYNTAX_ERROR;
reg_value = mips32->core_regs[num];
buf_set_u32(mips32->core_cache->reg_list[num].value, 0, 32, reg_value);
mips32->core_cache->reg_list[num].valid = 1;
mips32->core_cache->reg_list[num].dirty = 0;
return ERROR_OK;
}
static int mips32_write_core_reg(struct target *target, int num)
{
uint32_t reg_value;
/* get pointers to arch-specific information */
struct mips32_common *mips32 = target_to_mips32(target);
if ((num < 0) || (num >= MIPS32NUMCOREREGS))
return ERROR_COMMAND_SYNTAX_ERROR;
reg_value = buf_get_u32(mips32->core_cache->reg_list[num].value, 0, 32);
mips32->core_regs[num] = reg_value;
LOG_DEBUG("write core reg %i value 0x%" PRIx32 "", num , reg_value);
mips32->core_cache->reg_list[num].valid = 1;
mips32->core_cache->reg_list[num].dirty = 0;
return ERROR_OK;
}
int mips32_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size)
{
/* get pointers to arch-specific information */
struct mips32_common *mips32 = target_to_mips32(target);
int i;
/* include floating point registers */
*reg_list_size = MIPS32NUMCOREREGS + MIPS32NUMFPREGS;
*reg_list = malloc(sizeof(struct reg *) * (*reg_list_size));
for (i = 0; i < MIPS32NUMCOREREGS; i++)
(*reg_list)[i] = &mips32->core_cache->reg_list[i];
/* add dummy floating points regs */
for (i = MIPS32NUMCOREREGS; i < (MIPS32NUMCOREREGS + MIPS32NUMFPREGS); i++)
(*reg_list)[i] = &mips32_gdb_dummy_fp_reg;
return ERROR_OK;
}
int mips32_save_context(struct target *target)
{
int i;
/* get pointers to arch-specific information */
struct mips32_common *mips32 = target_to_mips32(target);
struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
/* read core registers */
mips32_pracc_read_regs(ejtag_info, mips32->core_regs);
for (i = 0; i < MIPS32NUMCOREREGS; i++) {
if (!mips32->core_cache->reg_list[i].valid)
mips32->read_core_reg(target, i);
}
return ERROR_OK;
}
int mips32_restore_context(struct target *target)
{
int i;
/* get pointers to arch-specific information */
struct mips32_common *mips32 = target_to_mips32(target);
struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
for (i = 0; i < MIPS32NUMCOREREGS; i++) {
if (mips32->core_cache->reg_list[i].dirty)
mips32->write_core_reg(target, i);
}
/* write core regs */
mips32_pracc_write_regs(ejtag_info, mips32->core_regs);
return ERROR_OK;
}
int mips32_arch_state(struct target *target)
{
struct mips32_common *mips32 = target_to_mips32(target);
LOG_USER("target halted in %s mode due to %s, pc: 0x%8.8" PRIx32 "",
mips_isa_strings[mips32->isa_mode],
debug_reason_name(target),
buf_get_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 32));
return ERROR_OK;
}
static const struct reg_arch_type mips32_reg_type = {
.get = mips32_get_core_reg,
.set = mips32_set_core_reg,
};
struct reg_cache *mips32_build_reg_cache(struct target *target)
{
/* get pointers to arch-specific information */
struct mips32_common *mips32 = target_to_mips32(target);
int num_regs = MIPS32NUMCOREREGS;
struct reg_cache **cache_p = register_get_last_cache_p(&target->reg_cache);
struct reg_cache *cache = malloc(sizeof(struct reg_cache));
struct reg *reg_list = malloc(sizeof(struct reg) * num_regs);
struct mips32_core_reg *arch_info = malloc(sizeof(struct mips32_core_reg) * num_regs);
int i;
register_init_dummy(&mips32_gdb_dummy_fp_reg);
/* Build the process context cache */
cache->name = "mips32 registers";
cache->next = NULL;
cache->reg_list = reg_list;
cache->num_regs = num_regs;
(*cache_p) = cache;
mips32->core_cache = cache;
for (i = 0; i < num_regs; i++) {
arch_info[i] = mips32_core_reg_list_arch_info[i];
arch_info[i].target = target;
arch_info[i].mips32_common = mips32;
reg_list[i].name = mips32_core_reg_list[i];
reg_list[i].size = 32;
reg_list[i].value = calloc(1, 4);
reg_list[i].dirty = 0;
reg_list[i].valid = 0;
reg_list[i].type = &mips32_reg_type;
reg_list[i].arch_info = &arch_info[i];
}
return cache;
}
int mips32_init_arch_info(struct target *target, struct mips32_common *mips32, struct jtag_tap *tap)
{
target->arch_info = mips32;
mips32->common_magic = MIPS32_COMMON_MAGIC;
mips32->fast_data_area = NULL;
/* has breakpoint/watchpint unit been scanned */
mips32->bp_scanned = 0;
mips32->data_break_list = NULL;
mips32->ejtag_info.tap = tap;
mips32->read_core_reg = mips32_read_core_reg;
mips32->write_core_reg = mips32_write_core_reg;
mips32->ejtag_info.scan_delay = 2000000; /* Initial default value */
mips32->ejtag_info.mode = 0; /* Initial default value */
return ERROR_OK;
}
/* run to exit point. return error if exit point was not reached. */
static int mips32_run_and_wait(struct target *target, uint32_t entry_point,
int timeout_ms, uint32_t exit_point, struct mips32_common *mips32)
{
uint32_t pc;
int retval;
/* This code relies on the target specific resume() and poll()->debug_entry()
* sequence to write register values to the processor and the read them back */
retval = target_resume(target, 0, entry_point, 0, 1);
if (retval != ERROR_OK)
return retval;
retval = target_wait_state(target, TARGET_HALTED, timeout_ms);
/* If the target fails to halt due to the breakpoint, force a halt */
if (retval != ERROR_OK || target->state != TARGET_HALTED) {
retval = target_halt(target);
if (retval != ERROR_OK)
return retval;
retval = target_wait_state(target, TARGET_HALTED, 500);
if (retval != ERROR_OK)
return retval;
return ERROR_TARGET_TIMEOUT;
}
pc = buf_get_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 32);
if (exit_point && (pc != exit_point)) {
LOG_DEBUG("failed algorithm halted at 0x%" PRIx32 " ", pc);
return ERROR_TARGET_TIMEOUT;
}
return ERROR_OK;
}
int mips32_run_algorithm(struct target *target, int num_mem_params,
struct mem_param *mem_params, int num_reg_params,
struct reg_param *reg_params, uint32_t entry_point,
uint32_t exit_point, int timeout_ms, void *arch_info)
{
struct mips32_common *mips32 = target_to_mips32(target);
struct mips32_algorithm *mips32_algorithm_info = arch_info;
enum mips32_isa_mode isa_mode = mips32->isa_mode;
uint32_t context[MIPS32NUMCOREREGS];
int i;
int retval = ERROR_OK;
LOG_DEBUG("Running algorithm");
/* NOTE: mips32_run_algorithm requires that each algorithm uses a software breakpoint
* at the exit point */
if (mips32->common_magic != MIPS32_COMMON_MAGIC) {
LOG_ERROR("current target isn't a MIPS32 target");
return ERROR_TARGET_INVALID;
}
if (target->state != TARGET_HALTED) {
LOG_WARNING("target not halted");
return ERROR_TARGET_NOT_HALTED;
}
/* refresh core register cache */
for (i = 0; i < MIPS32NUMCOREREGS; i++) {
if (!mips32->core_cache->reg_list[i].valid)
mips32->read_core_reg(target, i);
context[i] = buf_get_u32(mips32->core_cache->reg_list[i].value, 0, 32);
}
for (i = 0; i < num_mem_params; i++) {
retval = target_write_buffer(target, mem_params[i].address,
mem_params[i].size, mem_params[i].value);
if (retval != ERROR_OK)
return retval;
}
for (i = 0; i < num_reg_params; i++) {
struct reg *reg = register_get_by_name(mips32->core_cache, reg_params[i].reg_name, 0);
if (!reg) {
LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name);
return ERROR_COMMAND_SYNTAX_ERROR;
}
if (reg->size != reg_params[i].size) {
LOG_ERROR("BUG: register '%s' size doesn't match reg_params[i].size",
reg_params[i].reg_name);
return ERROR_COMMAND_SYNTAX_ERROR;
}
mips32_set_core_reg(reg, reg_params[i].value);
}
mips32->isa_mode = mips32_algorithm_info->isa_mode;
retval = mips32_run_and_wait(target, entry_point, timeout_ms, exit_point, mips32);
if (retval != ERROR_OK)
return retval;
for (i = 0; i < num_mem_params; i++) {
if (mem_params[i].direction != PARAM_OUT) {
retval = target_read_buffer(target, mem_params[i].address, mem_params[i].size,
mem_params[i].value);
if (retval != ERROR_OK)
return retval;
}
}
for (i = 0; i < num_reg_params; i++) {
if (reg_params[i].direction != PARAM_OUT) {
struct reg *reg = register_get_by_name(mips32->core_cache, reg_params[i].reg_name, 0);
if (!reg) {
LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name);
return ERROR_COMMAND_SYNTAX_ERROR;
}
if (reg->size != reg_params[i].size) {
LOG_ERROR("BUG: register '%s' size doesn't match reg_params[i].size",
reg_params[i].reg_name);
return ERROR_COMMAND_SYNTAX_ERROR;
}
buf_set_u32(reg_params[i].value, 0, 32, buf_get_u32(reg->value, 0, 32));
}
}
/* restore everything we saved before */
for (i = 0; i < MIPS32NUMCOREREGS; i++) {
uint32_t regvalue;
regvalue = buf_get_u32(mips32->core_cache->reg_list[i].value, 0, 32);
if (regvalue != context[i]) {
LOG_DEBUG("restoring register %s with value 0x%8.8" PRIx32,
mips32->core_cache->reg_list[i].name, context[i]);
buf_set_u32(mips32->core_cache->reg_list[i].value,
0, 32, context[i]);
mips32->core_cache->reg_list[i].valid = 1;
mips32->core_cache->reg_list[i].dirty = 1;
}
}
mips32->isa_mode = isa_mode;
return ERROR_OK;
}
int mips32_examine(struct target *target)
{
struct mips32_common *mips32 = target_to_mips32(target);
if (!target_was_examined(target)) {
target_set_examined(target);
/* we will configure later */
mips32->bp_scanned = 0;
mips32->num_inst_bpoints = 0;
mips32->num_data_bpoints = 0;
mips32->num_inst_bpoints_avail = 0;
mips32->num_data_bpoints_avail = 0;
}
return ERROR_OK;
}
int mips32_configure_break_unit(struct target *target)
{
/* get pointers to arch-specific information */
struct mips32_common *mips32 = target_to_mips32(target);
int retval;
uint32_t dcr, bpinfo;
int i;
if (mips32->bp_scanned)
return ERROR_OK;
/* get info about breakpoint support */
retval = target_read_u32(target, EJTAG_DCR, &dcr);
if (retval != ERROR_OK)
return retval;
if (dcr & EJTAG_DCR_IB) {
/* get number of inst breakpoints */
retval = target_read_u32(target, EJTAG_IBS, &bpinfo);
if (retval != ERROR_OK)
return retval;
mips32->num_inst_bpoints = (bpinfo >> 24) & 0x0F;
mips32->num_inst_bpoints_avail = mips32->num_inst_bpoints;
mips32->inst_break_list = calloc(mips32->num_inst_bpoints, sizeof(struct mips32_comparator));
for (i = 0; i < mips32->num_inst_bpoints; i++)
mips32->inst_break_list[i].reg_address = EJTAG_IBA1 + (0x100 * i);
/* clear IBIS reg */
retval = target_write_u32(target, EJTAG_IBS, 0);
if (retval != ERROR_OK)
return retval;
}
if (dcr & EJTAG_DCR_DB) {
/* get number of data breakpoints */
retval = target_read_u32(target, EJTAG_DBS, &bpinfo);
if (retval != ERROR_OK)
return retval;
mips32->num_data_bpoints = (bpinfo >> 24) & 0x0F;
mips32->num_data_bpoints_avail = mips32->num_data_bpoints;
mips32->data_break_list = calloc(mips32->num_data_bpoints, sizeof(struct mips32_comparator));
for (i = 0; i < mips32->num_data_bpoints; i++)
mips32->data_break_list[i].reg_address = EJTAG_DBA1 + (0x100 * i);
/* clear DBIS reg */
retval = target_write_u32(target, EJTAG_DBS, 0);
if (retval != ERROR_OK)
return retval;
}
/* check if target endianness settings matches debug control register */
if (((dcr & EJTAG_DCR_ENM) && (target->endianness == TARGET_LITTLE_ENDIAN)) ||
(!(dcr & EJTAG_DCR_ENM) && (target->endianness == TARGET_BIG_ENDIAN)))
LOG_WARNING("DCR endianness settings does not match target settings");
LOG_DEBUG("DCR 0x%" PRIx32 " numinst %i numdata %i", dcr, mips32->num_inst_bpoints,
mips32->num_data_bpoints);
mips32->bp_scanned = 1;
return ERROR_OK;
}
int mips32_enable_interrupts(struct target *target, int enable)
{
int retval;
int update = 0;
uint32_t dcr;
/* read debug control register */
retval = target_read_u32(target, EJTAG_DCR, &dcr);
if (retval != ERROR_OK)
return retval;
if (enable) {
if (!(dcr & EJTAG_DCR_INTE)) {
/* enable interrupts */
dcr |= EJTAG_DCR_INTE;
update = 1;
}
} else {
if (dcr & EJTAG_DCR_INTE) {
/* disable interrupts */
dcr &= ~EJTAG_DCR_INTE;
update = 1;
}
}
if (update) {
retval = target_write_u32(target, EJTAG_DCR, dcr);
if (retval != ERROR_OK)
return retval;
}
return ERROR_OK;
}
int mips32_checksum_memory(struct target *target, uint32_t address,
uint32_t count, uint32_t *checksum)
{
struct working_area *crc_algorithm;
struct reg_param reg_params[2];
struct mips32_algorithm mips32_info;
int retval;
uint32_t i;
/* see contib/loaders/checksum/mips32.s for src */
static const uint32_t mips_crc_code[] = {
0x248C0000, /* addiu $t4, $a0, 0 */
0x24AA0000, /* addiu $t2, $a1, 0 */
0x2404FFFF, /* addiu $a0, $zero, 0xffffffff */
0x10000010, /* beq $zero, $zero, ncomp */
0x240B0000, /* addiu $t3, $zero, 0 */
/* nbyte: */
0x81850000, /* lb $a1, ($t4) */
0x218C0001, /* addi $t4, $t4, 1 */
0x00052E00, /* sll $a1, $a1, 24 */
0x3C0204C1, /* lui $v0, 0x04c1 */
0x00852026, /* xor $a0, $a0, $a1 */
0x34471DB7, /* ori $a3, $v0, 0x1db7 */
0x00003021, /* addu $a2, $zero, $zero */
/* loop: */
0x00044040, /* sll $t0, $a0, 1 */
0x24C60001, /* addiu $a2, $a2, 1 */
0x28840000, /* slti $a0, $a0, 0 */
0x01074826, /* xor $t1, $t0, $a3 */
0x0124400B, /* movn $t0, $t1, $a0 */
0x28C30008, /* slti $v1, $a2, 8 */
0x1460FFF9, /* bne $v1, $zero, loop */
0x01002021, /* addu $a0, $t0, $zero */
/* ncomp: */
0x154BFFF0, /* bne $t2, $t3, nbyte */
0x256B0001, /* addiu $t3, $t3, 1 */
0x7000003F, /* sdbbp */
};
/* make sure we have a working area */
if (target_alloc_working_area(target, sizeof(mips_crc_code), &crc_algorithm) != ERROR_OK)
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
/* convert flash writing code into a buffer in target endianness */
for (i = 0; i < ARRAY_SIZE(mips_crc_code); i++)
target_write_u32(target, crc_algorithm->address + i*sizeof(uint32_t), mips_crc_code[i]);
mips32_info.common_magic = MIPS32_COMMON_MAGIC;
mips32_info.isa_mode = MIPS32_ISA_MIPS32;
init_reg_param(&reg_params[0], "a0", 32, PARAM_IN_OUT);
buf_set_u32(reg_params[0].value, 0, 32, address);
init_reg_param(&reg_params[1], "a1", 32, PARAM_OUT);
buf_set_u32(reg_params[1].value, 0, 32, count);
int timeout = 20000 * (1 + (count / (1024 * 1024)));
retval = target_run_algorithm(target, 0, NULL, 2, reg_params,
crc_algorithm->address, crc_algorithm->address + (sizeof(mips_crc_code)-4), timeout,
&mips32_info);
if (retval != ERROR_OK) {
destroy_reg_param(&reg_params[0]);
destroy_reg_param(&reg_params[1]);
target_free_working_area(target, crc_algorithm);
return retval;
}
*checksum = buf_get_u32(reg_params[0].value, 0, 32);
destroy_reg_param(&reg_params[0]);
destroy_reg_param(&reg_params[1]);
target_free_working_area(target, crc_algorithm);
return ERROR_OK;
}
/** Checks whether a memory region is zeroed. */
int mips32_blank_check_memory(struct target *target,
uint32_t address, uint32_t count, uint32_t *blank)
{
struct working_area *erase_check_algorithm;
struct reg_param reg_params[3];
struct mips32_algorithm mips32_info;
int retval;
uint32_t i;
static const uint32_t erase_check_code[] = {
/* nbyte: */
0x80880000, /* lb $t0, ($a0) */
0x00C83024, /* and $a2, $a2, $t0 */
0x24A5FFFF, /* addiu $a1, $a1, -1 */
0x14A0FFFC, /* bne $a1, $zero, nbyte */
0x24840001, /* addiu $a0, $a0, 1 */
0x7000003F /* sdbbp */
};
/* make sure we have a working area */
if (target_alloc_working_area(target, sizeof(erase_check_code), &erase_check_algorithm) != ERROR_OK)
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
/* convert flash writing code into a buffer in target endianness */
for (i = 0; i < ARRAY_SIZE(erase_check_code); i++) {
target_write_u32(target, erase_check_algorithm->address + i*sizeof(uint32_t),
erase_check_code[i]);
}
mips32_info.common_magic = MIPS32_COMMON_MAGIC;
mips32_info.isa_mode = MIPS32_ISA_MIPS32;
init_reg_param(&reg_params[0], "a0", 32, PARAM_OUT);
buf_set_u32(reg_params[0].value, 0, 32, address);
init_reg_param(&reg_params[1], "a1", 32, PARAM_OUT);
buf_set_u32(reg_params[1].value, 0, 32, count);
init_reg_param(&reg_params[2], "a2", 32, PARAM_IN_OUT);
buf_set_u32(reg_params[2].value, 0, 32, 0xff);
retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
erase_check_algorithm->address,
erase_check_algorithm->address + (sizeof(erase_check_code)-4),
10000, &mips32_info);
if (retval != ERROR_OK) {
destroy_reg_param(&reg_params[0]);
destroy_reg_param(&reg_params[1]);
destroy_reg_param(&reg_params[2]);
target_free_working_area(target, erase_check_algorithm);
return retval;
}
*blank = buf_get_u32(reg_params[2].value, 0, 32);
destroy_reg_param(&reg_params[0]);
destroy_reg_param(&reg_params[1]);
destroy_reg_param(&reg_params[2]);
target_free_working_area(target, erase_check_algorithm);
return ERROR_OK;
}
static int mips32_verify_pointer(struct command_context *cmd_ctx,
struct mips32_common *mips32)
{
if (mips32->common_magic != MIPS32_COMMON_MAGIC) {
command_print(cmd_ctx, "target is not an MIPS32");
return ERROR_TARGET_INVALID;
}
return ERROR_OK;
}
/**
* MIPS32 targets expose command interface
* to manipulate CP0 registers
*/
COMMAND_HANDLER(mips32_handle_cp0_command)
{
int retval;
struct target *target = get_current_target(CMD_CTX);
struct mips32_common *mips32 = target_to_mips32(target);
struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
retval = mips32_verify_pointer(CMD_CTX, mips32);
if (retval != ERROR_OK)
return retval;
if (target->state != TARGET_HALTED) {
command_print(CMD_CTX, "target must be stopped for \"%s\" command", CMD_NAME);
return ERROR_OK;
}
/* two or more argument, access a single register/select (write if third argument is given) */
if (CMD_ARGC < 2)
return ERROR_COMMAND_SYNTAX_ERROR;
else {
uint32_t cp0_reg, cp0_sel;
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], cp0_reg);
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], cp0_sel);
if (CMD_ARGC == 2) {
uint32_t value;
retval = mips32_cp0_read(ejtag_info, &value, cp0_reg, cp0_sel);
if (retval != ERROR_OK) {
command_print(CMD_CTX,
"couldn't access reg %" PRIi32,
cp0_reg);
return ERROR_OK;
}
command_print(CMD_CTX, "cp0 reg %" PRIi32 ", select %" PRIi32 ": %8.8" PRIx32,
cp0_reg, cp0_sel, value);
} else if (CMD_ARGC == 3) {
uint32_t value;
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], value);
retval = mips32_cp0_write(ejtag_info, value, cp0_reg, cp0_sel);
if (retval != ERROR_OK) {
command_print(CMD_CTX,
"couldn't access cp0 reg %" PRIi32 ", select %" PRIi32,
cp0_reg, cp0_sel);
return ERROR_OK;
}
command_print(CMD_CTX, "cp0 reg %" PRIi32 ", select %" PRIi32 ": %8.8" PRIx32,
cp0_reg, cp0_sel, value);
}
}
return ERROR_OK;
}
COMMAND_HANDLER(mips32_handle_scan_delay_command)
{
struct target *target = get_current_target(CMD_CTX);
struct mips32_common *mips32 = target_to_mips32(target);
struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
if (CMD_ARGC == 1)
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], ejtag_info->scan_delay);
else if (CMD_ARGC > 1)
return ERROR_COMMAND_SYNTAX_ERROR;
command_print(CMD_CTX, "scan delay: %d nsec", ejtag_info->scan_delay);
if (ejtag_info->scan_delay >= 2000000) {
ejtag_info->mode = 0;
command_print(CMD_CTX, "running in legacy mode");
} else {
ejtag_info->mode = 1;
command_print(CMD_CTX, "running in fast queued mode");
}
return ERROR_OK;
}
static const struct command_registration mips32_exec_command_handlers[] = {
{
.name = "cp0",
.handler = mips32_handle_cp0_command,
.mode = COMMAND_EXEC,
.usage = "regnum select [value]",
.help = "display/modify cp0 register",
},
{
.name = "scan_delay",
.handler = mips32_handle_scan_delay_command,
.mode = COMMAND_ANY,
.help = "display/set scan delay in nano seconds",
.usage = "[value]",
},
COMMAND_REGISTRATION_DONE
};
const struct command_registration mips32_command_handlers[] = {
{
.name = "mips32",
.mode = COMMAND_ANY,
.help = "mips32 command group",
.usage = "",
.chain = mips32_exec_command_handlers,
},
COMMAND_REGISTRATION_DONE
};

View File

@ -0,0 +1,250 @@
/***************************************************************************
* Copyright (C) 2008 by Spencer Oliver *
* spen@spen-soft.co.uk *
* *
* Copyright (C) 2008 by David T.L. Wong *
* *
* Copyright (C) 2011 by Drasko DRASKOVIC *
* drasko.draskovic@gmail.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef MIPS32_H
#define MIPS32_H
#include "target.h"
#include "mips32_pracc.h"
#define MIPS32_COMMON_MAGIC 0xB320B320
/**
* Memory segments (32bit kernel mode addresses)
* These are the traditional names used in the 32-bit universe.
*/
#define KUSEG 0x00000000
#define KSEG0 0x80000000
#define KSEG1 0xa0000000
#define KSEG2 0xc0000000
#define KSEG3 0xe0000000
/** Returns the kernel segment base of a given address */
#define KSEGX(a) ((a) & 0xe0000000)
/** CP0 CONFIG regites fields */
#define MIPS32_CONFIG0_KU_SHIFT 25
#define MIPS32_CONFIG0_KU_MASK (0x7 << MIPS32_CONFIG0_KU_SHIFT)
#define MIPS32_CONFIG0_K0_SHIFT 0
#define MIPS32_CONFIG0_K0_MASK (0x7 << MIPS32_CONFIG0_K0_SHIFT)
#define MIPS32_CONFIG0_K23_SHIFT 28
#define MIPS32_CONFIG0_K23_MASK (0x7 << MIPS32_CONFIG0_K23_SHIFT)
#define MIPS32_CONFIG0_AR_SHIFT 10
#define MIPS32_CONFIG0_AR_MASK (0x7 << MIPS32_CONFIG0_AR_SHIFT)
#define MIPS32_CONFIG1_DL_SHIFT 10
#define MIPS32_CONFIG1_DL_MASK (0x7 << MIPS32_CONFIG1_DL_SHIFT)
#define MIPS32_ARCH_REL1 0x0
#define MIPS32_ARCH_REL2 0x1
/* offsets into mips32 core register cache */
enum {
MIPS32_PC = 37,
MIPS32NUMCOREREGS
};
enum mips32_isa_mode {
MIPS32_ISA_MIPS32 = 0,
MIPS32_ISA_MIPS16E = 1,
};
struct mips32_comparator {
int used;
uint32_t bp_value;
uint32_t reg_address;
};
struct mips32_common {
uint32_t common_magic;
void *arch_info;
struct reg_cache *core_cache;
struct mips_ejtag ejtag_info;
uint32_t core_regs[MIPS32NUMCOREREGS];
enum mips32_isa_mode isa_mode;
/* working area for fastdata access */
struct working_area *fast_data_area;
int bp_scanned;
int num_inst_bpoints;
int num_data_bpoints;
int num_inst_bpoints_avail;
int num_data_bpoints_avail;
struct mips32_comparator *inst_break_list;
struct mips32_comparator *data_break_list;
/* register cache to processor synchronization */
int (*read_core_reg)(struct target *target, int num);
int (*write_core_reg)(struct target *target, int num);
};
static inline struct mips32_common *
target_to_mips32(struct target *target)
{
return target->arch_info;
}
struct mips32_core_reg {
uint32_t num;
struct target *target;
struct mips32_common *mips32_common;
};
struct mips32_algorithm {
int common_magic;
enum mips32_isa_mode isa_mode;
};
#define MIPS32_OP_ADDIU 0x21
#define MIPS32_OP_ANDI 0x0C
#define MIPS32_OP_BEQ 0x04
#define MIPS32_OP_BGTZ 0x07
#define MIPS32_OP_BNE 0x05
#define MIPS32_OP_ADDI 0x08
#define MIPS32_OP_AND 0x24
#define MIPS32_OP_CACHE 0x2F
#define MIPS32_OP_COP0 0x10
#define MIPS32_OP_JR 0x08
#define MIPS32_OP_LUI 0x0F
#define MIPS32_OP_LW 0x23
#define MIPS32_OP_LBU 0x24
#define MIPS32_OP_LHU 0x25
#define MIPS32_OP_MFHI 0x10
#define MIPS32_OP_MTHI 0x11
#define MIPS32_OP_MFLO 0x12
#define MIPS32_OP_MTLO 0x13
#define MIPS32_OP_RDHWR 0x3B
#define MIPS32_OP_SB 0x28
#define MIPS32_OP_SH 0x29
#define MIPS32_OP_SW 0x2B
#define MIPS32_OP_ORI 0x0D
#define MIPS32_OP_XORI 0x0E
#define MIPS32_OP_XOR 0x26
#define MIPS32_OP_SLTU 0x2B
#define MIPS32_OP_SRL 0x03
#define MIPS32_OP_SYNCI 0x1F
#define MIPS32_OP_REGIMM 0x01
#define MIPS32_OP_SDBBP 0x3F
#define MIPS32_OP_SPECIAL 0x00
#define MIPS32_OP_SPECIAL2 0x07
#define MIPS32_OP_SPECIAL3 0x1F
#define MIPS32_COP0_MF 0x00
#define MIPS32_COP0_MT 0x04
#define MIPS32_R_INST(opcode, rs, rt, rd, shamt, funct) \
(((opcode) << 26) | ((rs) << 21) | ((rt) << 16) | ((rd) << 11) | ((shamt) << 6) | (funct))
#define MIPS32_I_INST(opcode, rs, rt, immd) \
(((opcode) << 26) | ((rs) << 21) | ((rt) << 16) | (immd))
#define MIPS32_J_INST(opcode, addr) (((opcode) << 26) | (addr))
#define MIPS32_NOP 0
#define MIPS32_ADDI(tar, src, val) MIPS32_I_INST(MIPS32_OP_ADDI, src, tar, val)
#define MIPS32_ADDU(dst, src, tar) MIPS32_R_INST(MIPS32_OP_SPECIAL, src, tar, dst, 0, MIPS32_OP_ADDIU)
#define MIPS32_AND(reg, off, val) MIPS32_R_INST(0, off, val, reg, 0, MIPS32_OP_AND)
#define MIPS32_ANDI(tar, src, val) MIPS32_I_INST(MIPS32_OP_ANDI, src, tar, val)
#define MIPS32_B(off) MIPS32_BEQ(0, 0, off)
#define MIPS32_BEQ(src, tar, off) MIPS32_I_INST(MIPS32_OP_BEQ, src, tar, off)
#define MIPS32_BGTZ(reg, off) MIPS32_I_INST(MIPS32_OP_BGTZ, reg, 0, off)
#define MIPS32_BNE(src, tar, off) MIPS32_I_INST(MIPS32_OP_BNE, src, tar, off)
#define MIPS32_CACHE(op, off, base) MIPS32_I_INST(MIPS32_OP_CACHE, base, op, off)
#define MIPS32_JR(reg) MIPS32_R_INST(0, reg, 0, 0, 0, MIPS32_OP_JR)
#define MIPS32_MFC0(gpr, cpr, sel) MIPS32_R_INST(MIPS32_OP_COP0, MIPS32_COP0_MF, gpr, cpr, 0, sel)
#define MIPS32_MTC0(gpr, cpr, sel) MIPS32_R_INST(MIPS32_OP_COP0, MIPS32_COP0_MT, gpr, cpr, 0, sel)
#define MIPS32_LBU(reg, off, base) MIPS32_I_INST(MIPS32_OP_LBU, base, reg, off)
#define MIPS32_LHU(reg, off, base) MIPS32_I_INST(MIPS32_OP_LHU, base, reg, off)
#define MIPS32_LUI(reg, val) MIPS32_I_INST(MIPS32_OP_LUI, 0, reg, val)
#define MIPS32_LW(reg, off, base) MIPS32_I_INST(MIPS32_OP_LW, base, reg, off)
#define MIPS32_MFLO(reg) MIPS32_R_INST(0, 0, 0, reg, 0, MIPS32_OP_MFLO)
#define MIPS32_MFHI(reg) MIPS32_R_INST(0, 0, 0, reg, 0, MIPS32_OP_MFHI)
#define MIPS32_MTLO(reg) MIPS32_R_INST(0, reg, 0, 0, 0, MIPS32_OP_MTLO)
#define MIPS32_MTHI(reg) MIPS32_R_INST(0, reg, 0, 0, 0, MIPS32_OP_MTHI)
#define MIPS32_ORI(tar, src, val) MIPS32_I_INST(MIPS32_OP_ORI, src, tar, val)
#define MIPS32_XORI(tar, src, val) MIPS32_I_INST(MIPS32_OP_XORI, src, tar, val)
#define MIPS32_RDHWR(tar, dst) MIPS32_R_INST(MIPS32_OP_SPECIAL3, 0, tar, dst, 0, MIPS32_OP_RDHWR)
#define MIPS32_SB(reg, off, base) MIPS32_I_INST(MIPS32_OP_SB, base, reg, off)
#define MIPS32_SH(reg, off, base) MIPS32_I_INST(MIPS32_OP_SH, base, reg, off)
#define MIPS32_SW(reg, off, base) MIPS32_I_INST(MIPS32_OP_SW, base, reg, off)
#define MIPS32_XOR(reg, val1, val2) MIPS32_R_INST(0, val1, val2, reg, 0, MIPS32_OP_XOR)
#define MIPS32_SRL(reg, src, off) MIPS32_R_INST(0, 0, src, reg, off, MIPS32_OP_SRL)
#define MIPS32_SLTU(dst, src, tar) MIPS32_R_INST(MIPS32_OP_SPECIAL, src, tar, dst, 0, MIPS32_OP_SLTU)
#define MIPS32_SYNCI(off, base) MIPS32_I_INST(MIPS32_OP_REGIMM, base, MIPS32_OP_SYNCI, off)
#define MIPS32_SYNC 0xF
#define MIPS32_SYNCI_STEP 0x1 /* reg num od address step size to be used with synci instruction */
/**
* Cache operations definietions
* Operation field is 5 bits long :
* 1) bits 1..0 hold cache type
* 2) bits 4..2 hold operation code
*/
#define MIPS32_CACHE_D_HIT_WRITEBACK ((0x1 << 0) | (0x6 << 2))
#define MIPS32_CACHE_I_HIT_INVALIDATE ((0x0 << 0) | (0x4 << 2))
/* ejtag specific instructions */
#define MIPS32_DRET 0x4200001F
#define MIPS32_SDBBP 0x7000003F /* MIPS32_J_INST(MIPS32_OP_SPECIAL2, MIPS32_OP_SDBBP) */
#define MIPS16_SDBBP 0xE801
extern const struct command_registration mips32_command_handlers[];
int mips32_arch_state(struct target *target);
int mips32_init_arch_info(struct target *target,
struct mips32_common *mips32, struct jtag_tap *tap);
int mips32_restore_context(struct target *target);
int mips32_save_context(struct target *target);
struct reg_cache *mips32_build_reg_cache(struct target *target);
int mips32_run_algorithm(struct target *target,
int num_mem_params, struct mem_param *mem_params,
int num_reg_params, struct reg_param *reg_params,
uint32_t entry_point, uint32_t exit_point,
int timeout_ms, void *arch_info);
int mips32_configure_break_unit(struct target *target);
int mips32_enable_interrupts(struct target *target, int enable);
int mips32_examine(struct target *target);
int mips32_register_commands(struct command_context *cmd_ctx);
int mips32_get_gdb_reg_list(struct target *target,
struct reg **reg_list[], int *reg_list_size);
int mips32_checksum_memory(struct target *target, uint32_t address,
uint32_t count, uint32_t *checksum);
int mips32_blank_check_memory(struct target *target,
uint32_t address, uint32_t count, uint32_t *blank);
#endif /*MIPS32_H*/

View File

@ -0,0 +1,465 @@
/***************************************************************************
* Copyright (C) 2008 by John McCarthy *
* jgmcc@magma.ca *
* *
* Copyright (C) 2008 by Spencer Oliver *
* spen@spen-soft.co.uk *
* *
* Copyright (C) 2008 by David T.L. Wong *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "mips32_dmaacc.h"
static int mips32_dmaacc_read_mem8(struct mips_ejtag *ejtag_info,
uint32_t addr, int count, uint8_t *buf);
static int mips32_dmaacc_read_mem16(struct mips_ejtag *ejtag_info,
uint32_t addr, int count, uint16_t *buf);
static int mips32_dmaacc_read_mem32(struct mips_ejtag *ejtag_info,
uint32_t addr, int count, uint32_t *buf);
static int mips32_dmaacc_write_mem8(struct mips_ejtag *ejtag_info,
uint32_t addr, int count, uint8_t *buf);
static int mips32_dmaacc_write_mem16(struct mips_ejtag *ejtag_info,
uint32_t addr, int count, uint16_t *buf);
static int mips32_dmaacc_write_mem32(struct mips_ejtag *ejtag_info,
uint32_t addr, int count, uint32_t *buf);
/*
* The following logic shamelessly cloned from HairyDairyMaid's wrt54g_debrick
* to support the Broadcom BCM5352 SoC in the Linksys WRT54GL wireless router
* (and any others that support EJTAG DMA transfers).
* Note: This only supports memory read/write. Since the BCM5352 doesn't
* appear to support PRACC accesses, all debug functions except halt
* do not work. Still, this does allow erasing/writing flash as well as
* displaying/modifying memory and memory mapped registers.
*/
static int ejtag_dma_read(struct mips_ejtag *ejtag_info, uint32_t addr, uint32_t *data)
{
uint32_t v;
uint32_t ejtag_ctrl;
int retries = RETRY_ATTEMPTS;
begin_ejtag_dma_read:
/* Setup Address */
v = addr;
mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS);
mips_ejtag_drscan_32(ejtag_info, &v);
/* Initiate DMA Read & set DSTRT */
mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL);
ejtag_ctrl = EJTAG_CTRL_DMAACC | EJTAG_CTRL_DRWN | EJTAG_CTRL_DMA_WORD | EJTAG_CTRL_DSTRT | ejtag_info->ejtag_ctrl;
mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl);
/* Wait for DSTRT to Clear */
do {
ejtag_ctrl = EJTAG_CTRL_DMAACC | ejtag_info->ejtag_ctrl;
mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl);
} while (ejtag_ctrl & EJTAG_CTRL_DSTRT);
/* Read Data */
mips_ejtag_set_instr(ejtag_info, EJTAG_INST_DATA);
mips_ejtag_drscan_32(ejtag_info, data);
/* Clear DMA & Check DERR */
mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL);
ejtag_ctrl = ejtag_info->ejtag_ctrl;
mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl);
if (ejtag_ctrl & EJTAG_CTRL_DERR) {
if (retries--) {
LOG_ERROR("DMA Read Addr = %08" PRIx32 " Data = ERROR ON READ (retrying)", addr);
goto begin_ejtag_dma_read;
} else
LOG_ERROR("DMA Read Addr = %08" PRIx32 " Data = ERROR ON READ", addr);
return ERROR_JTAG_DEVICE_ERROR;
}
return ERROR_OK;
}
static int ejtag_dma_read_h(struct mips_ejtag *ejtag_info, uint32_t addr, uint16_t *data)
{
uint32_t v;
uint32_t ejtag_ctrl;
int retries = RETRY_ATTEMPTS;
begin_ejtag_dma_read_h:
/* Setup Address */
v = addr;
mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS);
mips_ejtag_drscan_32(ejtag_info, &v);
/* Initiate DMA Read & set DSTRT */
mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL);
ejtag_ctrl = EJTAG_CTRL_DMAACC | EJTAG_CTRL_DRWN | EJTAG_CTRL_DMA_HALFWORD |
EJTAG_CTRL_DSTRT | ejtag_info->ejtag_ctrl;
mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl);
/* Wait for DSTRT to Clear */
do {
ejtag_ctrl = EJTAG_CTRL_DMAACC | ejtag_info->ejtag_ctrl;
mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl);
} while (ejtag_ctrl & EJTAG_CTRL_DSTRT);
/* Read Data */
mips_ejtag_set_instr(ejtag_info, EJTAG_INST_DATA);
mips_ejtag_drscan_32(ejtag_info, &v);
/* Clear DMA & Check DERR */
mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL);
ejtag_ctrl = ejtag_info->ejtag_ctrl;
mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl);
if (ejtag_ctrl & EJTAG_CTRL_DERR) {
if (retries--) {
LOG_ERROR("DMA Read Addr = %08" PRIx32 " Data = ERROR ON READ (retrying)", addr);
goto begin_ejtag_dma_read_h;
} else
LOG_ERROR("DMA Read Addr = %08" PRIx32 " Data = ERROR ON READ", addr);
return ERROR_JTAG_DEVICE_ERROR;
}
/* Handle the bigendian/littleendian */
if (addr & 0x2)
*data = (v >> 16) & 0xffff;
else
*data = (v & 0x0000ffff);
return ERROR_OK;
}
static int ejtag_dma_read_b(struct mips_ejtag *ejtag_info, uint32_t addr, uint8_t *data)
{
uint32_t v;
uint32_t ejtag_ctrl;
int retries = RETRY_ATTEMPTS;
begin_ejtag_dma_read_b:
/* Setup Address */
v = addr;
mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS);
mips_ejtag_drscan_32(ejtag_info, &v);
/* Initiate DMA Read & set DSTRT */
mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL);
ejtag_ctrl = EJTAG_CTRL_DMAACC | EJTAG_CTRL_DRWN | EJTAG_CTRL_DMA_BYTE | EJTAG_CTRL_DSTRT | ejtag_info->ejtag_ctrl;
mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl);
/* Wait for DSTRT to Clear */
do {
ejtag_ctrl = EJTAG_CTRL_DMAACC | ejtag_info->ejtag_ctrl;
mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl);
} while (ejtag_ctrl & EJTAG_CTRL_DSTRT);
/* Read Data */
mips_ejtag_set_instr(ejtag_info, EJTAG_INST_DATA);
mips_ejtag_drscan_32(ejtag_info, &v);
/* Clear DMA & Check DERR */
mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL);
ejtag_ctrl = ejtag_info->ejtag_ctrl;
mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl);
if (ejtag_ctrl & EJTAG_CTRL_DERR) {
if (retries--) {
LOG_ERROR("DMA Read Addr = %08" PRIx32 " Data = ERROR ON READ (retrying)", addr);
goto begin_ejtag_dma_read_b;
} else
LOG_ERROR("DMA Read Addr = %08" PRIx32 " Data = ERROR ON READ", addr);
return ERROR_JTAG_DEVICE_ERROR;
}
/* Handle the bigendian/littleendian */
switch (addr & 0x3) {
case 0:
*data = v & 0xff;
break;
case 1:
*data = (v >> 8) & 0xff;
break;
case 2:
*data = (v >> 16) & 0xff;
break;
case 3:
*data = (v >> 24) & 0xff;
break;
}
return ERROR_OK;
}
static int ejtag_dma_write(struct mips_ejtag *ejtag_info, uint32_t addr, uint32_t data)
{
uint32_t v;
uint32_t ejtag_ctrl;
int retries = RETRY_ATTEMPTS;
begin_ejtag_dma_write:
/* Setup Address */
v = addr;
mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS);
mips_ejtag_drscan_32(ejtag_info, &v);
/* Setup Data */
v = data;
mips_ejtag_set_instr(ejtag_info, EJTAG_INST_DATA);
mips_ejtag_drscan_32(ejtag_info, &v);
/* Initiate DMA Write & set DSTRT */
mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL);
ejtag_ctrl = EJTAG_CTRL_DMAACC | EJTAG_CTRL_DMA_WORD | EJTAG_CTRL_DSTRT | ejtag_info->ejtag_ctrl;
mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl);
/* Wait for DSTRT to Clear */
do {
ejtag_ctrl = EJTAG_CTRL_DMAACC | ejtag_info->ejtag_ctrl;
mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl);
} while (ejtag_ctrl & EJTAG_CTRL_DSTRT);
/* Clear DMA & Check DERR */
mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL);
ejtag_ctrl = ejtag_info->ejtag_ctrl;
mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl);
if (ejtag_ctrl & EJTAG_CTRL_DERR) {
if (retries--) {
LOG_ERROR("DMA Write Addr = %08" PRIx32 " Data = ERROR ON WRITE (retrying)", addr);
goto begin_ejtag_dma_write;
} else
LOG_ERROR("DMA Write Addr = %08" PRIx32 " Data = ERROR ON WRITE", addr);
return ERROR_JTAG_DEVICE_ERROR;
}
return ERROR_OK;
}
static int ejtag_dma_write_h(struct mips_ejtag *ejtag_info, uint32_t addr, uint32_t data)
{
uint32_t v;
uint32_t ejtag_ctrl;
int retries = RETRY_ATTEMPTS;
/* Handle the bigendian/littleendian */
data &= 0xffff;
data |= data << 16;
begin_ejtag_dma_write_h:
/* Setup Address */
v = addr;
mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS);
mips_ejtag_drscan_32(ejtag_info, &v);
/* Setup Data */
v = data;
mips_ejtag_set_instr(ejtag_info, EJTAG_INST_DATA);
mips_ejtag_drscan_32(ejtag_info, &v);
/* Initiate DMA Write & set DSTRT */
mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL);
ejtag_ctrl = EJTAG_CTRL_DMAACC | EJTAG_CTRL_DMA_HALFWORD | EJTAG_CTRL_DSTRT | ejtag_info->ejtag_ctrl;
mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl);
/* Wait for DSTRT to Clear */
do {
ejtag_ctrl = EJTAG_CTRL_DMAACC | ejtag_info->ejtag_ctrl;
mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl);
} while (ejtag_ctrl & EJTAG_CTRL_DSTRT);
/* Clear DMA & Check DERR */
mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL);
ejtag_ctrl = ejtag_info->ejtag_ctrl;
mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl);
if (ejtag_ctrl & EJTAG_CTRL_DERR) {
if (retries--) {
LOG_ERROR("DMA Write Addr = %08" PRIx32 " Data = ERROR ON WRITE (retrying)", addr);
goto begin_ejtag_dma_write_h;
} else
LOG_ERROR("DMA Write Addr = %08" PRIx32 " Data = ERROR ON WRITE", addr);
return ERROR_JTAG_DEVICE_ERROR;
}
return ERROR_OK;
}
static int ejtag_dma_write_b(struct mips_ejtag *ejtag_info, uint32_t addr, uint32_t data)
{
uint32_t v;
uint32_t ejtag_ctrl;
int retries = RETRY_ATTEMPTS;
/* Handle the bigendian/littleendian */
data &= 0xff;
data |= data << 8;
data |= data << 16;
begin_ejtag_dma_write_b:
/* Setup Address*/
v = addr;
mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS);
mips_ejtag_drscan_32(ejtag_info, &v);
/* Setup Data */
v = data;
mips_ejtag_set_instr(ejtag_info, EJTAG_INST_DATA);
mips_ejtag_drscan_32(ejtag_info, &v);
/* Initiate DMA Write & set DSTRT */
mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL);
ejtag_ctrl = EJTAG_CTRL_DMAACC | EJTAG_CTRL_DMA_BYTE | EJTAG_CTRL_DSTRT | ejtag_info->ejtag_ctrl;
mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl);
/* Wait for DSTRT to Clear */
do {
ejtag_ctrl = EJTAG_CTRL_DMAACC | ejtag_info->ejtag_ctrl;
mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl);
} while (ejtag_ctrl & EJTAG_CTRL_DSTRT);
/* Clear DMA & Check DERR */
mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL);
ejtag_ctrl = ejtag_info->ejtag_ctrl;
mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl);
if (ejtag_ctrl & EJTAG_CTRL_DERR) {
if (retries--) {
LOG_ERROR("DMA Write Addr = %08" PRIx32 " Data = ERROR ON WRITE (retrying)", addr);
goto begin_ejtag_dma_write_b;
} else
LOG_ERROR("DMA Write Addr = %08" PRIx32 " Data = ERROR ON WRITE", addr);
return ERROR_JTAG_DEVICE_ERROR;
}
return ERROR_OK;
}
int mips32_dmaacc_read_mem(struct mips_ejtag *ejtag_info, uint32_t addr, int size, int count, void *buf)
{
switch (size) {
case 1:
return mips32_dmaacc_read_mem8(ejtag_info, addr, count, (uint8_t *)buf);
case 2:
return mips32_dmaacc_read_mem16(ejtag_info, addr, count, (uint16_t *)buf);
case 4:
return mips32_dmaacc_read_mem32(ejtag_info, addr, count, (uint32_t *)buf);
}
return ERROR_OK;
}
static int mips32_dmaacc_read_mem32(struct mips_ejtag *ejtag_info, uint32_t addr, int count, uint32_t *buf)
{
int i;
int retval;
for (i = 0; i < count; i++) {
retval = ejtag_dma_read(ejtag_info, addr + i * sizeof(*buf), &buf[i]);
if (retval != ERROR_OK)
return retval;
}
return ERROR_OK;
}
static int mips32_dmaacc_read_mem16(struct mips_ejtag *ejtag_info, uint32_t addr, int count, uint16_t *buf)
{
int i;
int retval;
for (i = 0; i < count; i++) {
retval = ejtag_dma_read_h(ejtag_info, addr + i * sizeof(*buf), &buf[i]);
if (retval != ERROR_OK)
return retval;
}
return ERROR_OK;
}
static int mips32_dmaacc_read_mem8(struct mips_ejtag *ejtag_info, uint32_t addr, int count, uint8_t *buf)
{
int i;
int retval;
for (i = 0; i < count; i++) {
retval = ejtag_dma_read_b(ejtag_info, addr + i * sizeof(*buf), &buf[i]);
if (retval != ERROR_OK)
return retval;
}
return ERROR_OK;
}
int mips32_dmaacc_write_mem(struct mips_ejtag *ejtag_info, uint32_t addr, int size, int count, void *buf)
{
switch (size) {
case 1:
return mips32_dmaacc_write_mem8(ejtag_info, addr, count, (uint8_t *)buf);
case 2:
return mips32_dmaacc_write_mem16(ejtag_info, addr, count, (uint16_t *)buf);
case 4:
return mips32_dmaacc_write_mem32(ejtag_info, addr, count, (uint32_t *)buf);
}
return ERROR_OK;
}
static int mips32_dmaacc_write_mem32(struct mips_ejtag *ejtag_info, uint32_t addr, int count, uint32_t *buf)
{
int i;
int retval;
for (i = 0; i < count; i++) {
retval = ejtag_dma_write(ejtag_info, addr + i * sizeof(*buf), buf[i]);
if (retval != ERROR_OK)
return retval;
}
return ERROR_OK;
}
static int mips32_dmaacc_write_mem16(struct mips_ejtag *ejtag_info, uint32_t addr, int count, uint16_t *buf)
{
int i;
int retval;
for (i = 0; i < count; i++) {
retval = ejtag_dma_write_h(ejtag_info, addr + i * sizeof(*buf), buf[i]);
if (retval != ERROR_OK)
return retval;
}
return ERROR_OK;
}
static int mips32_dmaacc_write_mem8(struct mips_ejtag *ejtag_info, uint32_t addr, int count, uint8_t *buf)
{
int i;
int retval;
for (i = 0; i < count; i++) {
retval = ejtag_dma_write_b(ejtag_info, addr + i * sizeof(*buf), buf[i]);
if (retval != ERROR_OK)
return retval;
}
return ERROR_OK;
}

View File

@ -0,0 +1,43 @@
/***************************************************************************
* Copyright (C) 2008 by John McCarthy *
* jgmcc@magma.ca *
* *
* Copyright (C) 2008 by Spencer Oliver *
* spen@spen-soft.co.uk *
* *
* Copyright (C) 2008 by David T.L. Wong *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef MIPS32_DMAACC_H
#define MIPS32_DMAACC_H
#include "mips_ejtag.h"
#define EJTAG_CTRL_DMA_BYTE 0x00000000
#define EJTAG_CTRL_DMA_HALFWORD 0x00000080
#define EJTAG_CTRL_DMA_WORD 0x00000100
#define EJTAG_CTRL_DMA_TRIPLEBYTE 0x00000180
#define RETRY_ATTEMPTS 0
int mips32_dmaacc_read_mem(struct mips_ejtag *ejtag_info,
uint32_t addr, int size, int count, void *buf);
int mips32_dmaacc_write_mem(struct mips_ejtag *ejtag_info,
uint32_t addr, int size, int count, void *buf);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,113 @@
/***************************************************************************
* Copyright (C) 2008 by Spencer Oliver *
* spen@spen-soft.co.uk *
* *
* Copyright (C) 2008 by David T.L. Wong *
* *
* Copyright (C) 2011 by Drasko DRASKOVIC *
* drasko.draskovic@gmail.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef MIPS32_PRACC_H
#define MIPS32_PRACC_H
#include <target/mips32.h>
#include <target/mips_ejtag.h>
#define MIPS32_PRACC_FASTDATA_AREA 0xFF200000
#define MIPS32_PRACC_BASE_ADDR 0xFF200000
#define MIPS32_PRACC_FASTDATA_SIZE 16
#define MIPS32_PRACC_TEXT 0xFF200200
#define MIPS32_PRACC_STACK 0xFF204000
#define MIPS32_PRACC_PARAM_IN 0xFF201000
#define MIPS32_PRACC_PARAM_IN_SIZE 0x1000
#define MIPS32_PRACC_PARAM_OUT (MIPS32_PRACC_PARAM_IN + MIPS32_PRACC_PARAM_IN_SIZE)
#define MIPS32_PRACC_PARAM_OUT_SIZE 0x1000
#define PRACC_UPPER_BASE_ADDR (MIPS32_PRACC_BASE_ADDR >> 16)
#define PRACC_TEXT_OFFSET (MIPS32_PRACC_TEXT - MIPS32_PRACC_BASE_ADDR)
#define PRACC_IN_OFFSET (MIPS32_PRACC_PARAM_IN - MIPS32_PRACC_BASE_ADDR)
#define PRACC_OUT_OFFSET (MIPS32_PRACC_PARAM_OUT - MIPS32_PRACC_BASE_ADDR)
#define PRACC_STACK_OFFSET (MIPS32_PRACC_STACK - MIPS32_PRACC_BASE_ADDR)
#define MIPS32_FASTDATA_HANDLER_SIZE 0x80
#define UPPER16(uint32_t) (uint32_t >> 16)
#define LOWER16(uint32_t) (uint32_t & 0xFFFF)
#define NEG16(v) (((~(v)) + 1) & 0xFFFF)
/*#define NEG18(v) (((~(v)) + 1) & 0x3FFFF)*/
struct pracc_queue_info {
int retval;
const int max_code;
int code_count;
int store_count;
uint32_t *pracc_list; /* Code and store addresses */
};
void pracc_queue_init(struct pracc_queue_info *ctx);
void pracc_add(struct pracc_queue_info *ctx, uint32_t addr, uint32_t instr);
void pracc_queue_free(struct pracc_queue_info *ctx);
int mips32_pracc_queue_exec(struct mips_ejtag *ejtag_info,
struct pracc_queue_info *ctx, uint32_t *buf);
int mips32_pracc_read_mem(struct mips_ejtag *ejtag_info,
uint32_t addr, int size, int count, void *buf);
int mips32_pracc_write_mem(struct mips_ejtag *ejtag_info,
uint32_t addr, int size, int count, void *buf);
int mips32_pracc_fastdata_xfer(struct mips_ejtag *ejtag_info, struct working_area *source,
int write_t, uint32_t addr, int count, uint32_t *buf);
int mips32_pracc_read_regs(struct mips_ejtag *ejtag_info, uint32_t *regs);
int mips32_pracc_write_regs(struct mips_ejtag *ejtag_info, uint32_t *regs);
int mips32_pracc_exec(struct mips_ejtag *ejtag_info, int code_len, const uint32_t *code,
int num_param_in, uint32_t *param_in,
int num_param_out, uint32_t *param_out, int cycle);
/**
* \b mips32_cp0_read
*
* Simulates mfc0 ASM instruction (Move From C0),
* i.e. implements copro C0 Register read.
*
* @param[in] ejtag_info
* @param[in] val Storage to hold read value
* @param[in] cp0_reg Number of copro C0 register we want to read
* @param[in] cp0_sel Select for the given C0 register
*
* @return ERROR_OK on Sucess, ERROR_FAIL otherwise
*/
int mips32_cp0_read(struct mips_ejtag *ejtag_info,
uint32_t *val, uint32_t cp0_reg, uint32_t cp0_sel);
/**
* \b mips32_cp0_write
*
* Simulates mtc0 ASM instruction (Move To C0),
* i.e. implements copro C0 Register read.
*
* @param[in] ejtag_info
* @param[in] val Value to be written
* @param[in] cp0_reg Number of copro C0 register we want to write to
* @param[in] cp0_sel Select for the given C0 register
*
* @return ERROR_OK on Sucess, ERROR_FAIL otherwise
*/
int mips32_cp0_write(struct mips_ejtag *ejtag_info,
uint32_t val, uint32_t cp0_reg, uint32_t cp0_sel);
#endif

View File

@ -0,0 +1,364 @@
/***************************************************************************
* Copyright (C) 2008 by Spencer Oliver *
* spen@spen-soft.co.uk *
* *
* Copyright (C) 2008 by David T.L. Wong *
* *
* Copyright (C) 2009 by David N. Claffey <dnclaffey@gmail.com> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "mips32.h"
#include "mips_ejtag.h"
void mips_ejtag_set_instr(struct mips_ejtag *ejtag_info, int new_instr)
{
struct jtag_tap *tap;
tap = ejtag_info->tap;
assert(tap != NULL);
if (buf_get_u32(tap->cur_instr, 0, tap->ir_length) != (uint32_t)new_instr) {
struct scan_field field;
uint8_t t[4];
field.num_bits = tap->ir_length;
field.out_value = t;
buf_set_u32(t, 0, field.num_bits, new_instr);
field.in_value = NULL;
jtag_add_ir_scan(tap, &field, TAP_IDLE);
}
}
int mips_ejtag_get_idcode(struct mips_ejtag *ejtag_info, uint32_t *idcode)
{
struct scan_field field;
uint8_t r[4];
mips_ejtag_set_instr(ejtag_info, EJTAG_INST_IDCODE);
field.num_bits = 32;
field.out_value = NULL;
field.in_value = r;
jtag_add_dr_scan(ejtag_info->tap, 1, &field, TAP_IDLE);
int retval;
retval = jtag_execute_queue();
if (retval != ERROR_OK) {
LOG_ERROR("register read failed");
return retval;
}
*idcode = buf_get_u32(field.in_value, 0, 32);
return ERROR_OK;
}
static int mips_ejtag_get_impcode(struct mips_ejtag *ejtag_info, uint32_t *impcode)
{
struct scan_field field;
uint8_t r[4];
mips_ejtag_set_instr(ejtag_info, EJTAG_INST_IMPCODE);
field.num_bits = 32;
field.out_value = NULL;
field.in_value = r;
jtag_add_dr_scan(ejtag_info->tap, 1, &field, TAP_IDLE);
int retval;
retval = jtag_execute_queue();
if (retval != ERROR_OK) {
LOG_ERROR("register read failed");
return retval;
}
*impcode = buf_get_u32(field.in_value, 0, 32);
return ERROR_OK;
}
void mips_ejtag_add_scan_96(struct mips_ejtag *ejtag_info, uint32_t ctrl, uint32_t data, uint8_t *in_scan_buf)
{
assert(ejtag_info->tap != NULL);
struct jtag_tap *tap = ejtag_info->tap;
struct scan_field field;
uint8_t out_scan[12];
/* processor access "all" register 96 bit */
field.num_bits = 96;
field.out_value = out_scan;
buf_set_u32(out_scan, 0, 32, ctrl);
buf_set_u32(out_scan + 4, 0, 32, data);
buf_set_u32(out_scan + 8, 0, 32, 0);
field.in_value = in_scan_buf;
jtag_add_dr_scan(tap, 1, &field, TAP_IDLE);
keep_alive();
}
int mips_ejtag_drscan_32(struct mips_ejtag *ejtag_info, uint32_t *data)
{
struct jtag_tap *tap;
tap = ejtag_info->tap;
assert(tap != NULL);
struct scan_field field;
uint8_t t[4], r[4];
int retval;
field.num_bits = 32;
field.out_value = t;
buf_set_u32(t, 0, field.num_bits, *data);
field.in_value = r;
jtag_add_dr_scan(tap, 1, &field, TAP_IDLE);
retval = jtag_execute_queue();
if (retval != ERROR_OK) {
LOG_ERROR("register read failed");
return retval;
}
*data = buf_get_u32(field.in_value, 0, 32);
keep_alive();
return ERROR_OK;
}
void mips_ejtag_drscan_32_out(struct mips_ejtag *ejtag_info, uint32_t data)
{
uint8_t t[4];
struct jtag_tap *tap;
tap = ejtag_info->tap;
assert(tap != NULL);
struct scan_field field;
field.num_bits = 32;
field.out_value = t;
buf_set_u32(t, 0, field.num_bits, data);
field.in_value = NULL;
jtag_add_dr_scan(tap, 1, &field, TAP_IDLE);
}
int mips_ejtag_drscan_8(struct mips_ejtag *ejtag_info, uint32_t *data)
{
struct jtag_tap *tap;
tap = ejtag_info->tap;
assert(tap != NULL);
struct scan_field field;
uint8_t t[4] = {0, 0, 0, 0}, r[4];
int retval;
field.num_bits = 8;
field.out_value = t;
buf_set_u32(t, 0, field.num_bits, *data);
field.in_value = r;
jtag_add_dr_scan(tap, 1, &field, TAP_IDLE);
retval = jtag_execute_queue();
if (retval != ERROR_OK) {
LOG_ERROR("register read failed");
return retval;
}
*data = buf_get_u32(field.in_value, 0, 32);
return ERROR_OK;
}
void mips_ejtag_drscan_8_out(struct mips_ejtag *ejtag_info, uint8_t data)
{
struct jtag_tap *tap;
tap = ejtag_info->tap;
assert(tap != NULL);
struct scan_field field;
field.num_bits = 8;
field.out_value = &data;
field.in_value = NULL;
jtag_add_dr_scan(tap, 1, &field, TAP_IDLE);
}
/* Set (to enable) or clear (to disable stepping) the SSt bit (bit 8) in Cp0 Debug reg (reg 23, sel 0) */
int mips_ejtag_config_step(struct mips_ejtag *ejtag_info, int enable_step)
{
struct pracc_queue_info ctx = {.max_code = 7};
pracc_queue_init(&ctx);
if (ctx.retval != ERROR_OK)
goto exit;
pracc_add(&ctx, 0, MIPS32_MFC0(8, 23, 0)); /* move COP0 Debug to $8 */
pracc_add(&ctx, 0, MIPS32_ORI(8, 8, 0x0100)); /* set SSt bit in debug reg */
if (!enable_step)
pracc_add(&ctx, 0, MIPS32_XORI(8, 8, 0x0100)); /* clear SSt bit in debug reg */
pracc_add(&ctx, 0, MIPS32_MTC0(8, 23, 0)); /* move $8 to COP0 Debug */
pracc_add(&ctx, 0, MIPS32_LUI(8, UPPER16(ejtag_info->reg8))); /* restore upper 16 bits of $8 */
pracc_add(&ctx, 0, MIPS32_B(NEG16((ctx.code_count + 1)))); /* jump to start */
pracc_add(&ctx, 0, MIPS32_ORI(8, 8, LOWER16(ejtag_info->reg8))); /* restore lower 16 bits of $8 */
ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, NULL);
exit:
pracc_queue_free(&ctx);
return ctx.retval;
}
int mips_ejtag_enter_debug(struct mips_ejtag *ejtag_info)
{
uint32_t ejtag_ctrl;
mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL);
/* set debug break bit */
ejtag_ctrl = ejtag_info->ejtag_ctrl | EJTAG_CTRL_JTAGBRK;
mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl);
/* break bit will be cleared by hardware */
ejtag_ctrl = ejtag_info->ejtag_ctrl;
mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl);
LOG_DEBUG("ejtag_ctrl: 0x%8.8" PRIx32 "", ejtag_ctrl);
if ((ejtag_ctrl & EJTAG_CTRL_BRKST) == 0) {
LOG_ERROR("Failed to enter Debug Mode!");
return ERROR_FAIL;
}
return ERROR_OK;
}
int mips_ejtag_exit_debug(struct mips_ejtag *ejtag_info)
{
uint32_t instr = MIPS32_DRET;
struct pracc_queue_info ctx = {.max_code = 1, .pracc_list = &instr, .code_count = 1, .store_count = 0};
/* execute our dret instruction */
ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, NULL);
/* pic32mx workaround, false pending at low core clock */
jtag_add_sleep(1000);
return ctx.retval;
}
int mips_ejtag_init(struct mips_ejtag *ejtag_info)
{
uint32_t ejtag_version;
int retval;
retval = mips_ejtag_get_impcode(ejtag_info, &ejtag_info->impcode);
if (retval != ERROR_OK)
return retval;
LOG_DEBUG("impcode: 0x%8.8" PRIx32 "", ejtag_info->impcode);
/* get ejtag version */
ejtag_version = ((ejtag_info->impcode >> 29) & 0x07);
switch (ejtag_version) {
case 0:
LOG_DEBUG("EJTAG: Version 1 or 2.0 Detected");
break;
case 1:
LOG_DEBUG("EJTAG: Version 2.5 Detected");
break;
case 2:
LOG_DEBUG("EJTAG: Version 2.6 Detected");
break;
case 3:
LOG_DEBUG("EJTAG: Version 3.1 Detected");
break;
case 4:
LOG_DEBUG("EJTAG: Version 4.1 Detected");
break;
case 5:
LOG_DEBUG("EJTAG: Version 5.1 Detected");
break;
default:
LOG_DEBUG("EJTAG: Unknown Version Detected");
break;
}
LOG_DEBUG("EJTAG: features:%s%s%s%s%s%s%s",
ejtag_info->impcode & EJTAG_IMP_R3K ? " R3k" : " R4k",
ejtag_info->impcode & EJTAG_IMP_DINT ? " DINT" : "",
ejtag_info->impcode & (1 << 22) ? " ASID_8" : "",
ejtag_info->impcode & (1 << 21) ? " ASID_6" : "",
ejtag_info->impcode & EJTAG_IMP_MIPS16 ? " MIPS16" : "",
ejtag_info->impcode & EJTAG_IMP_NODMA ? " noDMA" : " DMA",
ejtag_info->impcode & EJTAG_DCR_MIPS64 ? " MIPS64" : " MIPS32");
if ((ejtag_info->impcode & EJTAG_IMP_NODMA) == 0)
LOG_DEBUG("EJTAG: DMA Access Mode Support Enabled");
/* set initial state for ejtag control reg */
ejtag_info->ejtag_ctrl = EJTAG_CTRL_ROCC | EJTAG_CTRL_PRACC | EJTAG_CTRL_PROBEN | EJTAG_CTRL_SETDEV;
ejtag_info->fast_access_save = -1;
return ERROR_OK;
}
int mips_ejtag_fastdata_scan(struct mips_ejtag *ejtag_info, int write_t, uint32_t *data)
{
struct jtag_tap *tap;
tap = ejtag_info->tap;
assert(tap != NULL);
struct scan_field fields[2];
uint8_t spracc = 0;
uint8_t t[4] = {0, 0, 0, 0};
/* fastdata 1-bit register */
fields[0].num_bits = 1;
fields[0].out_value = &spracc;
fields[0].in_value = NULL;
/* processor access data register 32 bit */
fields[1].num_bits = 32;
fields[1].out_value = t;
if (write_t) {
fields[1].in_value = NULL;
buf_set_u32(t, 0, 32, *data);
} else
fields[1].in_value = (void *) data;
jtag_add_dr_scan(tap, 2, fields, TAP_IDLE);
if (!write_t && data)
jtag_add_callback(mips_le_to_h_u32,
(jtag_callback_data_t) data);
keep_alive();
return ERROR_OK;
}

View File

@ -0,0 +1,159 @@
/***************************************************************************
* Copyright (C) 2008 by Spencer Oliver *
* spen@spen-soft.co.uk *
* *
* Copyright (C) 2008 by David T.L. Wong *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef MIPS_EJTAG
#define MIPS_EJTAG
#include <jtag/jtag.h>
/* tap instructions */
#define EJTAG_INST_IDCODE 0x01
#define EJTAG_INST_IMPCODE 0x03
#define EJTAG_INST_ADDRESS 0x08
#define EJTAG_INST_DATA 0x09
#define EJTAG_INST_CONTROL 0x0A
#define EJTAG_INST_ALL 0x0B
#define EJTAG_INST_EJTAGBOOT 0x0C
#define EJTAG_INST_NORMALBOOT 0x0D
#define EJTAG_INST_FASTDATA 0x0E
#define EJTAG_INST_TCBCONTROLA 0x10
#define EJTAG_INST_TCBCONTROLB 0x11
#define EJTAG_INST_TCBDATA 0x12
#define EJTAG_INST_BYPASS 0xFF
/* microchip PIC32MX specific instructions */
#define MTAP_SW_MTAP 0x04
#define MTAP_SW_ETAP 0x05
#define MTAP_COMMAND 0x07
/* microchip specific cmds */
#define MCHP_ASERT_RST 0xd1
#define MCHP_DE_ASSERT_RST 0xd0
#define MCHP_ERASE 0xfc
#define MCHP_STATUS 0x00
/* ejtag control register bits ECR */
#define EJTAG_CTRL_TOF (1 << 1)
#define EJTAG_CTRL_TIF (1 << 2)
#define EJTAG_CTRL_BRKST (1 << 3)
#define EJTAG_CTRL_DLOCK (1 << 5)
#define EJTAG_CTRL_DRWN (1 << 9)
#define EJTAG_CTRL_DERR (1 << 10)
#define EJTAG_CTRL_DSTRT (1 << 11)
#define EJTAG_CTRL_JTAGBRK (1 << 12)
#define EJTAG_CTRL_SETDEV (1 << 14)
#define EJTAG_CTRL_PROBEN (1 << 15)
#define EJTAG_CTRL_PRRST (1 << 16)
#define EJTAG_CTRL_DMAACC (1 << 17)
#define EJTAG_CTRL_PRACC (1 << 18)
#define EJTAG_CTRL_PRNW (1 << 19)
#define EJTAG_CTRL_PERRST (1 << 20)
#define EJTAG_CTRL_SYNC (1 << 23)
#define EJTAG_CTRL_DNM (1 << 28)
#define EJTAG_CTRL_ROCC (1 << 31)
/* Debug Register (CP0 Register 23, Select 0) */
#define EJTAG_DEBUG_DSS (1 << 0)
#define EJTAG_DEBUG_DBP (1 << 1)
#define EJTAG_DEBUG_DDBL (1 << 2)
#define EJTAG_DEBUG_DDBS (1 << 3)
#define EJTAG_DEBUG_DIB (1 << 4)
#define EJTAG_DEBUG_DINT (1 << 5)
#define EJTAG_DEBUG_OFFLINE (1 << 7)
#define EJTAG_DEBUG_SST (1 << 8)
#define EJTAG_DEBUG_NOSST (1 << 9)
#define EJTAG_DEBUG_DDBLIMPR (1 << 18)
#define EJTAG_DEBUG_DDBSIMPR (1 << 19)
#define EJTAG_DEBUG_IEXI (1 << 20)
#define EJTAG_DEBUG_DBUSEP (1 << 21)
#define EJTAG_DEBUG_CACHEEP (1 << 22)
#define EJTAG_DEBUG_MCHECKP (1 << 23)
#define EJTAG_DEBUG_IBUSEP (1 << 24)
#define EJTAG_DEBUG_COUNTDM (1 << 25)
#define EJTAG_DEBUG_HALT (1 << 26)
#define EJTAG_DEBUG_DOZE (1 << 27)
#define EJTAG_DEBUG_LSNM (1 << 28)
#define EJTAG_DEBUG_NODCR (1 << 29)
#define EJTAG_DEBUG_DM (1 << 30)
#define EJTAG_DEBUG_DBD (1 << 31)
/* implementaion register bits */
#define EJTAG_IMP_R3K (1 << 28)
#define EJTAG_IMP_DINT (1 << 24)
#define EJTAG_IMP_NODMA (1 << 14)
#define EJTAG_IMP_MIPS16 (1 << 16)
#define EJTAG_DCR_MIPS64 (1 << 0)
/* Debug Control Register DCR */
#define EJTAG_DCR 0xFF300000
#define EJTAG_DCR_ENM (1 << 29)
#define EJTAG_DCR_DB (1 << 17)
#define EJTAG_DCR_IB (1 << 16)
#define EJTAG_DCR_INTE (1 << 4)
/* breakpoint support */
#define EJTAG_IBS 0xFF301000
#define EJTAG_IBA1 0xFF301100
#define EJTAG_DBS 0xFF302000
#define EJTAG_DBA1 0xFF302100
#define EJTAG_DBCn_NOSB (1 << 13)
#define EJTAG_DBCn_NOLB (1 << 12)
#define EJTAG_DBCn_BLM_MASK 0xff
#define EJTAG_DBCn_BLM_SHIFT 4
#define EJTAG_DBCn_BE (1 << 0)
struct mips_ejtag {
struct jtag_tap *tap;
uint32_t impcode;
uint32_t idcode;
uint32_t ejtag_ctrl;
int fast_access_save;
uint32_t reg8;
uint32_t reg9;
unsigned scan_delay;
int mode;
};
void mips_ejtag_set_instr(struct mips_ejtag *ejtag_info,
int new_instr);
int mips_ejtag_enter_debug(struct mips_ejtag *ejtag_info);
int mips_ejtag_exit_debug(struct mips_ejtag *ejtag_info);
int mips_ejtag_get_idcode(struct mips_ejtag *ejtag_info, uint32_t *idcode);
void mips_ejtag_add_scan_96(struct mips_ejtag *ejtag_info,
uint32_t ctrl, uint32_t data, uint8_t *in_scan_buf);
void mips_ejtag_drscan_32_out(struct mips_ejtag *ejtag_info, uint32_t data);
int mips_ejtag_drscan_32(struct mips_ejtag *ejtag_info, uint32_t *data);
void mips_ejtag_drscan_8_out(struct mips_ejtag *ejtag_info, uint8_t data);
int mips_ejtag_drscan_8(struct mips_ejtag *ejtag_info, uint32_t *data);
int mips_ejtag_fastdata_scan(struct mips_ejtag *ejtag_info, int write_t, uint32_t *data);
int mips_ejtag_init(struct mips_ejtag *ejtag_info);
int mips_ejtag_config_step(struct mips_ejtag *ejtag_info, int enable_step);
static inline void mips_le_to_h_u32(jtag_callback_data_t arg)
{
uint8_t *in = (uint8_t *)arg;
*((uint32_t *)arg) = le_to_h_u32(in);
}
#endif /* MIPS_EJTAG */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,48 @@
/***************************************************************************
* Copyright (C) 2008 by Spencer Oliver *
* spen@spen-soft.co.uk *
* *
* Copyright (C) 2008 by David T.L. Wong *
* *
* Copyright (C) 2011 by Drasko DRASKOVIC *
* drasko.draskovic@gmail.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef MIPS_M4K_H
#define MIPS_M4K_H
struct target;
#define MIPSM4K_COMMON_MAGIC 0xB321B321
struct mips_m4k_common {
uint32_t common_magic;
bool is_pic32mx;
struct mips32_common mips32;
};
static inline struct mips_m4k_common *
target_to_m4k(struct target *target)
{
return container_of(target->arch_info,
struct mips_m4k_common, mips32);
}
extern const struct command_registration mips_m4k_command_handlers[];
#endif /*MIPS_M4K_H*/

View File

@ -0,0 +1,410 @@
/***************************************************************************
* Copyright (C) 2007 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "arm.h"
#include "etm.h"
#include "oocd_trace.h"
/*
* This is "proof of concept" code, for prototype hardware:
* https://lists.berlios.de/pipermail/openocd-development/2007-September/000336.html
*/
static int oocd_trace_read_reg(struct oocd_trace *oocd_trace, int reg, uint32_t *value)
{
size_t bytes_written, bytes_read, bytes_to_read;
uint8_t cmd;
cmd = 0x10 | (reg & 0x7);
bytes_written = write(oocd_trace->tty_fd, &cmd, 1);
bytes_to_read = 4;
while (bytes_to_read > 0) {
bytes_read = read(oocd_trace->tty_fd, ((uint8_t *)value) + 4 - bytes_to_read, bytes_to_read);
bytes_to_read -= bytes_read;
}
LOG_DEBUG("reg #%i: 0x%8.8x", reg, *value);
return ERROR_OK;
}
static int oocd_trace_write_reg(struct oocd_trace *oocd_trace, int reg, uint32_t value)
{
size_t bytes_written;
uint8_t data[5];
data[0] = 0x18 | (reg & 0x7);
data[1] = value & 0xff;
data[2] = (value & 0xff00) >> 8;
data[3] = (value & 0xff0000) >> 16;
data[4] = (value & 0xff000000) >> 24;
bytes_written = write(oocd_trace->tty_fd, data, 5);
LOG_DEBUG("reg #%i: 0x%8.8x", reg, value);
return ERROR_OK;
}
static int oocd_trace_read_memory(struct oocd_trace *oocd_trace, uint8_t *data, uint32_t address, uint32_t size)
{
size_t bytes_written, bytes_to_read;
ssize_t bytes_read;
uint8_t cmd;
oocd_trace_write_reg(oocd_trace, OOCD_TRACE_ADDRESS, address);
oocd_trace_write_reg(oocd_trace, OOCD_TRACE_SDRAM_COUNTER, size);
cmd = 0x20;
bytes_written = write(oocd_trace->tty_fd, &cmd, 1);
bytes_to_read = size * 16;
while (bytes_to_read > 0) {
bytes_read = read(oocd_trace->tty_fd,
((uint8_t *)data) + (size * 16) - bytes_to_read, bytes_to_read);
if (bytes_read < 0)
LOG_DEBUG("read() returned %zi (%s)", bytes_read, strerror(errno));
else
bytes_to_read -= bytes_read;
}
return ERROR_OK;
}
static int oocd_trace_init(struct etm_context *etm_ctx)
{
uint8_t trash[256];
struct oocd_trace *oocd_trace = etm_ctx->capture_driver_priv;
size_t bytes_read;
oocd_trace->tty_fd = open(oocd_trace->tty, O_RDWR | O_NOCTTY | O_NONBLOCK);
if (oocd_trace->tty_fd < 0) {
LOG_ERROR("can't open tty");
return ERROR_ETM_CAPTURE_INIT_FAILED;
}
/* clear input & output buffers, then switch to "blocking mode" */
tcflush(oocd_trace->tty_fd, TCOFLUSH);
tcflush(oocd_trace->tty_fd, TCIFLUSH);
fcntl(oocd_trace->tty_fd, F_SETFL, fcntl(oocd_trace->tty_fd, F_GETFL) & ~O_NONBLOCK);
tcgetattr(oocd_trace->tty_fd, &oocd_trace->oldtio); /* save current port settings */
bzero(&oocd_trace->newtio, sizeof(oocd_trace->newtio));
oocd_trace->newtio.c_cflag = CS8 | CLOCAL | CREAD | B2500000;
oocd_trace->newtio.c_iflag = IGNPAR | IGNBRK | IXON | IXOFF;
oocd_trace->newtio.c_oflag = 0;
/* set input mode (non-canonical, no echo,...) */
oocd_trace->newtio.c_lflag = 0;
cfmakeraw(&oocd_trace->newtio);
oocd_trace->newtio.c_cc[VTIME] = 1; /* inter-character timer used */
oocd_trace->newtio.c_cc[VMIN] = 0; /* blocking read until 0 chars received */
tcflush(oocd_trace->tty_fd, TCIFLUSH);
tcsetattr(oocd_trace->tty_fd, TCSANOW, &oocd_trace->newtio);
/* occasionally one bogus character is left in the input buffer
* read up any leftover characters to ensure communication is in sync */
do {
bytes_read = read(oocd_trace->tty_fd, trash, sizeof(trash));
if (bytes_read)
LOG_DEBUG("%zi bytes read", bytes_read);
} while (bytes_read > 0);
return ERROR_OK;
}
static trace_status_t oocd_trace_status(struct etm_context *etm_ctx)
{
struct oocd_trace *oocd_trace = etm_ctx->capture_driver_priv;
uint32_t status;
oocd_trace_read_reg(oocd_trace, OOCD_TRACE_STATUS, &status);
/* if tracing is currently idle, return this information */
if (etm_ctx->capture_status == TRACE_IDLE)
return etm_ctx->capture_status;
else if (etm_ctx->capture_status & TRACE_RUNNING) {
/* check Full bit to identify an overflow */
if (status & 0x4)
etm_ctx->capture_status |= TRACE_OVERFLOWED;
/* check Triggered bit to identify trigger condition */
if (status & 0x2)
etm_ctx->capture_status |= TRACE_TRIGGERED;
if (status & 0x1) {
etm_ctx->capture_status &= ~TRACE_RUNNING;
etm_ctx->capture_status |= TRACE_COMPLETED;
}
}
return etm_ctx->capture_status;
}
static int oocd_trace_read_trace(struct etm_context *etm_ctx)
{
struct oocd_trace *oocd_trace = etm_ctx->capture_driver_priv;
uint32_t status, address;
uint32_t first_frame = 0x0;
uint32_t num_frames = 1048576;
uint8_t *trace_data;
uint32_t i;
oocd_trace_read_reg(oocd_trace, OOCD_TRACE_STATUS, &status);
oocd_trace_read_reg(oocd_trace, OOCD_TRACE_ADDRESS, &address);
/* check if we overflowed, and adjust first frame of the trace accordingly
* if we didn't overflow, read only up to the frame that would be written next,
* i.e. don't read invalid entries
*/
if (status & 0x4)
first_frame = address;
else
num_frames = address;
/* read data into temporary array for unpacking
* one frame from OpenOCD + trace corresponds to 16 trace cycles
*/
trace_data = malloc(sizeof(uint8_t) * num_frames * 16);
oocd_trace_read_memory(oocd_trace, trace_data, first_frame, num_frames);
if (etm_ctx->trace_depth > 0)
free(etm_ctx->trace_data);
etm_ctx->trace_depth = num_frames * 16;
etm_ctx->trace_data = malloc(sizeof(struct etmv1_trace_data) * etm_ctx->trace_depth);
for (i = 0; i < num_frames * 16; i++) {
etm_ctx->trace_data[i].pipestat = (trace_data[i] & 0x7);
etm_ctx->trace_data[i].packet = (trace_data[i] & 0x78) >> 3;
etm_ctx->trace_data[i].flags = 0;
if ((trace_data[i] & 0x80) >> 7)
etm_ctx->trace_data[i].flags |= ETMV1_TRACESYNC_CYCLE;
if (etm_ctx->trace_data[i].pipestat == STAT_TR) {
etm_ctx->trace_data[i].pipestat = etm_ctx->trace_data[i].packet & 0x7;
etm_ctx->trace_data[i].flags |= ETMV1_TRIGGER_CYCLE;
}
}
free(trace_data);
return ERROR_OK;
}
static int oocd_trace_start_capture(struct etm_context *etm_ctx)
{
struct oocd_trace *oocd_trace = etm_ctx->capture_driver_priv;
uint32_t control = 0x1; /* 0x1: enabled */
uint32_t trigger_count;
if (((etm_ctx->control & ETM_PORT_MODE_MASK) != ETM_PORT_NORMAL)
|| ((etm_ctx->control & ETM_PORT_WIDTH_MASK) != ETM_PORT_4BIT)) {
LOG_DEBUG("OpenOCD + trace only supports normal 4-bit ETM mode");
return ERROR_ETM_PORTMODE_NOT_SUPPORTED;
}
if ((etm_ctx->control & ETM_PORT_CLOCK_MASK) == ETM_PORT_HALF_CLOCK)
control |= 0x2; /* half rate clock, capture at twice the clock rate */
/* OpenOCD + trace holds up to 16 million samples,
* but trigger counts is set in multiples of 16 */
trigger_count = (1048576 * /* trigger_percent */ 50) / 100;
/* capturing always starts at address zero */
oocd_trace_write_reg(oocd_trace, OOCD_TRACE_ADDRESS, 0x0);
oocd_trace_write_reg(oocd_trace, OOCD_TRACE_TRIGGER_COUNTER, trigger_count);
oocd_trace_write_reg(oocd_trace, OOCD_TRACE_CONTROL, control);
/* we're starting a new trace, initialize capture status */
etm_ctx->capture_status = TRACE_RUNNING;
return ERROR_OK;
}
static int oocd_trace_stop_capture(struct etm_context *etm_ctx)
{
struct oocd_trace *oocd_trace = etm_ctx->capture_driver_priv;
/* trace stopped, just clear running flag, but preserve others */
etm_ctx->capture_status &= ~TRACE_RUNNING;
oocd_trace_write_reg(oocd_trace, OOCD_TRACE_CONTROL, 0x0);
return ERROR_OK;
}
COMMAND_HANDLER(handle_oocd_trace_config_command)
{
struct target *target;
struct arm *arm;
if (CMD_ARGC != 2)
return ERROR_COMMAND_SYNTAX_ERROR;
target = get_current_target(CMD_CTX);
arm = target_to_arm(target);
if (!is_arm(arm)) {
command_print(CMD_CTX, "current target isn't an ARM");
return ERROR_FAIL;
}
if (arm->etm) {
struct oocd_trace *oocd_trace = malloc(sizeof(struct oocd_trace));
arm->etm->capture_driver_priv = oocd_trace;
oocd_trace->etm_ctx = arm->etm;
/* copy name of TTY device used to communicate with OpenOCD + trace */
oocd_trace->tty = strndup(CMD_ARGV[1], 256);
} else
LOG_ERROR("target has no ETM defined, OpenOCD + trace left unconfigured");
return ERROR_OK;
}
COMMAND_HANDLER(handle_oocd_trace_status_command)
{
struct target *target;
struct arm *arm;
struct oocd_trace *oocd_trace;
uint32_t status;
target = get_current_target(CMD_CTX);
arm = target_to_arm(target);
if (!is_arm(arm)) {
command_print(CMD_CTX, "current target isn't an ARM");
return ERROR_FAIL;
}
if (!arm->etm) {
command_print(CMD_CTX, "current target doesn't have an ETM configured");
return ERROR_FAIL;
}
if (strcmp(arm->etm->capture_driver->name, "oocd_trace") != 0) {
command_print(CMD_CTX, "current target's ETM capture driver isn't 'oocd_trace'");
return ERROR_FAIL;
}
oocd_trace = (struct oocd_trace *)arm->etm->capture_driver_priv;
oocd_trace_read_reg(oocd_trace, OOCD_TRACE_STATUS, &status);
if (status & 0x8)
command_print(CMD_CTX, "trace clock locked");
else
command_print(CMD_CTX, "no trace clock");
return ERROR_OK;
}
COMMAND_HANDLER(handle_oocd_trace_resync_command)
{
struct target *target;
struct arm *arm;
struct oocd_trace *oocd_trace;
size_t bytes_written;
uint8_t cmd_array[1];
target = get_current_target(CMD_CTX);
arm = target_to_arm(target);
if (!is_arm(arm)) {
command_print(CMD_CTX, "current target isn't an ARM");
return ERROR_FAIL;
}
if (!arm->etm) {
command_print(CMD_CTX, "current target doesn't have an ETM configured");
return ERROR_FAIL;
}
if (strcmp(arm->etm->capture_driver->name, "oocd_trace") != 0) {
command_print(CMD_CTX, "current target's ETM capture driver isn't 'oocd_trace'");
return ERROR_FAIL;
}
oocd_trace = (struct oocd_trace *)arm->etm->capture_driver_priv;
cmd_array[0] = 0xf0;
bytes_written = write(oocd_trace->tty_fd, cmd_array, 1);
command_print(CMD_CTX, "requesting traceclock resync");
LOG_DEBUG("resyncing traceclk pll");
return ERROR_OK;
}
static const struct command_registration oocd_trace_all_command_handlers[] = {
{
.name = "config",
.handler = handle_oocd_trace_config_command,
.mode = COMMAND_CONFIG,
.usage = "<target> <tty>",
},
{
.name = "status",
.handler = handle_oocd_trace_status_command,
.mode = COMMAND_EXEC,
.usage = "",
.help = "display OpenOCD + trace status",
},
{
.name = "resync",
.handler = handle_oocd_trace_resync_command,
.mode = COMMAND_EXEC,
.usage = "",
.help = "resync OpenOCD + trace capture clock",
},
COMMAND_REGISTRATION_DONE
};
static const struct command_registration oocd_trace_command_handlers[] = {
{
.name = "oocd_trace",
.mode = COMMAND_ANY,
.help = "OpenOCD trace capture driver command group",
.usage = "",
.chain = oocd_trace_all_command_handlers,
},
COMMAND_REGISTRATION_DONE
};
struct etm_capture_driver oocd_trace_capture_driver = {
.name = "oocd_trace",
.commands = oocd_trace_command_handlers,
.init = oocd_trace_init,
.status = oocd_trace_status,
.start_capture = oocd_trace_start_capture,
.stop_capture = oocd_trace_stop_capture,
.read_trace = oocd_trace_read_trace,
};

View File

@ -0,0 +1,55 @@
/***************************************************************************
* Copyright (C) 2007 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef OOCD_TRACE_H
#define OOCD_TRACE_H
#include <termios.h>
/* registers */
enum {
OOCD_TRACE_ID = 0x7,
OOCD_TRACE_ADDRESS = 0x0,
OOCD_TRACE_TRIGGER_COUNTER = 0x01,
OOCD_TRACE_CONTROL = 0x2,
OOCD_TRACE_STATUS = 0x3,
OOCD_TRACE_SDRAM_COUNTER = 0x4,
};
/* commands */
enum {
OOCD_TRACE_NOP = 0x0,
OOCD_TRACE_READ_REG = 0x10,
OOCD_TRACE_WRITE_REG = 0x18,
OOCD_TRACE_READ_RAM = 0x20,
/* OOCD_TRACE_WRITE_RAM = 0x28, */
OOCD_TRACE_RESYNC = 0xf0,
};
struct oocd_trace {
struct etm_context *etm_ctx;
char *tty;
int tty_fd;
struct termios oldtio, newtio;
};
extern struct etm_capture_driver oocd_trace_capture_driver;
#endif /* OOCD_TRACE_TRACE_H */

View File

@ -0,0 +1,107 @@
/***************************************************************************
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* Copyright (C) 2007,2008 Øyvind Harboe *
* oyvind.harboe@zylin.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "register.h"
#include <helper/log.h>
/**
* @file
* Holds utilities to work with register caches.
*
* OpenOCD uses machine registers internally, and exposes them by name
* to Tcl scripts. Sets of related registers are grouped into caches.
* For example, a CPU core will expose a set of registers, and there
* may be separate registers associated with debug or trace modules.
*/
struct reg *register_get_by_name(struct reg_cache *first,
const char *name, bool search_all)
{
unsigned i;
struct reg_cache *cache = first;
while (cache) {
for (i = 0; i < cache->num_regs; i++) {
if (strcmp(cache->reg_list[i].name, name) == 0)
return &(cache->reg_list[i]);
}
if (search_all)
cache = cache->next;
else
break;
}
return NULL;
}
struct reg_cache **register_get_last_cache_p(struct reg_cache **first)
{
struct reg_cache **cache_p = first;
if (*cache_p)
while (*cache_p)
cache_p = &((*cache_p)->next);
else
return first;
return cache_p;
}
/** Marks the contents of the register cache as invalid (and clean). */
void register_cache_invalidate(struct reg_cache *cache)
{
struct reg *reg = cache->reg_list;
for (unsigned n = cache->num_regs; n != 0; n--, reg++) {
reg->valid = 0;
reg->dirty = 0;
}
}
static int register_get_dummy_core_reg(struct reg *reg)
{
return ERROR_OK;
}
static int register_set_dummy_core_reg(struct reg *reg, uint8_t *buf)
{
reg->dirty = 1;
reg->valid = 1;
return ERROR_OK;
}
static const struct reg_arch_type dummy_type = {
.get = register_get_dummy_core_reg,
.set = register_set_dummy_core_reg,
};
void register_init_dummy(struct reg *reg)
{
reg->type = &dummy_type;
}

View File

@ -0,0 +1,58 @@
/***************************************************************************
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* Copyright (C) 2007,2008 Øyvind Harboe *
* oyvind.harboe@zylin.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef REGISTER_H
#define REGISTER_H
struct target;
struct reg {
const char *name;
void *value;
bool dirty;
bool valid;
uint32_t size;
void *arch_info;
const struct reg_arch_type *type;
};
struct reg_cache {
const char *name;
struct reg_cache *next;
struct reg *reg_list;
unsigned num_regs;
};
struct reg_arch_type {
int (*get)(struct reg *reg);
int (*set)(struct reg *reg, uint8_t *buf);
};
struct reg *register_get_by_name(struct reg_cache *first,
const char *name, bool search_all);
struct reg_cache **register_get_last_cache_p(struct reg_cache **first);
void register_cache_invalidate(struct reg_cache *cache);
void register_init_dummy(struct reg *reg);
#endif /* REGISTER_H */

View File

@ -0,0 +1,101 @@
/***************************************************************************
* *
* Copyright (C) ST-Ericsson SA 2011 *
* Author: Michel Jaouen <michel.jaouen@stericsson.com> for ST-Ericsson. *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "server/server.h"
#include "target/target.h"
#include "server/gdb_server.h"
#include "smp.h"
#include "helper/binarybuffer.h"
/* implementation of new packet in gdb interface for smp feature */
/* */
/* j : smp status request */
/* J : smp set request */
/* */
/* jc :read core id displayed by gdb connection */
/* reply XXXXXXXX core id is int32_t , 8 hex digits */
/* */
/* Reply ENN error not supported (target not smp) */
/* */
/* JcXX set core id displayed at next gdb continue */
/* maximum 8 bytes described core id int32_t (8 hex digits) */
/* (core id -1 , reserved for returning to normal continue mode) */
/* Reply ENN error not supported(target not smp,core id out of range) */
/* Reply OK : for success */
/* */
/* handling of this packet within gdb can be done by the creation */
/* internal variable by mean of function allocate_computed_value */
/* set $_core 1 => Jc01 packet is sent */
/* print $_core => jc packet is sent and result is affected in $ */
/* Another way to test this packet is the usage of maintenance packet */
/* maint packet Jc01 */
/* maint packet jc */
/* packet j :smp status request */
int gdb_read_smp_packet(struct connection *connection,
char *packet, int packet_size)
{
struct target *target = get_target_from_connection(connection);
uint32_t len = sizeof(int32_t);
uint8_t *buffer;
char *hex_buffer;
int retval = ERROR_OK;
if (target->smp) {
if (strncmp(packet, "jc", 2) == 0) {
hex_buffer = malloc(len * 2 + 1);
buffer = (uint8_t *)&target->gdb_service->core[0];
int pkt_len = hexify(hex_buffer, (char *)buffer, len, len * 2 + 1);
retval = gdb_put_packet(connection, hex_buffer, pkt_len);
free(hex_buffer);
}
} else
retval = gdb_put_packet(connection, "E01", 3);
return retval;
}
/* J : smp set request */
int gdb_write_smp_packet(struct connection *connection,
char *packet, int packet_size)
{
struct target *target = get_target_from_connection(connection);
char *separator;
int coreid = 0;
int retval = ERROR_OK;
/* skip command character */
if (target->smp) {
if (strncmp(packet, "Jc", 2) == 0) {
packet += 2;
coreid = strtoul(packet, &separator, 16);
target->gdb_service->core[1] = coreid;
retval = gdb_put_packet(connection, "OK", 2);
}
} else
retval = gdb_put_packet(connection, "E01", 3);
return retval;
}

Some files were not shown because too many files have changed in this diff Show More