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:
170
debuggers/openocd/src/target/Makefile.am
Normal file
170
debuggers/openocd/src/target/Makefile.am
Normal 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
|
||||
868
debuggers/openocd/src/target/Makefile.in
Normal file
868
debuggers/openocd/src/target/Makefile.in
Normal 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:
|
||||
530
debuggers/openocd/src/target/adi_v5_jtag.c
Normal file
530
debuggers/openocd/src/target/adi_v5_jtag.c
Normal 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;
|
||||
}
|
||||
357
debuggers/openocd/src/target/adi_v5_swd.c
Normal file
357
debuggers/openocd/src/target/adi_v5_swd.c
Normal 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;
|
||||
}
|
||||
54
debuggers/openocd/src/target/algorithm.c
Normal file
54
debuggers/openocd/src/target/algorithm.c
Normal 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;
|
||||
}
|
||||
52
debuggers/openocd/src/target/algorithm.h
Normal file
52
debuggers/openocd/src/target/algorithm.h
Normal 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 */
|
||||
243
debuggers/openocd/src/target/arm.h
Normal file
243
debuggers/openocd/src/target/arm.h
Normal 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 */
|
||||
1370
debuggers/openocd/src/target/arm11.c
Normal file
1370
debuggers/openocd/src/target/arm11.c
Normal file
File diff suppressed because it is too large
Load Diff
116
debuggers/openocd/src/target/arm11.h
Normal file
116
debuggers/openocd/src/target/arm11.h
Normal 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 */
|
||||
1197
debuggers/openocd/src/target/arm11_dbgtap.c
Normal file
1197
debuggers/openocd/src/target/arm11_dbgtap.c
Normal file
File diff suppressed because it is too large
Load Diff
85
debuggers/openocd/src/target/arm11_dbgtap.h
Normal file
85
debuggers/openocd/src/target/arm11_dbgtap.h
Normal 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 */
|
||||
591
debuggers/openocd/src/target/arm720t.c
Normal file
591
debuggers/openocd/src/target/arm720t.c
Normal 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,
|
||||
};
|
||||
43
debuggers/openocd/src/target/arm720t.h
Normal file
43
debuggers/openocd/src/target/arm720t.h
Normal 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 */
|
||||
2864
debuggers/openocd/src/target/arm7_9_common.c
Normal file
2864
debuggers/openocd/src/target/arm7_9_common.c
Normal file
File diff suppressed because it is too large
Load Diff
179
debuggers/openocd/src/target/arm7_9_common.h
Normal file
179
debuggers/openocd/src/target/arm7_9_common.h
Normal 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 */
|
||||
715
debuggers/openocd/src/target/arm7tdmi.c
Normal file
715
debuggers/openocd/src/target/arm7tdmi.c
Normal 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,
|
||||
};
|
||||
34
debuggers/openocd/src/target/arm7tdmi.h
Normal file
34
debuggers/openocd/src/target/arm7tdmi.h
Normal 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 */
|
||||
1723
debuggers/openocd/src/target/arm920t.c
Normal file
1723
debuggers/openocd/src/target/arm920t.c
Normal file
File diff suppressed because it is too large
Load Diff
73
debuggers/openocd/src/target/arm920t.h
Normal file
73
debuggers/openocd/src/target/arm920t.h
Normal 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 */
|
||||
834
debuggers/openocd/src/target/arm926ejs.c
Normal file
834
debuggers/openocd/src/target/arm926ejs.c
Normal 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,
|
||||
};
|
||||
57
debuggers/openocd/src/target/arm926ejs.h
Normal file
57
debuggers/openocd/src/target/arm926ejs.h
Normal 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 */
|
||||
787
debuggers/openocd/src/target/arm946e.c
Normal file
787
debuggers/openocd/src/target/arm946e.c
Normal 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 = ®_addr_buf;
|
||||
fields[1].in_value = NULL;
|
||||
|
||||
fields[2].num_bits = 1;
|
||||
fields[2].out_value = &nr_w_buf;
|
||||
fields[2].in_value = NULL;
|
||||
|
||||
jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE);
|
||||
|
||||
fields[0].in_value = (uint8_t *)value;
|
||||
jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE);
|
||||
|
||||
jtag_add_callback(arm_le_to_h_u32, (jtag_callback_data_t)value);
|
||||
|
||||
#ifdef _DEBUG_INSTRUCTION_EXECUTION_
|
||||
LOG_DEBUG("addr: 0x%x value: %8.8x", reg_addr, *value);
|
||||
#endif
|
||||
|
||||
retval = jtag_execute_queue();
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int arm946e_write_cp15(struct target *target, int reg_addr, uint32_t value)
|
||||
{
|
||||
int retval = ERROR_OK;
|
||||
struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
|
||||
struct arm_jtag *jtag_info = &arm7_9->jtag_info;
|
||||
struct scan_field fields[3];
|
||||
uint8_t reg_addr_buf = reg_addr & 0x3f;
|
||||
uint8_t nr_w_buf = 1;
|
||||
uint8_t value_buf[4];
|
||||
|
||||
buf_set_u32(value_buf, 0, 32, value);
|
||||
|
||||
retval = arm_jtag_scann(jtag_info, 0xf, TAP_IDLE);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
retval = arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL, TAP_IDLE);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
fields[0].num_bits = 32;
|
||||
fields[0].out_value = value_buf;
|
||||
fields[0].in_value = NULL;
|
||||
|
||||
fields[1].num_bits = 6;
|
||||
fields[1].out_value = ®_addr_buf;
|
||||
fields[1].in_value = NULL;
|
||||
|
||||
fields[2].num_bits = 1;
|
||||
fields[2].out_value = &nr_w_buf;
|
||||
fields[2].in_value = NULL;
|
||||
|
||||
jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE);
|
||||
|
||||
#ifdef _DEBUG_INSTRUCTION_EXECUTION_
|
||||
LOG_DEBUG("addr: 0x%x value: %8.8x", reg_addr, value);
|
||||
#endif
|
||||
|
||||
retval = jtag_execute_queue();
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
#define GET_ICACHE_SIZE 6
|
||||
#define GET_DCACHE_SIZE 18
|
||||
|
||||
/*
|
||||
* \param target struct target pointer
|
||||
* \param idsel select GET_ICACHE_SIZE or GET_DCACHE_SIZE
|
||||
* \returns cache size, given in bytes
|
||||
*/
|
||||
static uint32_t arm946e_cp15_get_csize(struct target *target, int idsel)
|
||||
{
|
||||
struct arm946e_common *arm946e = target_to_arm946(target);
|
||||
uint32_t csize = arm946e->cp15_cache_info;
|
||||
if (csize == 0) {
|
||||
if (arm946e_read_cp15(target, 0x01, &csize) == ERROR_OK)
|
||||
arm946e->cp15_cache_info = csize;
|
||||
}
|
||||
if (csize & (1<<(idsel-4))) /* cache absent */
|
||||
return 0;
|
||||
csize = (csize >> idsel) & 0x0F;
|
||||
return csize ? 1 << (12 + (csize-3)) : 0;
|
||||
}
|
||||
|
||||
uint32_t arm946e_invalidate_whole_dcache(struct target *target)
|
||||
{
|
||||
uint32_t csize = arm946e_cp15_get_csize(target, GET_DCACHE_SIZE);
|
||||
if (csize == 0)
|
||||
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
||||
|
||||
/* One line (index) is 32 bytes (8 words) long, 4-way assoc
|
||||
* ARM DDI 0201D, Section 3.3.5
|
||||
*/
|
||||
int nb_idx = (csize / (4*8*NB_CACHE_WAYS)); /* gives nb of lines (indexes) in the cache */
|
||||
|
||||
/* Loop for all segmentde (i.e. ways) */
|
||||
uint32_t seg;
|
||||
for (seg = 0; seg < NB_CACHE_WAYS; seg++) {
|
||||
/* Loop for all indexes */
|
||||
int idx;
|
||||
for (idx = 0; idx < nb_idx; idx++) {
|
||||
/* Form and write cp15 index (segment + line idx) */
|
||||
uint32_t cp15_idx = seg << 30 | idx << 5;
|
||||
int retval = arm946e_write_cp15(target, 0x3a, cp15_idx);
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_DEBUG("ERROR writing index");
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* Read dtag */
|
||||
uint32_t dtag;
|
||||
arm946e_read_cp15(target, 0x16, (uint32_t *) &dtag);
|
||||
|
||||
/* Check cache line VALID bit */
|
||||
if (!(dtag >> 4 & 0x1))
|
||||
continue;
|
||||
|
||||
/* Clean data cache line */
|
||||
retval = arm946e_write_cp15(target, 0x35, 0x1);
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_DEBUG("ERROR cleaning cache line");
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* Flush data cache line */
|
||||
retval = arm946e_write_cp15(target, 0x1a, 0x1);
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_DEBUG("ERROR flushing cache line");
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
uint32_t arm946e_invalidate_whole_icache(struct target *target)
|
||||
{
|
||||
/* Check cache presence before flushing - avoid undefined behavior */
|
||||
uint32_t csize = arm946e_cp15_get_csize(target, GET_ICACHE_SIZE);
|
||||
if (csize == 0)
|
||||
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
||||
|
||||
LOG_DEBUG("FLUSHING I$");
|
||||
/**
|
||||
* Invalidate (flush) I$
|
||||
* mcr 15, 0, r0, cr7, cr5, {0}
|
||||
*/
|
||||
int retval = arm946e_write_cp15(target, 0x0f, 0x1);
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_DEBUG("ERROR flushing I$");
|
||||
return retval;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int arm946e_post_debug_entry(struct target *target)
|
||||
{
|
||||
uint32_t ctr_reg = 0x0;
|
||||
uint32_t retval = ERROR_OK;
|
||||
struct arm946e_common *arm946e = target_to_arm946(target);
|
||||
|
||||
/* See if CACHES are enabled, and save that info
|
||||
* in the context bits, so that arm946e_pre_restore_context() can use them */
|
||||
arm946e_read_cp15(target, CP15_CTL, (uint32_t *) &ctr_reg);
|
||||
|
||||
/* Save control reg in the context */
|
||||
arm946e->cp15_control_reg = ctr_reg;
|
||||
|
||||
if (arm946e_preserve_cache) {
|
||||
if (ctr_reg & CP15_CTL_DCACHE) {
|
||||
/* Clean and flush D$ */
|
||||
arm946e_invalidate_whole_dcache(target);
|
||||
|
||||
/* Disable D$ */
|
||||
ctr_reg &= ~CP15_CTL_DCACHE;
|
||||
}
|
||||
|
||||
if (ctr_reg & CP15_CTL_ICACHE) {
|
||||
/* Flush I$ */
|
||||
arm946e_invalidate_whole_icache(target);
|
||||
|
||||
/* Disable I$ */
|
||||
ctr_reg &= ~CP15_CTL_ICACHE;
|
||||
}
|
||||
|
||||
/* Write the new configuration */
|
||||
retval = arm946e_write_cp15(target, CP15_CTL, ctr_reg);
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_DEBUG("ERROR disabling cache");
|
||||
return retval;
|
||||
}
|
||||
} /* if preserve_cache */
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
void arm946e_pre_restore_context(struct target *target)
|
||||
{
|
||||
uint32_t ctr_reg = 0x0;
|
||||
uint32_t retval;
|
||||
|
||||
if (arm946e_preserve_cache) {
|
||||
struct arm946e_common *arm946e = target_to_arm946(target);
|
||||
/* Get the contents of the CTR reg */
|
||||
arm946e_read_cp15(target, CP15_CTL, (uint32_t *) &ctr_reg);
|
||||
|
||||
/**
|
||||
* Read-modify-write CP15 control
|
||||
* to reenable I/D-cache operation
|
||||
* NOTE: It is not possible to disable cache by CP15.
|
||||
* if arm946e_preserve_cache debugging flag enabled.
|
||||
*/
|
||||
ctr_reg |= arm946e->cp15_control_reg & (CP15_CTL_DCACHE|CP15_CTL_ICACHE);
|
||||
|
||||
/* Write the new configuration */
|
||||
retval = arm946e_write_cp15(target, CP15_CTL, ctr_reg);
|
||||
if (retval != ERROR_OK)
|
||||
LOG_DEBUG("ERROR enabling cache");
|
||||
} /* if preserve_cache */
|
||||
}
|
||||
|
||||
uint32_t arm946e_invalidate_dcache(struct target *target, uint32_t address,
|
||||
uint32_t size, uint32_t count)
|
||||
{
|
||||
uint32_t cur_addr = 0x0;
|
||||
uint32_t cp15_idx, set, way, dtag;
|
||||
uint32_t i = 0;
|
||||
int retval;
|
||||
|
||||
for (i = 0; i < count*size; i++) {
|
||||
cur_addr = address + i;
|
||||
|
||||
|
||||
set = (cur_addr >> 5) & 0xff; /* set field is 8 bits long */
|
||||
|
||||
for (way = 0; way < NB_CACHE_WAYS; way++) {
|
||||
/**
|
||||
* Find if the affected address is kept in the cache.
|
||||
* Because JTAG Scan Chain 15 offers limited approach,
|
||||
* we have to loop through all cache ways (segments) and
|
||||
* read cache tags, then compare them with with address.
|
||||
*/
|
||||
|
||||
/* Form and write cp15 index (segment + line idx) */
|
||||
cp15_idx = way << 30 | set << 5;
|
||||
retval = arm946e_write_cp15(target, 0x3a, cp15_idx);
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_DEBUG("ERROR writing index");
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* Read dtag */
|
||||
arm946e_read_cp15(target, 0x16, (uint32_t *) &dtag);
|
||||
|
||||
/* Check cache line VALID bit */
|
||||
if (!(dtag >> 4 & 0x1))
|
||||
continue;
|
||||
|
||||
/* If line is valid and corresponds to affected address - invalidate it */
|
||||
if (dtag >> 5 == cur_addr >> 5) {
|
||||
/* Clean data cache line */
|
||||
retval = arm946e_write_cp15(target, 0x35, 0x1);
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_DEBUG("ERROR cleaning cache line");
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* Flush data cache line */
|
||||
retval = arm946e_write_cp15(target, 0x1c, 0x1);
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_DEBUG("ERROR flushing cache line");
|
||||
return retval;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
} /* loop through all 4 ways */
|
||||
} /* loop through all addresses */
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
uint32_t arm946e_invalidate_icache(struct target *target, uint32_t address,
|
||||
uint32_t size, uint32_t count)
|
||||
{
|
||||
uint32_t cur_addr = 0x0;
|
||||
uint32_t cp15_idx, set, way, itag;
|
||||
uint32_t i = 0;
|
||||
int retval;
|
||||
|
||||
for (i = 0; i < count*size; i++) {
|
||||
cur_addr = address + i;
|
||||
|
||||
set = (cur_addr >> 5) & 0xff; /* set field is 8 bits long */
|
||||
|
||||
for (way = 0; way < NB_CACHE_WAYS; way++) {
|
||||
/* Form and write cp15 index (segment + line idx) */
|
||||
cp15_idx = way << 30 | set << 5;
|
||||
retval = arm946e_write_cp15(target, 0x3a, cp15_idx);
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_DEBUG("ERROR writing index");
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* Read itag */
|
||||
arm946e_read_cp15(target, 0x17, (uint32_t *) &itag);
|
||||
|
||||
/* Check cache line VALID bit */
|
||||
if (!(itag >> 4 & 0x1))
|
||||
continue;
|
||||
|
||||
/* If line is valid and corresponds to affected address - invalidate it */
|
||||
if (itag >> 5 == cur_addr >> 5) {
|
||||
/* Flush I$ line */
|
||||
retval = arm946e_write_cp15(target, 0x1d, 0x0);
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_DEBUG("ERROR flushing cache line");
|
||||
return retval;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
} /* way loop */
|
||||
} /* addr loop */
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/** Writes a buffer, in the specified word size, with current MMU settings. */
|
||||
int arm946e_write_memory(struct target *target, uint32_t address,
|
||||
uint32_t size, uint32_t count, const uint8_t *buffer)
|
||||
{
|
||||
int retval;
|
||||
|
||||
LOG_DEBUG("-");
|
||||
|
||||
struct arm946e_common *arm946e = target_to_arm946(target);
|
||||
/* Invalidate D$ if it is ON */
|
||||
if (!arm946e_preserve_cache && (arm946e->cp15_control_reg & CP15_CTL_DCACHE))
|
||||
arm946e_invalidate_dcache(target, address, size, count);
|
||||
|
||||
/**
|
||||
* Write memory
|
||||
*/
|
||||
retval = arm7_9_write_memory(target, address, size, count, buffer);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
/* *
|
||||
* Invalidate I$ if it is ON.
|
||||
*
|
||||
* D$ has been cleaned and flushed before mem write thus forcing it to behave like write-through,
|
||||
* because arm7_9_write_memory() has seen non-valid bit in D$
|
||||
* and wrote data into physical RAM (without touching or allocating the cache line).
|
||||
* From ARM946ES Technical Reference Manual we can see that it uses "allocate on read-miss"
|
||||
* policy for both I$ and D$ (Chapter 3.2 and 3.3)
|
||||
*
|
||||
* Explanation :
|
||||
* "ARM system developer's guide: designing and optimizing system software" by
|
||||
* Andrew N. Sloss, Dominic Symes and Chris Wright,
|
||||
* Chapter 12.3.3 Allocating Policy on a Cache Miss :
|
||||
* A read allocate on cache miss policy allocates a cache line only during a read from main memory.
|
||||
* If the victim cache line contains valid data, then it is written to main memory before the cache line
|
||||
* is filled with new data.
|
||||
* Under this strategy, a write of new data to memory does not update the contents of the cache memory
|
||||
* unless a cache line was allocated on a previous read from main memory.
|
||||
* If the cache line contains valid data, then the write updates the cache and may update the main memory if
|
||||
* the cache write policy is write-through.
|
||||
* If the data is not in the cache, the controller writes to main memory only.
|
||||
*/
|
||||
if (!arm946e_preserve_cache && (arm946e->cp15_control_reg & CP15_CTL_ICACHE))
|
||||
arm946e_invalidate_icache(target, address, size, count);
|
||||
|
||||
return ERROR_OK;
|
||||
|
||||
}
|
||||
|
||||
int arm946e_read_memory(struct target *target, uint32_t address,
|
||||
uint32_t size, uint32_t count, uint8_t *buffer)
|
||||
{
|
||||
int retval;
|
||||
|
||||
LOG_DEBUG("-");
|
||||
|
||||
retval = arm7_9_read_memory(target, address, size, count, buffer);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int jim_arm946e_cp15(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
|
||||
{
|
||||
/* one or two arguments, access a single register (write if second argument is given) */
|
||||
if (argc < 2 || argc > 3) {
|
||||
Jim_WrongNumArgs(interp, 1, argv, "addr [value]");
|
||||
return JIM_ERR;
|
||||
}
|
||||
|
||||
struct command_context *cmd_ctx = current_command_context(interp);
|
||||
assert(cmd_ctx != NULL);
|
||||
|
||||
struct target *target = get_current_target(cmd_ctx);
|
||||
if (target == NULL) {
|
||||
LOG_ERROR("arm946e: no current target");
|
||||
return JIM_ERR;
|
||||
}
|
||||
|
||||
struct arm946e_common *arm946e = target_to_arm946(target);
|
||||
int retval = arm946e_verify_pointer(cmd_ctx, arm946e);
|
||||
if (retval != ERROR_OK)
|
||||
return JIM_ERR;
|
||||
|
||||
if (target->state != TARGET_HALTED) {
|
||||
command_print(cmd_ctx, "target %s must be stopped for \"cp15\" command", target_name(target));
|
||||
return JIM_ERR;
|
||||
}
|
||||
|
||||
long l;
|
||||
uint32_t address;
|
||||
retval = Jim_GetLong(interp, argv[1], &l);
|
||||
address = l;
|
||||
if (JIM_OK != retval)
|
||||
return retval;
|
||||
|
||||
if (argc == 2) {
|
||||
uint32_t value;
|
||||
retval = arm946e_read_cp15(target, address, &value);
|
||||
if (retval != ERROR_OK) {
|
||||
command_print(cmd_ctx, "%s cp15 reg %" PRIi32 " access failed", target_name(target), address);
|
||||
return JIM_ERR;
|
||||
}
|
||||
retval = jtag_execute_queue();
|
||||
if (retval != ERROR_OK)
|
||||
return JIM_ERR;
|
||||
char buf[20];
|
||||
sprintf(buf, "0x%08x", value);
|
||||
/* Return value in hex format */
|
||||
Jim_SetResultString(interp, buf, -1);
|
||||
} else if (argc == 3) {
|
||||
uint32_t value;
|
||||
retval = Jim_GetLong(interp, argv[2], &l);
|
||||
value = l;
|
||||
if (JIM_OK != retval)
|
||||
return retval;
|
||||
retval = arm946e_write_cp15(target, address, value);
|
||||
if (retval != ERROR_OK) {
|
||||
command_print(cmd_ctx, "%s cp15 reg %" PRIi32 " access failed", target_name(target), address);
|
||||
return JIM_ERR;
|
||||
}
|
||||
if (address == CP15_CTL)
|
||||
arm946e_update_cp15_caches(target, value);
|
||||
}
|
||||
|
||||
return JIM_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(arm946e_handle_idcache)
|
||||
{
|
||||
if (CMD_ARGC > 1)
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
|
||||
int retval;
|
||||
struct target *target = get_current_target(CMD_CTX);
|
||||
struct arm946e_common *arm946e = target_to_arm946(target);
|
||||
|
||||
retval = arm946e_verify_pointer(CMD_CTX, arm946e);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
if (target->state != TARGET_HALTED) {
|
||||
command_print(CMD_CTX, "target must be stopped for \"%s\" command", CMD_NAME);
|
||||
return ERROR_TARGET_NOT_HALTED;
|
||||
}
|
||||
|
||||
bool icache = (strcmp(CMD_NAME, "icache") == 0);
|
||||
uint32_t csize = arm946e_cp15_get_csize(target, icache ? GET_ICACHE_SIZE : GET_DCACHE_SIZE) / 1024;
|
||||
if (CMD_ARGC == 0) {
|
||||
bool bena = ((arm946e->cp15_control_reg & (icache ? CP15_CTL_ICACHE : CP15_CTL_DCACHE)) != 0)
|
||||
&& (arm946e->cp15_control_reg & 0x1);
|
||||
if (csize == 0)
|
||||
command_print(CMD_CTX, "%s-cache absent", icache ? "I" : "D");
|
||||
else
|
||||
command_print(CMD_CTX, "%s-cache size: %dK, %s", icache ? "I" : "D", csize, bena ? "enabled" : "disabled");
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
bool flush = false;
|
||||
bool enable = false;
|
||||
retval = command_parse_bool_arg(CMD_ARGV[0], &enable);
|
||||
if (retval == ERROR_COMMAND_SYNTAX_ERROR) {
|
||||
if (strcmp(CMD_ARGV[0], "flush") == 0) {
|
||||
flush = true;
|
||||
retval = ERROR_OK;
|
||||
} else
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* Do not invalidate or change state, if cache is absent */
|
||||
if (csize == 0) {
|
||||
command_print(CMD_CTX, "%s-cache absent, '%s' operation undefined", icache ? "I" : "D", CMD_ARGV[0]);
|
||||
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
/* NOTE: flushing entire cache will not preserve lock-down cache regions */
|
||||
if (icache) {
|
||||
if ((arm946e->cp15_control_reg & CP15_CTL_ICACHE) && !enable)
|
||||
retval = arm946e_invalidate_whole_icache(target);
|
||||
} else {
|
||||
if ((arm946e->cp15_control_reg & CP15_CTL_DCACHE) && !enable)
|
||||
retval = arm946e_invalidate_whole_dcache(target);
|
||||
}
|
||||
|
||||
if (retval != ERROR_OK || flush)
|
||||
return retval;
|
||||
|
||||
uint32_t value;
|
||||
retval = arm946e_read_cp15(target, CP15_CTL, &value);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
uint32_t vnew = value;
|
||||
uint32_t cmask = icache ? CP15_CTL_ICACHE : CP15_CTL_DCACHE;
|
||||
if (enable) {
|
||||
if ((value & 0x1) == 0)
|
||||
LOG_WARNING("arm946e: MPU must be enabled for cache to operate");
|
||||
vnew |= cmask;
|
||||
} else
|
||||
vnew &= ~cmask;
|
||||
|
||||
if (vnew == value)
|
||||
return ERROR_OK;
|
||||
|
||||
retval = arm946e_write_cp15(target, CP15_CTL, vnew);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
arm946e_update_cp15_caches(target, vnew);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static const struct command_registration arm946e_exec_command_handlers[] = {
|
||||
{
|
||||
.name = "cp15",
|
||||
.jim_handler = jim_arm946e_cp15,
|
||||
.mode = COMMAND_EXEC,
|
||||
.usage = "regnum [value]",
|
||||
.help = "read/modify cp15 register",
|
||||
},
|
||||
{
|
||||
.name = "icache",
|
||||
.handler = arm946e_handle_idcache,
|
||||
.mode = COMMAND_EXEC,
|
||||
.usage = "['enable'|'disable'|'flush']",
|
||||
.help = "I-cache info and operations",
|
||||
},
|
||||
{
|
||||
.name = "dcache",
|
||||
.handler = arm946e_handle_idcache,
|
||||
.mode = COMMAND_EXEC,
|
||||
.usage = "['enable'|'disable'|'flush']",
|
||||
.help = "D-cache info and operations",
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
const struct command_registration arm946e_command_handlers[] = {
|
||||
{
|
||||
.chain = arm9tdmi_command_handlers,
|
||||
},
|
||||
{
|
||||
.name = "arm946e",
|
||||
.mode = COMMAND_ANY,
|
||||
.help = "arm946e command group",
|
||||
.usage = "",
|
||||
.chain = arm946e_exec_command_handlers,
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
/** Holds methods for ARM946 targets. */
|
||||
struct target_type arm946e_target = {
|
||||
.name = "arm946e",
|
||||
|
||||
.poll = arm7_9_poll,
|
||||
.arch_state = arm_arch_state,
|
||||
|
||||
.target_request_data = arm7_9_target_request_data,
|
||||
|
||||
.halt = arm7_9_halt,
|
||||
.resume = arm7_9_resume,
|
||||
.step = arm7_9_step,
|
||||
|
||||
.assert_reset = arm7_9_assert_reset,
|
||||
.deassert_reset = arm7_9_deassert_reset,
|
||||
.soft_reset_halt = arm7_9_soft_reset_halt,
|
||||
|
||||
.get_gdb_reg_list = arm_get_gdb_reg_list,
|
||||
|
||||
/* .read_memory = arm7_9_read_memory, */
|
||||
/* .write_memory = arm7_9_write_memory, */
|
||||
.read_memory = arm946e_read_memory,
|
||||
.write_memory = arm946e_write_memory,
|
||||
|
||||
.bulk_write_memory = arm7_9_bulk_write_memory,
|
||||
|
||||
.checksum_memory = arm_checksum_memory,
|
||||
.blank_check_memory = arm_blank_check_memory,
|
||||
|
||||
.run_algorithm = armv4_5_run_algorithm,
|
||||
|
||||
.add_breakpoint = arm7_9_add_breakpoint,
|
||||
.remove_breakpoint = arm7_9_remove_breakpoint,
|
||||
/* .add_breakpoint = arm946e_add_breakpoint, */
|
||||
/* .remove_breakpoint = arm946e_remove_breakpoint, */
|
||||
|
||||
.add_watchpoint = arm7_9_add_watchpoint,
|
||||
.remove_watchpoint = arm7_9_remove_watchpoint,
|
||||
|
||||
.commands = arm946e_command_handlers,
|
||||
.target_create = arm946e_target_create,
|
||||
.init_target = arm9tdmi_init_target,
|
||||
.examine = arm7_9_examine,
|
||||
.check_reset = arm7_9_check_reset,
|
||||
};
|
||||
53
debuggers/openocd/src/target/arm946e.h
Normal file
53
debuggers/openocd/src/target/arm946e.h
Normal 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 */
|
||||
285
debuggers/openocd/src/target/arm966e.c
Normal file
285
debuggers/openocd/src/target/arm966e.c
Normal 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 = ®_addr_buf;
|
||||
fields[1].in_value = NULL;
|
||||
|
||||
fields[2].num_bits = 1;
|
||||
fields[2].out_value = &nr_w_buf;
|
||||
fields[2].in_value = NULL;
|
||||
|
||||
jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE);
|
||||
|
||||
fields[1].in_value = (uint8_t *)value;
|
||||
|
||||
jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE);
|
||||
|
||||
jtag_add_callback(arm_le_to_h_u32, (jtag_callback_data_t)value);
|
||||
|
||||
|
||||
#ifdef _DEBUG_INSTRUCTION_EXECUTION_
|
||||
retval = jtag_execute_queue();
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
LOG_DEBUG("addr: 0x%x value: %8.8x", reg_addr, *value);
|
||||
#endif
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/* EXPORTED to str9x (flash) */
|
||||
int arm966e_write_cp15(struct target *target, int reg_addr, uint32_t value)
|
||||
{
|
||||
int retval = ERROR_OK;
|
||||
struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
|
||||
struct arm_jtag *jtag_info = &arm7_9->jtag_info;
|
||||
struct scan_field fields[3];
|
||||
uint8_t reg_addr_buf = reg_addr & 0x3f;
|
||||
uint8_t nr_w_buf = 1;
|
||||
uint8_t value_buf[4];
|
||||
|
||||
buf_set_u32(value_buf, 0, 32, value);
|
||||
|
||||
retval = arm_jtag_scann(jtag_info, 0xf, TAP_IDLE);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
retval = arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL, TAP_IDLE);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
fields[0].num_bits = 32;
|
||||
fields[0].out_value = value_buf;
|
||||
fields[0].in_value = NULL;
|
||||
|
||||
fields[1].num_bits = 6;
|
||||
fields[1].out_value = ®_addr_buf;
|
||||
fields[1].in_value = NULL;
|
||||
|
||||
fields[2].num_bits = 1;
|
||||
fields[2].out_value = &nr_w_buf;
|
||||
fields[2].in_value = NULL;
|
||||
|
||||
jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE);
|
||||
|
||||
#ifdef _DEBUG_INSTRUCTION_EXECUTION_
|
||||
LOG_DEBUG("addr: 0x%x value: %8.8x", reg_addr, value);
|
||||
#endif
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(arm966e_handle_cp15_command)
|
||||
{
|
||||
int retval;
|
||||
struct target *target = get_current_target(CMD_CTX);
|
||||
struct arm966e_common *arm966e = target_to_arm966(target);
|
||||
|
||||
retval = arm966e_verify_pointer(CMD_CTX, arm966e);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
if (target->state != TARGET_HALTED) {
|
||||
command_print(CMD_CTX, "target must be stopped for \"%s\" command", CMD_NAME);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/* one or more argument, access a single register (write if second argument is given */
|
||||
if (CMD_ARGC >= 1) {
|
||||
uint32_t address;
|
||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address);
|
||||
|
||||
if (CMD_ARGC == 1) {
|
||||
uint32_t value;
|
||||
retval = arm966e_read_cp15(target, address, &value);
|
||||
if (retval != ERROR_OK) {
|
||||
command_print(CMD_CTX,
|
||||
"couldn't access reg %" PRIi32,
|
||||
address);
|
||||
return ERROR_OK;
|
||||
}
|
||||
retval = jtag_execute_queue();
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
command_print(CMD_CTX, "%" PRIi32 ": %8.8" PRIx32,
|
||||
address, value);
|
||||
} else if (CMD_ARGC == 2) {
|
||||
uint32_t value;
|
||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value);
|
||||
retval = arm966e_write_cp15(target, address, value);
|
||||
if (retval != ERROR_OK) {
|
||||
command_print(CMD_CTX,
|
||||
"couldn't access reg %" PRIi32,
|
||||
address);
|
||||
return ERROR_OK;
|
||||
}
|
||||
command_print(CMD_CTX, "%" PRIi32 ": %8.8" PRIx32,
|
||||
address, value);
|
||||
}
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static const struct command_registration arm966e_exec_command_handlers[] = {
|
||||
{
|
||||
.name = "cp15",
|
||||
.handler = arm966e_handle_cp15_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.usage = "regnum [value]",
|
||||
.help = "display/modify cp15 register",
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
const struct command_registration arm966e_command_handlers[] = {
|
||||
{
|
||||
.chain = arm9tdmi_command_handlers,
|
||||
},
|
||||
{
|
||||
.name = "arm966e",
|
||||
.mode = COMMAND_ANY,
|
||||
.help = "arm966e command group",
|
||||
.usage = "",
|
||||
.chain = arm966e_exec_command_handlers,
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
/** Holds methods for ARM966 targets. */
|
||||
struct target_type arm966e_target = {
|
||||
.name = "arm966e",
|
||||
|
||||
.poll = arm7_9_poll,
|
||||
.arch_state = arm_arch_state,
|
||||
|
||||
.target_request_data = arm7_9_target_request_data,
|
||||
|
||||
.halt = arm7_9_halt,
|
||||
.resume = arm7_9_resume,
|
||||
.step = arm7_9_step,
|
||||
|
||||
.assert_reset = arm7_9_assert_reset,
|
||||
.deassert_reset = arm7_9_deassert_reset,
|
||||
.soft_reset_halt = arm7_9_soft_reset_halt,
|
||||
|
||||
.get_gdb_reg_list = arm_get_gdb_reg_list,
|
||||
|
||||
.read_memory = arm7_9_read_memory,
|
||||
.write_memory = arm7_9_write_memory,
|
||||
.bulk_write_memory = arm7_9_bulk_write_memory,
|
||||
|
||||
.checksum_memory = arm_checksum_memory,
|
||||
.blank_check_memory = arm_blank_check_memory,
|
||||
|
||||
.run_algorithm = armv4_5_run_algorithm,
|
||||
|
||||
.add_breakpoint = arm7_9_add_breakpoint,
|
||||
.remove_breakpoint = arm7_9_remove_breakpoint,
|
||||
.add_watchpoint = arm7_9_add_watchpoint,
|
||||
.remove_watchpoint = arm7_9_remove_watchpoint,
|
||||
|
||||
.commands = arm966e_command_handlers,
|
||||
.target_create = arm966e_target_create,
|
||||
.init_target = arm9tdmi_init_target,
|
||||
.examine = arm7_9_examine,
|
||||
.check_reset = arm7_9_check_reset,
|
||||
};
|
||||
50
debuggers/openocd/src/target/arm966e.h
Normal file
50
debuggers/openocd/src/target/arm966e.h
Normal 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 */
|
||||
923
debuggers/openocd/src/target/arm9tdmi.c
Normal file
923
debuggers/openocd/src/target/arm9tdmi.c
Normal 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,
|
||||
};
|
||||
58
debuggers/openocd/src/target/arm9tdmi.h
Normal file
58
debuggers/openocd/src/target/arm9tdmi.h
Normal 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 */
|
||||
1982
debuggers/openocd/src/target/arm_adi_v5.c
Normal file
1982
debuggers/openocd/src/target/arm_adi_v5.c
Normal file
File diff suppressed because it is too large
Load Diff
477
debuggers/openocd/src/target/arm_adi_v5.h
Normal file
477
debuggers/openocd/src/target/arm_adi_v5.h
Normal 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
|
||||
4438
debuggers/openocd/src/target/arm_disassembler.c
Normal file
4438
debuggers/openocd/src/target/arm_disassembler.c
Normal file
File diff suppressed because it is too large
Load Diff
201
debuggers/openocd/src/target/arm_disassembler.h
Normal file
201
debuggers/openocd/src/target/arm_disassembler.h
Normal 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 */
|
||||
1018
debuggers/openocd/src/target/arm_dpm.c
Normal file
1018
debuggers/openocd/src/target/arm_dpm.c
Normal file
File diff suppressed because it is too large
Load Diff
203
debuggers/openocd/src/target/arm_dpm.h
Normal file
203
debuggers/openocd/src/target/arm_dpm.h
Normal 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 */
|
||||
100
debuggers/openocd/src/target/arm_jtag.c
Normal file
100
debuggers/openocd/src/target/arm_jtag.c
Normal 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);
|
||||
}
|
||||
84
debuggers/openocd/src/target/arm_jtag.h
Normal file
84
debuggers/openocd/src/target/arm_jtag.h
Normal 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 */
|
||||
314
debuggers/openocd/src/target/arm_opcodes.h
Normal file
314
debuggers/openocd/src/target/arm_opcodes.h
Normal 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 */
|
||||
533
debuggers/openocd/src/target/arm_semihosting.c
Normal file
533
debuggers/openocd/src/target/arm_semihosting.c
Normal 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;
|
||||
}
|
||||
26
debuggers/openocd/src/target/arm_semihosting.h
Normal file
26
debuggers/openocd/src/target/arm_semihosting.h
Normal 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
|
||||
724
debuggers/openocd/src/target/arm_simulator.c
Normal file
724
debuggers/openocd/src/target/arm_simulator.c
Normal 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);
|
||||
}
|
||||
41
debuggers/openocd/src/target/arm_simulator.h
Normal file
41
debuggers/openocd/src/target/arm_simulator.h
Normal 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 */
|
||||
1550
debuggers/openocd/src/target/armv4_5.c
Normal file
1550
debuggers/openocd/src/target/armv4_5.c
Normal file
File diff suppressed because it is too large
Load Diff
51
debuggers/openocd/src/target/armv4_5.h
Normal file
51
debuggers/openocd/src/target/armv4_5.h
Normal 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 */
|
||||
104
debuggers/openocd/src/target/armv4_5_cache.c
Normal file
104
debuggers/openocd/src/target/armv4_5_cache.c
Normal 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;
|
||||
}
|
||||
57
debuggers/openocd/src/target/armv4_5_cache.h
Normal file
57
debuggers/openocd/src/target/armv4_5_cache.h
Normal 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 */
|
||||
171
debuggers/openocd/src/target/armv4_5_mmu.c
Normal file
171
debuggers/openocd/src/target/armv4_5_mmu.c
Normal 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;
|
||||
}
|
||||
58
debuggers/openocd/src/target/armv4_5_mmu.h
Normal file
58
debuggers/openocd/src/target/armv4_5_mmu.h
Normal 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 */
|
||||
804
debuggers/openocd/src/target/armv7a.c
Normal file
804
debuggers/openocd/src/target/armv7a.c
Normal 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
|
||||
};
|
||||
173
debuggers/openocd/src/target/armv7a.h
Normal file
173
debuggers/openocd/src/target/armv7a.h
Normal 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 */
|
||||
799
debuggers/openocd/src/target/armv7m.c
Normal file
799
debuggers/openocd/src/target/armv7m.c
Normal 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, ®_value);
|
||||
|
||||
buf_set_u32(armv7m->arm.core_cache->reg_list[num].value, 0, 32, reg_value);
|
||||
armv7m->arm.core_cache->reg_list[num].valid = 1;
|
||||
armv7m->arm.core_cache->reg_list[num].dirty = 0;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int armv7m_write_core_reg(struct target *target, struct reg *r,
|
||||
int num, enum arm_mode mode, uint32_t value)
|
||||
{
|
||||
int retval;
|
||||
uint32_t reg_value;
|
||||
struct arm_reg *armv7m_core_reg;
|
||||
struct armv7m_common *armv7m = target_to_armv7m(target);
|
||||
|
||||
assert(num < (int)armv7m->arm.core_cache->num_regs);
|
||||
|
||||
reg_value = buf_get_u32(armv7m->arm.core_cache->reg_list[num].value, 0, 32);
|
||||
armv7m_core_reg = armv7m->arm.core_cache->reg_list[num].arch_info;
|
||||
retval = armv7m->store_core_reg_u32(target,
|
||||
armv7m_core_reg->num,
|
||||
reg_value);
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_ERROR("JTAG failure");
|
||||
armv7m->arm.core_cache->reg_list[num].dirty = armv7m->arm.core_cache->reg_list[num].valid;
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
LOG_DEBUG("write core reg %i value 0x%" PRIx32 "", num, reg_value);
|
||||
armv7m->arm.core_cache->reg_list[num].valid = 1;
|
||||
armv7m->arm.core_cache->reg_list[num].dirty = 0;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns generic ARM userspace registers to GDB.
|
||||
* GDB doesn't quite understand that most ARMs don't have floating point
|
||||
* hardware, so this also fakes a set of long-obsolete FPA registers that
|
||||
* are not used in EABI based software stacks.
|
||||
*/
|
||||
int armv7m_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size)
|
||||
{
|
||||
struct armv7m_common *armv7m = target_to_armv7m(target);
|
||||
int i;
|
||||
|
||||
*reg_list_size = 26;
|
||||
*reg_list = malloc(sizeof(struct reg *) * (*reg_list_size));
|
||||
|
||||
/*
|
||||
* GDB register packet format for ARM:
|
||||
* - the first 16 registers are r0..r15
|
||||
* - (obsolete) 8 FPA registers
|
||||
* - (obsolete) FPA status
|
||||
* - CPSR
|
||||
*/
|
||||
for (i = 0; i < 16; i++)
|
||||
(*reg_list)[i] = &armv7m->arm.core_cache->reg_list[i];
|
||||
|
||||
for (i = 16; i < 24; i++)
|
||||
(*reg_list)[i] = &arm_gdb_dummy_fp_reg;
|
||||
(*reg_list)[24] = &arm_gdb_dummy_fps_reg;
|
||||
|
||||
#ifdef ARMV7_GDB_HACKS
|
||||
/* use dummy cpsr reg otherwise gdb may try and set the thumb bit */
|
||||
(*reg_list)[25] = &armv7m_gdb_dummy_cpsr_reg;
|
||||
|
||||
/* ARMV7M is always in thumb mode, try to make GDB understand this
|
||||
* if it does not support this arch */
|
||||
*((char *)armv7m->arm.pc->value) |= 1;
|
||||
#else
|
||||
(*reg_list)[25] = &armv7m->arm.core_cache->reg_list[ARMV7M_xPSR];
|
||||
#endif
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/** Runs a Thumb algorithm in the target. */
|
||||
int armv7m_run_algorithm(struct target *target,
|
||||
int num_mem_params, struct mem_param *mem_params,
|
||||
int num_reg_params, struct reg_param *reg_params,
|
||||
uint32_t entry_point, uint32_t exit_point,
|
||||
int timeout_ms, void *arch_info)
|
||||
{
|
||||
int retval;
|
||||
|
||||
retval = armv7m_start_algorithm(target,
|
||||
num_mem_params, mem_params,
|
||||
num_reg_params, reg_params,
|
||||
entry_point, exit_point,
|
||||
arch_info);
|
||||
|
||||
if (retval == ERROR_OK)
|
||||
retval = armv7m_wait_algorithm(target,
|
||||
num_mem_params, mem_params,
|
||||
num_reg_params, reg_params,
|
||||
exit_point, timeout_ms,
|
||||
arch_info);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/** Starts a Thumb algorithm in the target. */
|
||||
int armv7m_start_algorithm(struct target *target,
|
||||
int num_mem_params, struct mem_param *mem_params,
|
||||
int num_reg_params, struct reg_param *reg_params,
|
||||
uint32_t entry_point, uint32_t exit_point,
|
||||
void *arch_info)
|
||||
{
|
||||
struct armv7m_common *armv7m = target_to_armv7m(target);
|
||||
struct armv7m_algorithm *armv7m_algorithm_info = arch_info;
|
||||
enum arm_mode core_mode = armv7m->arm.core_mode;
|
||||
int retval = ERROR_OK;
|
||||
|
||||
/* NOTE: armv7m_run_algorithm requires that each algorithm uses a software breakpoint
|
||||
* at the exit point */
|
||||
|
||||
if (armv7m_algorithm_info->common_magic != ARMV7M_COMMON_MAGIC) {
|
||||
LOG_ERROR("current target isn't an ARMV7M target");
|
||||
return ERROR_TARGET_INVALID;
|
||||
}
|
||||
|
||||
if (target->state != TARGET_HALTED) {
|
||||
LOG_WARNING("target not halted");
|
||||
return ERROR_TARGET_NOT_HALTED;
|
||||
}
|
||||
|
||||
/* refresh core register cache
|
||||
* Not needed if core register cache is always consistent with target process state */
|
||||
for (unsigned i = 0; i < ARMV7M_NUM_REGS; i++) {
|
||||
|
||||
armv7m_algorithm_info->context[i] = buf_get_u32(
|
||||
armv7m->arm.core_cache->reg_list[i].value,
|
||||
0,
|
||||
32);
|
||||
}
|
||||
|
||||
for (int i = 0; i < num_mem_params; i++) {
|
||||
/* TODO: Write only out params */
|
||||
retval = target_write_buffer(target, mem_params[i].address,
|
||||
mem_params[i].size,
|
||||
mem_params[i].value);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
}
|
||||
|
||||
for (int i = 0; i < num_reg_params; i++) {
|
||||
struct reg *reg =
|
||||
register_get_by_name(armv7m->arm.core_cache, reg_params[i].reg_name, 0);
|
||||
/* uint32_t regvalue; */
|
||||
|
||||
if (!reg) {
|
||||
LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name);
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
if (reg->size != reg_params[i].size) {
|
||||
LOG_ERROR("BUG: register '%s' size doesn't match reg_params[i].size",
|
||||
reg_params[i].reg_name);
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
/* regvalue = buf_get_u32(reg_params[i].value, 0, 32); */
|
||||
armv7m_set_core_reg(reg, reg_params[i].value);
|
||||
}
|
||||
|
||||
if (armv7m_algorithm_info->core_mode != ARM_MODE_ANY &&
|
||||
armv7m_algorithm_info->core_mode != core_mode) {
|
||||
|
||||
/* we cannot set ARM_MODE_HANDLER, so use ARM_MODE_THREAD instead */
|
||||
if (armv7m_algorithm_info->core_mode == ARM_MODE_HANDLER) {
|
||||
armv7m_algorithm_info->core_mode = ARM_MODE_THREAD;
|
||||
LOG_INFO("ARM_MODE_HANDLER not currently supported, using ARM_MODE_THREAD instead");
|
||||
}
|
||||
|
||||
LOG_DEBUG("setting core_mode: 0x%2.2x", armv7m_algorithm_info->core_mode);
|
||||
buf_set_u32(armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].value,
|
||||
0, 1, armv7m_algorithm_info->core_mode);
|
||||
armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].dirty = 1;
|
||||
armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].valid = 1;
|
||||
}
|
||||
|
||||
/* save previous core mode */
|
||||
armv7m_algorithm_info->core_mode = core_mode;
|
||||
|
||||
retval = target_resume(target, 0, entry_point, 1, 1);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/** Waits for an algorithm in the target. */
|
||||
int armv7m_wait_algorithm(struct target *target,
|
||||
int num_mem_params, struct mem_param *mem_params,
|
||||
int num_reg_params, struct reg_param *reg_params,
|
||||
uint32_t exit_point, int timeout_ms,
|
||||
void *arch_info)
|
||||
{
|
||||
struct armv7m_common *armv7m = target_to_armv7m(target);
|
||||
struct armv7m_algorithm *armv7m_algorithm_info = arch_info;
|
||||
int retval = ERROR_OK;
|
||||
uint32_t pc;
|
||||
|
||||
/* NOTE: armv7m_run_algorithm requires that each algorithm uses a software breakpoint
|
||||
* at the exit point */
|
||||
|
||||
if (armv7m_algorithm_info->common_magic != ARMV7M_COMMON_MAGIC) {
|
||||
LOG_ERROR("current target isn't an ARMV7M target");
|
||||
return ERROR_TARGET_INVALID;
|
||||
}
|
||||
|
||||
retval = target_wait_state(target, TARGET_HALTED, timeout_ms);
|
||||
/* If the target fails to halt due to the breakpoint, force a halt */
|
||||
if (retval != ERROR_OK || target->state != TARGET_HALTED) {
|
||||
retval = target_halt(target);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
retval = target_wait_state(target, TARGET_HALTED, 500);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
return ERROR_TARGET_TIMEOUT;
|
||||
}
|
||||
|
||||
armv7m->load_core_reg_u32(target, 15, &pc);
|
||||
if (exit_point && (pc != exit_point)) {
|
||||
LOG_DEBUG("failed algorithm halted at 0x%" PRIx32 ", expected 0x%" PRIx32,
|
||||
pc,
|
||||
exit_point);
|
||||
return ERROR_TARGET_TIMEOUT;
|
||||
}
|
||||
|
||||
/* Read memory values to mem_params[] */
|
||||
for (int i = 0; i < num_mem_params; i++) {
|
||||
if (mem_params[i].direction != PARAM_OUT) {
|
||||
retval = target_read_buffer(target, mem_params[i].address,
|
||||
mem_params[i].size,
|
||||
mem_params[i].value);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
||||
/* Copy core register values to reg_params[] */
|
||||
for (int i = 0; i < num_reg_params; i++) {
|
||||
if (reg_params[i].direction != PARAM_OUT) {
|
||||
struct reg *reg = register_get_by_name(armv7m->arm.core_cache,
|
||||
reg_params[i].reg_name,
|
||||
0);
|
||||
|
||||
if (!reg) {
|
||||
LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name);
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
if (reg->size != reg_params[i].size) {
|
||||
LOG_ERROR(
|
||||
"BUG: register '%s' size doesn't match reg_params[i].size",
|
||||
reg_params[i].reg_name);
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
buf_set_u32(reg_params[i].value, 0, 32, buf_get_u32(reg->value, 0, 32));
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = ARMV7M_NUM_REGS - 1; i >= 0; i--) {
|
||||
uint32_t regvalue;
|
||||
regvalue = buf_get_u32(armv7m->arm.core_cache->reg_list[i].value, 0, 32);
|
||||
if (regvalue != armv7m_algorithm_info->context[i]) {
|
||||
LOG_DEBUG("restoring register %s with value 0x%8.8" PRIx32,
|
||||
armv7m->arm.core_cache->reg_list[i].name,
|
||||
armv7m_algorithm_info->context[i]);
|
||||
buf_set_u32(armv7m->arm.core_cache->reg_list[i].value,
|
||||
0, 32, armv7m_algorithm_info->context[i]);
|
||||
armv7m->arm.core_cache->reg_list[i].valid = 1;
|
||||
armv7m->arm.core_cache->reg_list[i].dirty = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* restore previous core mode */
|
||||
if (armv7m_algorithm_info->core_mode != armv7m->arm.core_mode) {
|
||||
LOG_DEBUG("restoring core_mode: 0x%2.2x", armv7m_algorithm_info->core_mode);
|
||||
buf_set_u32(armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].value,
|
||||
0, 1, armv7m_algorithm_info->core_mode);
|
||||
armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].dirty = 1;
|
||||
armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].valid = 1;
|
||||
}
|
||||
|
||||
armv7m->arm.core_mode = armv7m_algorithm_info->core_mode;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/** Logs summary of ARMv7-M state for a halted target. */
|
||||
int armv7m_arch_state(struct target *target)
|
||||
{
|
||||
struct armv7m_common *armv7m = target_to_armv7m(target);
|
||||
struct arm *arm = &armv7m->arm;
|
||||
uint32_t ctrl, sp;
|
||||
|
||||
ctrl = buf_get_u32(arm->core_cache->reg_list[ARMV7M_CONTROL].value, 0, 32);
|
||||
sp = buf_get_u32(arm->core_cache->reg_list[ARMV7M_R13].value, 0, 32);
|
||||
|
||||
LOG_USER("target halted due to %s, current mode: %s %s\n"
|
||||
"xPSR: %#8.8" PRIx32 " pc: %#8.8" PRIx32 " %csp: %#8.8" PRIx32 "%s",
|
||||
debug_reason_name(target),
|
||||
arm_mode_name(arm->core_mode),
|
||||
armv7m_exception_string(armv7m->exception_number),
|
||||
buf_get_u32(arm->cpsr->value, 0, 32),
|
||||
buf_get_u32(arm->pc->value, 0, 32),
|
||||
(ctrl & 0x02) ? 'p' : 'm',
|
||||
sp,
|
||||
arm->is_semihosting ? ", semihosting" : "");
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static const struct reg_arch_type armv7m_reg_type = {
|
||||
.get = armv7m_get_core_reg,
|
||||
.set = armv7m_set_core_reg,
|
||||
};
|
||||
|
||||
/** Builds cache of architecturally defined registers. */
|
||||
struct reg_cache *armv7m_build_reg_cache(struct target *target)
|
||||
{
|
||||
struct armv7m_common *armv7m = target_to_armv7m(target);
|
||||
struct arm *arm = &armv7m->arm;
|
||||
int num_regs = ARMV7M_NUM_REGS;
|
||||
struct reg_cache **cache_p = register_get_last_cache_p(&target->reg_cache);
|
||||
struct reg_cache *cache = malloc(sizeof(struct reg_cache));
|
||||
struct reg *reg_list = calloc(num_regs, sizeof(struct reg));
|
||||
struct arm_reg *arch_info = calloc(num_regs, sizeof(struct arm_reg));
|
||||
int i;
|
||||
|
||||
#ifdef ARMV7_GDB_HACKS
|
||||
register_init_dummy(&armv7m_gdb_dummy_cpsr_reg);
|
||||
#endif
|
||||
|
||||
/* Build the process context cache */
|
||||
cache->name = "arm v7m registers";
|
||||
cache->next = NULL;
|
||||
cache->reg_list = reg_list;
|
||||
cache->num_regs = num_regs;
|
||||
(*cache_p) = cache;
|
||||
|
||||
for (i = 0; i < num_regs; i++) {
|
||||
arch_info[i].num = armv7m_regs[i].id;
|
||||
arch_info[i].target = target;
|
||||
arch_info[i].arm = arm;
|
||||
|
||||
reg_list[i].name = armv7m_regs[i].name;
|
||||
reg_list[i].size = armv7m_regs[i].bits;
|
||||
reg_list[i].value = calloc(1, 4);
|
||||
reg_list[i].dirty = 0;
|
||||
reg_list[i].valid = 0;
|
||||
reg_list[i].type = &armv7m_reg_type;
|
||||
reg_list[i].arch_info = &arch_info[i];
|
||||
}
|
||||
|
||||
arm->cpsr = reg_list + ARMV7M_xPSR;
|
||||
arm->pc = reg_list + ARMV7M_PC;
|
||||
arm->core_cache = cache;
|
||||
return cache;
|
||||
}
|
||||
|
||||
static int armv7m_setup_semihosting(struct target *target, int enable)
|
||||
{
|
||||
/* nothing todo for armv7m */
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/** Sets up target as a generic ARMv7-M core */
|
||||
int armv7m_init_arch_info(struct target *target, struct armv7m_common *armv7m)
|
||||
{
|
||||
struct arm *arm = &armv7m->arm;
|
||||
|
||||
armv7m->common_magic = ARMV7M_COMMON_MAGIC;
|
||||
armv7m->fp_feature = FP_NONE;
|
||||
|
||||
arm->core_type = ARM_MODE_THREAD;
|
||||
arm->arch_info = armv7m;
|
||||
arm->setup_semihosting = armv7m_setup_semihosting;
|
||||
|
||||
arm->read_core_reg = armv7m_read_core_reg;
|
||||
arm->write_core_reg = armv7m_write_core_reg;
|
||||
|
||||
return arm_init_arch_info(target, arm);
|
||||
}
|
||||
|
||||
/** Generates a CRC32 checksum of a memory region. */
|
||||
int armv7m_checksum_memory(struct target *target,
|
||||
uint32_t address, uint32_t count, uint32_t *checksum)
|
||||
{
|
||||
struct working_area *crc_algorithm;
|
||||
struct armv7m_algorithm armv7m_info;
|
||||
struct reg_param reg_params[2];
|
||||
int retval;
|
||||
|
||||
/* see contrib/loaders/checksum/armv7m_crc.s for src */
|
||||
|
||||
static const uint8_t cortex_m3_crc_code[] = {
|
||||
/* main: */
|
||||
0x02, 0x46, /* mov r2, r0 */
|
||||
0x00, 0x20, /* movs r0, #0 */
|
||||
0xC0, 0x43, /* mvns r0, r0 */
|
||||
0x0A, 0x4E, /* ldr r6, CRC32XOR */
|
||||
0x0B, 0x46, /* mov r3, r1 */
|
||||
0x00, 0x24, /* movs r4, #0 */
|
||||
0x0D, 0xE0, /* b ncomp */
|
||||
/* nbyte: */
|
||||
0x11, 0x5D, /* ldrb r1, [r2, r4] */
|
||||
0x09, 0x06, /* lsls r1, r1, #24 */
|
||||
0x48, 0x40, /* eors r0, r0, r1 */
|
||||
0x00, 0x25, /* movs r5, #0 */
|
||||
/* loop: */
|
||||
0x00, 0x28, /* cmp r0, #0 */
|
||||
0x02, 0xDA, /* bge notset */
|
||||
0x40, 0x00, /* lsls r0, r0, #1 */
|
||||
0x70, 0x40, /* eors r0, r0, r6 */
|
||||
0x00, 0xE0, /* b cont */
|
||||
/* notset: */
|
||||
0x40, 0x00, /* lsls r0, r0, #1 */
|
||||
/* cont: */
|
||||
0x01, 0x35, /* adds r5, r5, #1 */
|
||||
0x08, 0x2D, /* cmp r5, #8 */
|
||||
0xF6, 0xD1, /* bne loop */
|
||||
0x01, 0x34, /* adds r4, r4, #1 */
|
||||
/* ncomp: */
|
||||
0x9C, 0x42, /* cmp r4, r3 */
|
||||
0xEF, 0xD1, /* bne nbyte */
|
||||
0x00, 0xBE, /* bkpt #0 */
|
||||
0xB7, 0x1D, 0xC1, 0x04 /* CRC32XOR: .word 0x04c11db7 */
|
||||
};
|
||||
|
||||
retval = target_alloc_working_area(target, sizeof(cortex_m3_crc_code), &crc_algorithm);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
retval = target_write_buffer(target, crc_algorithm->address,
|
||||
sizeof(cortex_m3_crc_code), (uint8_t *)cortex_m3_crc_code);
|
||||
if (retval != ERROR_OK)
|
||||
goto cleanup;
|
||||
|
||||
armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
|
||||
armv7m_info.core_mode = ARM_MODE_THREAD;
|
||||
|
||||
init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT);
|
||||
init_reg_param(®_params[1], "r1", 32, PARAM_OUT);
|
||||
|
||||
buf_set_u32(reg_params[0].value, 0, 32, address);
|
||||
buf_set_u32(reg_params[1].value, 0, 32, count);
|
||||
|
||||
int timeout = 20000 * (1 + (count / (1024 * 1024)));
|
||||
|
||||
retval = target_run_algorithm(target, 0, NULL, 2, reg_params, crc_algorithm->address,
|
||||
crc_algorithm->address + (sizeof(cortex_m3_crc_code) - 6),
|
||||
timeout, &armv7m_info);
|
||||
|
||||
if (retval == ERROR_OK)
|
||||
*checksum = buf_get_u32(reg_params[0].value, 0, 32);
|
||||
else
|
||||
LOG_ERROR("error executing cortex_m3 crc algorithm");
|
||||
|
||||
destroy_reg_param(®_params[0]);
|
||||
destroy_reg_param(®_params[1]);
|
||||
|
||||
cleanup:
|
||||
target_free_working_area(target, crc_algorithm);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/** Checks whether a memory region is zeroed. */
|
||||
int armv7m_blank_check_memory(struct target *target,
|
||||
uint32_t address, uint32_t count, uint32_t *blank)
|
||||
{
|
||||
struct working_area *erase_check_algorithm;
|
||||
struct reg_param reg_params[3];
|
||||
struct armv7m_algorithm armv7m_info;
|
||||
int retval;
|
||||
|
||||
/* see contrib/loaders/erase_check/armv7m_erase_check.s for src */
|
||||
|
||||
static const uint8_t erase_check_code[] = {
|
||||
/* loop: */
|
||||
0x03, 0x78, /* ldrb r3, [r0] */
|
||||
0x01, 0x30, /* adds r0, #1 */
|
||||
0x1A, 0x40, /* ands r2, r2, r3 */
|
||||
0x01, 0x39, /* subs r1, r1, #1 */
|
||||
0xFA, 0xD1, /* bne loop */
|
||||
0x00, 0xBE /* bkpt #0 */
|
||||
};
|
||||
|
||||
/* make sure we have a working area */
|
||||
if (target_alloc_working_area(target, sizeof(erase_check_code),
|
||||
&erase_check_algorithm) != ERROR_OK)
|
||||
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
||||
|
||||
retval = target_write_buffer(target, erase_check_algorithm->address,
|
||||
sizeof(erase_check_code), (uint8_t *)erase_check_code);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
|
||||
armv7m_info.core_mode = ARM_MODE_THREAD;
|
||||
|
||||
init_reg_param(®_params[0], "r0", 32, PARAM_OUT);
|
||||
buf_set_u32(reg_params[0].value, 0, 32, address);
|
||||
|
||||
init_reg_param(®_params[1], "r1", 32, PARAM_OUT);
|
||||
buf_set_u32(reg_params[1].value, 0, 32, count);
|
||||
|
||||
init_reg_param(®_params[2], "r2", 32, PARAM_IN_OUT);
|
||||
buf_set_u32(reg_params[2].value, 0, 32, 0xff);
|
||||
|
||||
retval = target_run_algorithm(target,
|
||||
0,
|
||||
NULL,
|
||||
3,
|
||||
reg_params,
|
||||
erase_check_algorithm->address,
|
||||
erase_check_algorithm->address + (sizeof(erase_check_code) - 2),
|
||||
10000,
|
||||
&armv7m_info);
|
||||
|
||||
if (retval == ERROR_OK)
|
||||
*blank = buf_get_u32(reg_params[2].value, 0, 32);
|
||||
|
||||
destroy_reg_param(®_params[0]);
|
||||
destroy_reg_param(®_params[1]);
|
||||
destroy_reg_param(®_params[2]);
|
||||
|
||||
target_free_working_area(target, erase_check_algorithm);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int armv7m_maybe_skip_bkpt_inst(struct target *target, bool *inst_found)
|
||||
{
|
||||
struct armv7m_common *armv7m = target_to_armv7m(target);
|
||||
struct reg *r = armv7m->arm.pc;
|
||||
bool result = false;
|
||||
|
||||
|
||||
/* if we halted last time due to a bkpt instruction
|
||||
* then we have to manually step over it, otherwise
|
||||
* the core will break again */
|
||||
|
||||
if (target->debug_reason == DBG_REASON_BREAKPOINT) {
|
||||
uint16_t op;
|
||||
uint32_t pc = buf_get_u32(r->value, 0, 32);
|
||||
|
||||
pc &= ~1;
|
||||
if (target_read_u16(target, pc, &op) == ERROR_OK) {
|
||||
if ((op & 0xFF00) == 0xBE00) {
|
||||
pc = buf_get_u32(r->value, 0, 32) + 2;
|
||||
buf_set_u32(r->value, 0, 32, pc);
|
||||
r->dirty = true;
|
||||
r->valid = true;
|
||||
result = true;
|
||||
LOG_DEBUG("Skipping over BKPT instruction");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (inst_found)
|
||||
*inst_found = result;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
const struct command_registration armv7m_command_handlers[] = {
|
||||
{
|
||||
.chain = arm_command_handlers,
|
||||
},
|
||||
{
|
||||
.chain = dap_command_handlers,
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
233
debuggers/openocd/src/target/armv7m.h
Normal file
233
debuggers/openocd/src/target/armv7m.h
Normal 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 */
|
||||
637
debuggers/openocd/src/target/avr32_ap7k.c
Normal file
637
debuggers/openocd/src/target/avr32_ap7k.c
Normal 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,
|
||||
};
|
||||
45
debuggers/openocd/src/target/avr32_ap7k.h
Normal file
45
debuggers/openocd/src/target/avr32_ap7k.h
Normal 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*/
|
||||
378
debuggers/openocd/src/target/avr32_jtag.c
Normal file
378
debuggers/openocd/src/target/avr32_jtag.c
Normal 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;
|
||||
}
|
||||
|
||||
105
debuggers/openocd/src/target/avr32_jtag.h
Normal file
105
debuggers/openocd/src/target/avr32_jtag.h
Normal 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 */
|
||||
319
debuggers/openocd/src/target/avr32_mem.c
Normal file
319
debuggers/openocd/src/target/avr32_mem.c
Normal 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;
|
||||
}
|
||||
37
debuggers/openocd/src/target/avr32_mem.h
Normal file
37
debuggers/openocd/src/target/avr32_mem.h
Normal 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 */
|
||||
116
debuggers/openocd/src/target/avr32_regs.c
Normal file
116
debuggers/openocd/src/target/avr32_regs.c
Normal 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;
|
||||
}
|
||||
46
debuggers/openocd/src/target/avr32_regs.h
Normal file
46
debuggers/openocd/src/target/avr32_regs.h
Normal 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 */
|
||||
235
debuggers/openocd/src/target/avrt.c
Normal file
235
debuggers/openocd/src/target/avrt.c
Normal 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();
|
||||
}
|
||||
39
debuggers/openocd/src/target/avrt.h
Normal file
39
debuggers/openocd/src/target/avrt.h
Normal 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 */
|
||||
502
debuggers/openocd/src/target/breakpoints.c
Normal file
502
debuggers/openocd/src/target/breakpoints.c
Normal 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);
|
||||
}
|
||||
75
debuggers/openocd/src/target/breakpoints.h
Normal file
75
debuggers/openocd/src/target/breakpoints.h
Normal 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 */
|
||||
2876
debuggers/openocd/src/target/cortex_a.c
Normal file
2876
debuggers/openocd/src/target/cortex_a.c
Normal file
File diff suppressed because it is too large
Load Diff
89
debuggers/openocd/src/target/cortex_a.h
Normal file
89
debuggers/openocd/src/target/cortex_a.h
Normal 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 */
|
||||
2305
debuggers/openocd/src/target/cortex_m.c
Normal file
2305
debuggers/openocd/src/target/cortex_m.c
Normal file
File diff suppressed because it is too large
Load Diff
201
debuggers/openocd/src/target/cortex_m.h
Normal file
201
debuggers/openocd/src/target/cortex_m.h
Normal 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 */
|
||||
2064
debuggers/openocd/src/target/dsp563xx.c
Normal file
2064
debuggers/openocd/src/target/dsp563xx.c
Normal file
File diff suppressed because it is too large
Load Diff
60
debuggers/openocd/src/target/dsp563xx.h
Normal file
60
debuggers/openocd/src/target/dsp563xx.h
Normal 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 */
|
||||
293
debuggers/openocd/src/target/dsp563xx_once.c
Normal file
293
debuggers/openocd/src/target/dsp563xx_once.c
Normal 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, ®s[i].reg);
|
||||
if (err != ERROR_OK)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (flush)
|
||||
err = jtag_execute_queue();
|
||||
return err;
|
||||
}
|
||||
|
||||
/** once read register with register len */
|
||||
int dsp563xx_once_reg_read_ex(struct jtag_tap *tap, int flush, uint8_t reg, uint8_t len, uint32_t * data)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = dsp563xx_once_ir_exec(tap, 1, reg, 1, 0, 0);
|
||||
if (err != ERROR_OK)
|
||||
return err;
|
||||
err = dsp563xx_write_dr_u32(tap, data, 0x00, len, 0);
|
||||
if (err != ERROR_OK)
|
||||
return err;
|
||||
if (flush)
|
||||
err = jtag_execute_queue();
|
||||
return err;
|
||||
}
|
||||
|
||||
/** once read register */
|
||||
int dsp563xx_once_reg_read(struct jtag_tap *tap, int flush, uint8_t reg, uint32_t * data)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = dsp563xx_once_ir_exec(tap, flush, reg, 1, 0, 0);
|
||||
if (err != ERROR_OK)
|
||||
return err;
|
||||
err = dsp563xx_write_dr_u32(tap, data, 0x00, 24, 0);
|
||||
if (err != ERROR_OK)
|
||||
return err;
|
||||
if (flush)
|
||||
err = jtag_execute_queue();
|
||||
return err;
|
||||
}
|
||||
|
||||
/** once write register */
|
||||
int dsp563xx_once_reg_write(struct jtag_tap *tap, int flush, uint8_t reg, uint32_t data)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = dsp563xx_once_ir_exec(tap, flush, reg, 0, 0, 0);
|
||||
if (err != ERROR_OK)
|
||||
return err;
|
||||
err = dsp563xx_write_dr_u32(tap, 0x00, data, 24, 0);
|
||||
if (err != ERROR_OK)
|
||||
return err;
|
||||
if (flush)
|
||||
err = jtag_execute_queue();
|
||||
return err;
|
||||
}
|
||||
|
||||
/** single word instruction */
|
||||
int dsp563xx_once_execute_sw_ir(struct jtag_tap *tap, int flush, uint32_t opcode)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = dsp563xx_once_ir_exec(tap, flush, DSP563XX_ONCE_OPDBR, 0, 1, 0);
|
||||
if (err != ERROR_OK)
|
||||
return err;
|
||||
err = dsp563xx_write_dr_u32(tap, 0, opcode, 24, 0);
|
||||
if (err != ERROR_OK)
|
||||
return err;
|
||||
if (flush)
|
||||
err = jtag_execute_queue();
|
||||
return err;
|
||||
}
|
||||
|
||||
/** double word instruction */
|
||||
int dsp563xx_once_execute_dw_ir(struct jtag_tap *tap, int flush, uint32_t opcode, uint32_t operand)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = dsp563xx_once_ir_exec(tap, flush, DSP563XX_ONCE_OPDBR, 0, 0, 0);
|
||||
if (err != ERROR_OK)
|
||||
return err;
|
||||
err = dsp563xx_write_dr_u32(tap, 0, opcode, 24, 0);
|
||||
if (err != ERROR_OK)
|
||||
return err;
|
||||
if (flush) {
|
||||
err = jtag_execute_queue();
|
||||
if (err != ERROR_OK)
|
||||
return err;
|
||||
}
|
||||
|
||||
err = dsp563xx_once_ir_exec(tap, flush, DSP563XX_ONCE_OPDBR, 0, 1, 0);
|
||||
if (err != ERROR_OK)
|
||||
return err;
|
||||
err = dsp563xx_write_dr_u32(tap, 0, operand, 24, 0);
|
||||
if (err != ERROR_OK)
|
||||
return err;
|
||||
if (flush) {
|
||||
err = jtag_execute_queue();
|
||||
if (err != ERROR_OK)
|
||||
return err;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
87
debuggers/openocd/src/target/dsp563xx_once.h
Normal file
87
debuggers/openocd/src/target/dsp563xx_once.h
Normal 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 */
|
||||
2301
debuggers/openocd/src/target/dsp5680xx.c
Normal file
2301
debuggers/openocd/src/target/dsp5680xx.c
Normal file
File diff suppressed because it is too large
Load Diff
384
debuggers/openocd/src/target/dsp5680xx.h
Normal file
384
debuggers/openocd/src/target/dsp5680xx.h
Normal 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 */
|
||||
650
debuggers/openocd/src/target/embeddedice.c
Normal file
650
debuggers/openocd/src/target/embeddedice.c
Normal 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(®_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
|
||||
127
debuggers/openocd/src/target/embeddedice.h
Normal file
127
debuggers/openocd/src/target/embeddedice.h
Normal 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 */
|
||||
706
debuggers/openocd/src/target/etb.c
Normal file
706
debuggers/openocd/src/target/etb.c
Normal 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,
|
||||
};
|
||||
60
debuggers/openocd/src/target/etb.h
Normal file
60
debuggers/openocd/src/target/etb.h
Normal 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 */
|
||||
2108
debuggers/openocd/src/target/etm.c
Normal file
2108
debuggers/openocd/src/target/etm.c
Normal file
File diff suppressed because it is too large
Load Diff
226
debuggers/openocd/src/target/etm.h
Normal file
226
debuggers/openocd/src/target/etm.h
Normal 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 */
|
||||
108
debuggers/openocd/src/target/etm_dummy.c
Normal file
108
debuggers/openocd/src/target/etm_dummy.c
Normal 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,
|
||||
};
|
||||
28
debuggers/openocd/src/target/etm_dummy.h
Normal file
28
debuggers/openocd/src/target/etm_dummy.h
Normal 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 */
|
||||
387
debuggers/openocd/src/target/fa526.c
Normal file
387
debuggers/openocd/src/target/fa526.c
Normal 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,
|
||||
};
|
||||
753
debuggers/openocd/src/target/feroceon.c
Normal file
753
debuggers/openocd/src/target/feroceon.c
Normal 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,
|
||||
};
|
||||
822
debuggers/openocd/src/target/hla_target.c
Normal file
822
debuggers/openocd/src/target/hla_target.c
Normal 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, ®);
|
||||
|
||||
switch (num) {
|
||||
case ARMV7M_PRIMASK:
|
||||
buf_set_u32((uint8_t *) ®, 0, 1, value);
|
||||
break;
|
||||
|
||||
case ARMV7M_BASEPRI:
|
||||
buf_set_u32((uint8_t *) ®, 8, 8, value);
|
||||
break;
|
||||
|
||||
case ARMV7M_FAULTMASK:
|
||||
buf_set_u32((uint8_t *) ®, 16, 1, value);
|
||||
break;
|
||||
|
||||
case ARMV7M_CONTROL:
|
||||
buf_set_u32((uint8_t *) ®, 24, 2, value);
|
||||
break;
|
||||
}
|
||||
|
||||
adapter->layout->api->write_reg(adapter->fd, 20, reg);
|
||||
|
||||
LOG_DEBUG("write special reg %i value 0x%" PRIx32 " ", (int)num, value);
|
||||
break;
|
||||
|
||||
default:
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int adapter_examine_debug_reason(struct target *target)
|
||||
{
|
||||
if ((target->debug_reason != DBG_REASON_DBGRQ)
|
||||
&& (target->debug_reason != DBG_REASON_SINGLESTEP)) {
|
||||
target->debug_reason = DBG_REASON_BREAKPOINT;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int adapter_init_arch_info(struct target *target,
|
||||
struct cortex_m3_common *cortex_m3,
|
||||
struct jtag_tap *tap)
|
||||
{
|
||||
struct armv7m_common *armv7m;
|
||||
|
||||
LOG_DEBUG("%s", __func__);
|
||||
|
||||
armv7m = &cortex_m3->armv7m;
|
||||
armv7m_init_arch_info(target, armv7m);
|
||||
|
||||
armv7m->load_core_reg_u32 = adapter_load_core_reg_u32;
|
||||
armv7m->store_core_reg_u32 = adapter_store_core_reg_u32;
|
||||
|
||||
armv7m->examine_debug_reason = adapter_examine_debug_reason;
|
||||
armv7m->stlink = true;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int adapter_init_target(struct command_context *cmd_ctx,
|
||||
struct target *target)
|
||||
{
|
||||
LOG_DEBUG("%s", __func__);
|
||||
|
||||
armv7m_build_reg_cache(target);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int adapter_target_create(struct target *target,
|
||||
Jim_Interp *interp)
|
||||
{
|
||||
LOG_DEBUG("%s", __func__);
|
||||
|
||||
struct cortex_m3_common *cortex_m3 = calloc(1, sizeof(struct cortex_m3_common));
|
||||
|
||||
if (!cortex_m3)
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
|
||||
adapter_init_arch_info(target, cortex_m3, target->tap);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int adapter_load_context(struct target *target)
|
||||
{
|
||||
struct armv7m_common *armv7m = target_to_armv7m(target);
|
||||
int num_regs = armv7m->arm.core_cache->num_regs;
|
||||
|
||||
for (int i = 0; i < num_regs; i++) {
|
||||
|
||||
struct reg *r = &armv7m->arm.core_cache->reg_list[i];
|
||||
if (!r->valid)
|
||||
armv7m->arm.read_core_reg(target, r, i, ARM_MODE_ANY);
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int adapter_debug_entry(struct target *target)
|
||||
{
|
||||
struct hl_interface_s *adapter = target_to_adapter(target);
|
||||
struct armv7m_common *armv7m = target_to_armv7m(target);
|
||||
struct arm *arm = &armv7m->arm;
|
||||
struct reg *r;
|
||||
uint32_t xPSR;
|
||||
int retval;
|
||||
|
||||
retval = armv7m->examine_debug_reason(target);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
adapter_load_context(target);
|
||||
|
||||
/* make sure we clear the vector catch bit */
|
||||
adapter->layout->api->write_debug_reg(adapter->fd, DCB_DEMCR, TRCENA);
|
||||
|
||||
r = arm->core_cache->reg_list + ARMV7M_xPSR;
|
||||
xPSR = buf_get_u32(r->value, 0, 32);
|
||||
|
||||
/* Are we in an exception handler */
|
||||
if (xPSR & 0x1FF) {
|
||||
armv7m->exception_number = (xPSR & 0x1FF);
|
||||
|
||||
arm->core_mode = ARM_MODE_HANDLER;
|
||||
arm->map = armv7m_msp_reg_map;
|
||||
} else {
|
||||
unsigned control = buf_get_u32(arm->core_cache
|
||||
->reg_list[ARMV7M_CONTROL].value, 0, 2);
|
||||
|
||||
/* is this thread privileged? */
|
||||
arm->core_mode = control & 1
|
||||
? ARM_MODE_USER_THREAD
|
||||
: ARM_MODE_THREAD;
|
||||
|
||||
/* which stack is it using? */
|
||||
if (control & 2)
|
||||
arm->map = armv7m_psp_reg_map;
|
||||
else
|
||||
arm->map = armv7m_msp_reg_map;
|
||||
|
||||
armv7m->exception_number = 0;
|
||||
}
|
||||
|
||||
LOG_DEBUG("entered debug state in core mode: %s at PC 0x%08" PRIx32 ", target->state: %s",
|
||||
arm_mode_name(arm->core_mode),
|
||||
*(uint32_t *)(arm->pc->value),
|
||||
target_state_name(target));
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int adapter_poll(struct target *target)
|
||||
{
|
||||
enum target_state state;
|
||||
struct hl_interface_s *adapter = target_to_adapter(target);
|
||||
struct armv7m_common *armv7m = target_to_armv7m(target);
|
||||
enum target_state prev_target_state = target->state;
|
||||
|
||||
state = adapter->layout->api->state(adapter->fd);
|
||||
|
||||
if (state == TARGET_UNKNOWN) {
|
||||
LOG_ERROR("jtag status contains invalid mode value - communication failure");
|
||||
return ERROR_TARGET_FAILURE;
|
||||
}
|
||||
|
||||
if (target->state == state)
|
||||
return ERROR_OK;
|
||||
|
||||
if (state == TARGET_HALTED) {
|
||||
target->state = state;
|
||||
|
||||
int retval = adapter_debug_entry(target);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
if (prev_target_state == TARGET_DEBUG_RUNNING) {
|
||||
target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED);
|
||||
} else {
|
||||
if (arm_semihosting(target, &retval) != 0)
|
||||
return retval;
|
||||
|
||||
target_call_event_callbacks(target, TARGET_EVENT_HALTED);
|
||||
}
|
||||
|
||||
LOG_DEBUG("halted: PC: 0x%08x", buf_get_u32(armv7m->arm.pc->value, 0, 32));
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int adapter_assert_reset(struct target *target)
|
||||
{
|
||||
int res = ERROR_OK;
|
||||
struct hl_interface_s *adapter = target_to_adapter(target);
|
||||
struct armv7m_common *armv7m = target_to_armv7m(target);
|
||||
bool use_srst_fallback = true;
|
||||
|
||||
LOG_DEBUG("%s", __func__);
|
||||
|
||||
enum reset_types jtag_reset_config = jtag_get_reset_config();
|
||||
|
||||
bool srst_asserted = false;
|
||||
|
||||
if (jtag_reset_config & RESET_SRST_NO_GATING) {
|
||||
jtag_add_reset(0, 1);
|
||||
res = adapter->layout->api->assert_srst(adapter->fd, 0);
|
||||
srst_asserted = true;
|
||||
}
|
||||
|
||||
adapter->layout->api->write_debug_reg(adapter->fd, DCB_DHCSR, DBGKEY|C_DEBUGEN);
|
||||
|
||||
/* only set vector catch if halt is requested */
|
||||
if (target->reset_halt)
|
||||
adapter->layout->api->write_debug_reg(adapter->fd, DCB_DEMCR, TRCENA|VC_CORERESET);
|
||||
else
|
||||
adapter->layout->api->write_debug_reg(adapter->fd, DCB_DEMCR, TRCENA);
|
||||
|
||||
if (jtag_reset_config & RESET_HAS_SRST) {
|
||||
if (!srst_asserted) {
|
||||
jtag_add_reset(0, 1);
|
||||
res = adapter->layout->api->assert_srst(adapter->fd, 0);
|
||||
}
|
||||
if (res == ERROR_COMMAND_NOTFOUND)
|
||||
LOG_ERROR("Hardware srst not supported, falling back to software reset");
|
||||
else if (res == ERROR_OK) {
|
||||
/* hardware srst supported */
|
||||
use_srst_fallback = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (use_srst_fallback) {
|
||||
/* stlink v1 api does not support hardware srst, so we use a software reset fallback */
|
||||
adapter->layout->api->write_debug_reg(adapter->fd, NVIC_AIRCR, AIRCR_VECTKEY | AIRCR_SYSRESETREQ);
|
||||
}
|
||||
|
||||
res = adapter->layout->api->reset(adapter->fd);
|
||||
|
||||
if (res != ERROR_OK)
|
||||
return res;
|
||||
|
||||
/* registers are now invalid */
|
||||
register_cache_invalidate(armv7m->arm.core_cache);
|
||||
|
||||
if (target->reset_halt) {
|
||||
target->state = TARGET_RESET;
|
||||
target->debug_reason = DBG_REASON_DBGRQ;
|
||||
} else {
|
||||
target->state = TARGET_HALTED;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int adapter_deassert_reset(struct target *target)
|
||||
{
|
||||
int res;
|
||||
struct hl_interface_s *adapter = target_to_adapter(target);
|
||||
|
||||
enum reset_types jtag_reset_config = jtag_get_reset_config();
|
||||
|
||||
LOG_DEBUG("%s", __func__);
|
||||
|
||||
if (jtag_reset_config & RESET_HAS_SRST)
|
||||
adapter->layout->api->assert_srst(adapter->fd, 1);
|
||||
|
||||
/* virtual deassert reset, we need it for the internal
|
||||
* jtag state machine
|
||||
*/
|
||||
jtag_add_reset(0, 0);
|
||||
|
||||
if (!target->reset_halt) {
|
||||
res = target_resume(target, 1, 0, 0, 0);
|
||||
|
||||
if (res != ERROR_OK)
|
||||
return res;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int adapter_soft_reset_halt(struct target *target)
|
||||
{
|
||||
LOG_DEBUG("%s", __func__);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int adapter_halt(struct target *target)
|
||||
{
|
||||
int res;
|
||||
struct hl_interface_s *adapter = target_to_adapter(target);
|
||||
|
||||
LOG_DEBUG("%s", __func__);
|
||||
|
||||
if (target->state == TARGET_HALTED) {
|
||||
LOG_DEBUG("target was already halted");
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
if (target->state == TARGET_UNKNOWN)
|
||||
LOG_WARNING("target was in unknown state when halt was requested");
|
||||
|
||||
res = adapter->layout->api->halt(adapter->fd);
|
||||
|
||||
if (res != ERROR_OK)
|
||||
return res;
|
||||
|
||||
target->debug_reason = DBG_REASON_DBGRQ;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int adapter_resume(struct target *target, int current,
|
||||
uint32_t address, int handle_breakpoints,
|
||||
int debug_execution)
|
||||
{
|
||||
int res;
|
||||
struct hl_interface_s *adapter = target_to_adapter(target);
|
||||
struct armv7m_common *armv7m = target_to_armv7m(target);
|
||||
uint32_t resume_pc;
|
||||
struct breakpoint *breakpoint = NULL;
|
||||
struct reg *pc;
|
||||
|
||||
LOG_DEBUG("%s %d 0x%08x %d %d", __func__, current, address,
|
||||
handle_breakpoints, debug_execution);
|
||||
|
||||
if (target->state != TARGET_HALTED) {
|
||||
LOG_WARNING("target not halted");
|
||||
return ERROR_TARGET_NOT_HALTED;
|
||||
}
|
||||
|
||||
if (!debug_execution) {
|
||||
target_free_all_working_areas(target);
|
||||
cortex_m3_enable_breakpoints(target);
|
||||
cortex_m3_enable_watchpoints(target);
|
||||
}
|
||||
|
||||
pc = armv7m->arm.pc;
|
||||
if (!current) {
|
||||
buf_set_u32(pc->value, 0, 32, address);
|
||||
pc->dirty = true;
|
||||
pc->valid = true;
|
||||
}
|
||||
|
||||
if (!breakpoint_find(target, buf_get_u32(pc->value, 0, 32))
|
||||
&& !debug_execution) {
|
||||
armv7m_maybe_skip_bkpt_inst(target, NULL);
|
||||
}
|
||||
|
||||
resume_pc = buf_get_u32(pc->value, 0, 32);
|
||||
|
||||
/* write any user vector flags */
|
||||
res = target_write_u32(target, DCB_DEMCR, TRCENA | armv7m->demcr);
|
||||
if (res != ERROR_OK)
|
||||
return res;
|
||||
|
||||
armv7m_restore_context(target);
|
||||
|
||||
/* registers are now invalid */
|
||||
register_cache_invalidate(armv7m->arm.core_cache);
|
||||
|
||||
/* the front-end may request us not to handle breakpoints */
|
||||
if (handle_breakpoints) {
|
||||
/* Single step past breakpoint at current address */
|
||||
breakpoint = breakpoint_find(target, resume_pc);
|
||||
if (breakpoint) {
|
||||
LOG_DEBUG("unset breakpoint at 0x%8.8" PRIx32 " (ID: %d)",
|
||||
breakpoint->address,
|
||||
breakpoint->unique_id);
|
||||
cortex_m3_unset_breakpoint(target, breakpoint);
|
||||
|
||||
res = adapter->layout->api->step(adapter->fd);
|
||||
|
||||
if (res != ERROR_OK)
|
||||
return res;
|
||||
|
||||
cortex_m3_set_breakpoint(target, breakpoint);
|
||||
}
|
||||
}
|
||||
|
||||
res = adapter->layout->api->run(adapter->fd);
|
||||
|
||||
if (res != ERROR_OK)
|
||||
return res;
|
||||
|
||||
target->debug_reason = DBG_REASON_NOTHALTED;
|
||||
|
||||
if (!debug_execution) {
|
||||
target->state = TARGET_RUNNING;
|
||||
target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
|
||||
} else {
|
||||
target->state = TARGET_DEBUG_RUNNING;
|
||||
target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED);
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int adapter_step(struct target *target, int current,
|
||||
uint32_t address, int handle_breakpoints)
|
||||
{
|
||||
int res;
|
||||
struct hl_interface_s *adapter = target_to_adapter(target);
|
||||
struct armv7m_common *armv7m = target_to_armv7m(target);
|
||||
struct breakpoint *breakpoint = NULL;
|
||||
struct reg *pc = armv7m->arm.pc;
|
||||
bool bkpt_inst_found = false;
|
||||
|
||||
LOG_DEBUG("%s", __func__);
|
||||
|
||||
if (target->state != TARGET_HALTED) {
|
||||
LOG_WARNING("target not halted");
|
||||
return ERROR_TARGET_NOT_HALTED;
|
||||
}
|
||||
|
||||
if (!current) {
|
||||
buf_set_u32(pc->value, 0, 32, address);
|
||||
pc->dirty = true;
|
||||
pc->valid = true;
|
||||
}
|
||||
|
||||
uint32_t pc_value = buf_get_u32(pc->value, 0, 32);
|
||||
|
||||
/* the front-end may request us not to handle breakpoints */
|
||||
if (handle_breakpoints) {
|
||||
breakpoint = breakpoint_find(target, pc_value);
|
||||
if (breakpoint)
|
||||
cortex_m3_unset_breakpoint(target, breakpoint);
|
||||
}
|
||||
|
||||
armv7m_maybe_skip_bkpt_inst(target, &bkpt_inst_found);
|
||||
|
||||
target->debug_reason = DBG_REASON_SINGLESTEP;
|
||||
|
||||
armv7m_restore_context(target);
|
||||
|
||||
target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
|
||||
|
||||
res = adapter->layout->api->step(adapter->fd);
|
||||
|
||||
if (res != ERROR_OK)
|
||||
return res;
|
||||
|
||||
/* registers are now invalid */
|
||||
register_cache_invalidate(armv7m->arm.core_cache);
|
||||
|
||||
if (breakpoint)
|
||||
cortex_m3_set_breakpoint(target, breakpoint);
|
||||
|
||||
adapter_debug_entry(target);
|
||||
target_call_event_callbacks(target, TARGET_EVENT_HALTED);
|
||||
|
||||
LOG_INFO("halted: PC: 0x%08x", buf_get_u32(armv7m->arm.pc->value, 0, 32));
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int adapter_read_memory(struct target *target, uint32_t address,
|
||||
uint32_t size, uint32_t count,
|
||||
uint8_t *buffer)
|
||||
{
|
||||
struct hl_interface_s *adapter = target_to_adapter(target);
|
||||
int res;
|
||||
uint32_t buffer_threshold = (adapter->param.max_buffer / 4);
|
||||
uint32_t addr_increment = 4;
|
||||
uint32_t c;
|
||||
|
||||
if (!count || !buffer)
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
|
||||
LOG_DEBUG("%s 0x%08x %d %d", __func__, address, size, count);
|
||||
|
||||
/* prepare byte count, buffer threshold
|
||||
* and address increment for none 32bit access
|
||||
*/
|
||||
if (size != 4) {
|
||||
count *= size;
|
||||
buffer_threshold = (adapter->param.max_buffer / 4) / 2;
|
||||
addr_increment = 1;
|
||||
}
|
||||
|
||||
while (count) {
|
||||
if (count > buffer_threshold)
|
||||
c = buffer_threshold;
|
||||
else
|
||||
c = count;
|
||||
|
||||
if (size != 4)
|
||||
res = adapter->layout->api->read_mem8(adapter->fd,
|
||||
address, c, buffer);
|
||||
else
|
||||
res = adapter->layout->api->read_mem32(adapter->fd,
|
||||
address, c, buffer);
|
||||
|
||||
if (res != ERROR_OK)
|
||||
return res;
|
||||
|
||||
address += (c * addr_increment);
|
||||
buffer += (c * addr_increment);
|
||||
count -= c;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int adapter_write_memory(struct target *target, uint32_t address,
|
||||
uint32_t size, uint32_t count,
|
||||
const uint8_t *buffer)
|
||||
{
|
||||
struct hl_interface_s *adapter = target_to_adapter(target);
|
||||
int res;
|
||||
uint32_t buffer_threshold = (adapter->param.max_buffer / 4);
|
||||
uint32_t addr_increment = 4;
|
||||
uint32_t c;
|
||||
|
||||
if (!count || !buffer)
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
|
||||
LOG_DEBUG("%s 0x%08x %d %d", __func__, address, size, count);
|
||||
|
||||
/* prepare byte count, buffer threshold
|
||||
* and address increment for none 32bit access
|
||||
*/
|
||||
if (size != 4) {
|
||||
count *= size;
|
||||
buffer_threshold = (adapter->param.max_buffer / 4) / 2;
|
||||
addr_increment = 1;
|
||||
}
|
||||
|
||||
while (count) {
|
||||
if (count > buffer_threshold)
|
||||
c = buffer_threshold;
|
||||
else
|
||||
c = count;
|
||||
|
||||
if (size != 4)
|
||||
res = adapter->layout->api->write_mem8(adapter->fd,
|
||||
address, c, buffer);
|
||||
else
|
||||
res = adapter->layout->api->write_mem32(adapter->fd,
|
||||
address, c, buffer);
|
||||
|
||||
if (res != ERROR_OK)
|
||||
return res;
|
||||
|
||||
address += (c * addr_increment);
|
||||
buffer += (c * addr_increment);
|
||||
count -= c;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static const struct command_registration adapter_command_handlers[] = {
|
||||
{
|
||||
.chain = arm_command_handlers,
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
struct target_type hla_target = {
|
||||
.name = "hla_target",
|
||||
.deprecated_name = "stm32_stlink",
|
||||
|
||||
.init_target = adapter_init_target,
|
||||
.target_create = adapter_target_create,
|
||||
.examine = cortex_m3_examine,
|
||||
.commands = adapter_command_handlers,
|
||||
|
||||
.poll = adapter_poll,
|
||||
.arch_state = armv7m_arch_state,
|
||||
|
||||
.assert_reset = adapter_assert_reset,
|
||||
.deassert_reset = adapter_deassert_reset,
|
||||
.soft_reset_halt = adapter_soft_reset_halt,
|
||||
|
||||
.halt = adapter_halt,
|
||||
.resume = adapter_resume,
|
||||
.step = adapter_step,
|
||||
|
||||
.get_gdb_reg_list = armv7m_get_gdb_reg_list,
|
||||
|
||||
.read_memory = adapter_read_memory,
|
||||
.write_memory = adapter_write_memory,
|
||||
.checksum_memory = armv7m_checksum_memory,
|
||||
.blank_check_memory = armv7m_blank_check_memory,
|
||||
|
||||
.run_algorithm = armv7m_run_algorithm,
|
||||
.start_algorithm = armv7m_start_algorithm,
|
||||
.wait_algorithm = armv7m_wait_algorithm,
|
||||
|
||||
.add_breakpoint = cortex_m3_add_breakpoint,
|
||||
.remove_breakpoint = cortex_m3_remove_breakpoint,
|
||||
.add_watchpoint = cortex_m3_add_watchpoint,
|
||||
.remove_watchpoint = cortex_m3_remove_watchpoint,
|
||||
};
|
||||
1042
debuggers/openocd/src/target/image.c
Normal file
1042
debuggers/openocd/src/target/image.c
Normal file
File diff suppressed because it is too large
Load Diff
112
debuggers/openocd/src/target/image.h
Normal file
112
debuggers/openocd/src/target/image.h
Normal 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 */
|
||||
835
debuggers/openocd/src/target/mips32.c
Normal file
835
debuggers/openocd/src/target/mips32.c
Normal 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(®_params[0], "a0", 32, PARAM_IN_OUT);
|
||||
buf_set_u32(reg_params[0].value, 0, 32, address);
|
||||
|
||||
init_reg_param(®_params[1], "a1", 32, PARAM_OUT);
|
||||
buf_set_u32(reg_params[1].value, 0, 32, count);
|
||||
|
||||
int timeout = 20000 * (1 + (count / (1024 * 1024)));
|
||||
|
||||
retval = target_run_algorithm(target, 0, NULL, 2, reg_params,
|
||||
crc_algorithm->address, crc_algorithm->address + (sizeof(mips_crc_code)-4), timeout,
|
||||
&mips32_info);
|
||||
if (retval != ERROR_OK) {
|
||||
destroy_reg_param(®_params[0]);
|
||||
destroy_reg_param(®_params[1]);
|
||||
target_free_working_area(target, crc_algorithm);
|
||||
return retval;
|
||||
}
|
||||
|
||||
*checksum = buf_get_u32(reg_params[0].value, 0, 32);
|
||||
|
||||
destroy_reg_param(®_params[0]);
|
||||
destroy_reg_param(®_params[1]);
|
||||
|
||||
target_free_working_area(target, crc_algorithm);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/** Checks whether a memory region is zeroed. */
|
||||
int mips32_blank_check_memory(struct target *target,
|
||||
uint32_t address, uint32_t count, uint32_t *blank)
|
||||
{
|
||||
struct working_area *erase_check_algorithm;
|
||||
struct reg_param reg_params[3];
|
||||
struct mips32_algorithm mips32_info;
|
||||
int retval;
|
||||
uint32_t i;
|
||||
|
||||
static const uint32_t erase_check_code[] = {
|
||||
/* nbyte: */
|
||||
0x80880000, /* lb $t0, ($a0) */
|
||||
0x00C83024, /* and $a2, $a2, $t0 */
|
||||
0x24A5FFFF, /* addiu $a1, $a1, -1 */
|
||||
0x14A0FFFC, /* bne $a1, $zero, nbyte */
|
||||
0x24840001, /* addiu $a0, $a0, 1 */
|
||||
0x7000003F /* sdbbp */
|
||||
};
|
||||
|
||||
/* make sure we have a working area */
|
||||
if (target_alloc_working_area(target, sizeof(erase_check_code), &erase_check_algorithm) != ERROR_OK)
|
||||
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
||||
|
||||
/* convert flash writing code into a buffer in target endianness */
|
||||
for (i = 0; i < ARRAY_SIZE(erase_check_code); i++) {
|
||||
target_write_u32(target, erase_check_algorithm->address + i*sizeof(uint32_t),
|
||||
erase_check_code[i]);
|
||||
}
|
||||
|
||||
mips32_info.common_magic = MIPS32_COMMON_MAGIC;
|
||||
mips32_info.isa_mode = MIPS32_ISA_MIPS32;
|
||||
|
||||
init_reg_param(®_params[0], "a0", 32, PARAM_OUT);
|
||||
buf_set_u32(reg_params[0].value, 0, 32, address);
|
||||
|
||||
init_reg_param(®_params[1], "a1", 32, PARAM_OUT);
|
||||
buf_set_u32(reg_params[1].value, 0, 32, count);
|
||||
|
||||
init_reg_param(®_params[2], "a2", 32, PARAM_IN_OUT);
|
||||
buf_set_u32(reg_params[2].value, 0, 32, 0xff);
|
||||
|
||||
retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
|
||||
erase_check_algorithm->address,
|
||||
erase_check_algorithm->address + (sizeof(erase_check_code)-4),
|
||||
10000, &mips32_info);
|
||||
if (retval != ERROR_OK) {
|
||||
destroy_reg_param(®_params[0]);
|
||||
destroy_reg_param(®_params[1]);
|
||||
destroy_reg_param(®_params[2]);
|
||||
target_free_working_area(target, erase_check_algorithm);
|
||||
return retval;
|
||||
}
|
||||
|
||||
*blank = buf_get_u32(reg_params[2].value, 0, 32);
|
||||
|
||||
destroy_reg_param(®_params[0]);
|
||||
destroy_reg_param(®_params[1]);
|
||||
destroy_reg_param(®_params[2]);
|
||||
|
||||
target_free_working_area(target, erase_check_algorithm);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int mips32_verify_pointer(struct command_context *cmd_ctx,
|
||||
struct mips32_common *mips32)
|
||||
{
|
||||
if (mips32->common_magic != MIPS32_COMMON_MAGIC) {
|
||||
command_print(cmd_ctx, "target is not an MIPS32");
|
||||
return ERROR_TARGET_INVALID;
|
||||
}
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* MIPS32 targets expose command interface
|
||||
* to manipulate CP0 registers
|
||||
*/
|
||||
COMMAND_HANDLER(mips32_handle_cp0_command)
|
||||
{
|
||||
int retval;
|
||||
struct target *target = get_current_target(CMD_CTX);
|
||||
struct mips32_common *mips32 = target_to_mips32(target);
|
||||
struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
|
||||
|
||||
|
||||
retval = mips32_verify_pointer(CMD_CTX, mips32);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
if (target->state != TARGET_HALTED) {
|
||||
command_print(CMD_CTX, "target must be stopped for \"%s\" command", CMD_NAME);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/* two or more argument, access a single register/select (write if third argument is given) */
|
||||
if (CMD_ARGC < 2)
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
else {
|
||||
uint32_t cp0_reg, cp0_sel;
|
||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], cp0_reg);
|
||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], cp0_sel);
|
||||
|
||||
if (CMD_ARGC == 2) {
|
||||
uint32_t value;
|
||||
|
||||
retval = mips32_cp0_read(ejtag_info, &value, cp0_reg, cp0_sel);
|
||||
if (retval != ERROR_OK) {
|
||||
command_print(CMD_CTX,
|
||||
"couldn't access reg %" PRIi32,
|
||||
cp0_reg);
|
||||
return ERROR_OK;
|
||||
}
|
||||
command_print(CMD_CTX, "cp0 reg %" PRIi32 ", select %" PRIi32 ": %8.8" PRIx32,
|
||||
cp0_reg, cp0_sel, value);
|
||||
|
||||
} else if (CMD_ARGC == 3) {
|
||||
uint32_t value;
|
||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], value);
|
||||
retval = mips32_cp0_write(ejtag_info, value, cp0_reg, cp0_sel);
|
||||
if (retval != ERROR_OK) {
|
||||
command_print(CMD_CTX,
|
||||
"couldn't access cp0 reg %" PRIi32 ", select %" PRIi32,
|
||||
cp0_reg, cp0_sel);
|
||||
return ERROR_OK;
|
||||
}
|
||||
command_print(CMD_CTX, "cp0 reg %" PRIi32 ", select %" PRIi32 ": %8.8" PRIx32,
|
||||
cp0_reg, cp0_sel, value);
|
||||
}
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(mips32_handle_scan_delay_command)
|
||||
{
|
||||
struct target *target = get_current_target(CMD_CTX);
|
||||
struct mips32_common *mips32 = target_to_mips32(target);
|
||||
struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
|
||||
|
||||
if (CMD_ARGC == 1)
|
||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], ejtag_info->scan_delay);
|
||||
else if (CMD_ARGC > 1)
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
|
||||
command_print(CMD_CTX, "scan delay: %d nsec", ejtag_info->scan_delay);
|
||||
if (ejtag_info->scan_delay >= 2000000) {
|
||||
ejtag_info->mode = 0;
|
||||
command_print(CMD_CTX, "running in legacy mode");
|
||||
} else {
|
||||
ejtag_info->mode = 1;
|
||||
command_print(CMD_CTX, "running in fast queued mode");
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static const struct command_registration mips32_exec_command_handlers[] = {
|
||||
{
|
||||
.name = "cp0",
|
||||
.handler = mips32_handle_cp0_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.usage = "regnum select [value]",
|
||||
.help = "display/modify cp0 register",
|
||||
},
|
||||
{
|
||||
.name = "scan_delay",
|
||||
.handler = mips32_handle_scan_delay_command,
|
||||
.mode = COMMAND_ANY,
|
||||
.help = "display/set scan delay in nano seconds",
|
||||
.usage = "[value]",
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
const struct command_registration mips32_command_handlers[] = {
|
||||
{
|
||||
.name = "mips32",
|
||||
.mode = COMMAND_ANY,
|
||||
.help = "mips32 command group",
|
||||
.usage = "",
|
||||
.chain = mips32_exec_command_handlers,
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
250
debuggers/openocd/src/target/mips32.h
Normal file
250
debuggers/openocd/src/target/mips32.h
Normal 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*/
|
||||
465
debuggers/openocd/src/target/mips32_dmaacc.c
Normal file
465
debuggers/openocd/src/target/mips32_dmaacc.c
Normal 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;
|
||||
}
|
||||
43
debuggers/openocd/src/target/mips32_dmaacc.h
Normal file
43
debuggers/openocd/src/target/mips32_dmaacc.h
Normal 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
|
||||
1104
debuggers/openocd/src/target/mips32_pracc.c
Normal file
1104
debuggers/openocd/src/target/mips32_pracc.c
Normal file
File diff suppressed because it is too large
Load Diff
113
debuggers/openocd/src/target/mips32_pracc.h
Normal file
113
debuggers/openocd/src/target/mips32_pracc.h
Normal 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
|
||||
364
debuggers/openocd/src/target/mips_ejtag.c
Normal file
364
debuggers/openocd/src/target/mips_ejtag.c
Normal 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;
|
||||
}
|
||||
159
debuggers/openocd/src/target/mips_ejtag.h
Normal file
159
debuggers/openocd/src/target/mips_ejtag.h
Normal 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 */
|
||||
1386
debuggers/openocd/src/target/mips_m4k.c
Normal file
1386
debuggers/openocd/src/target/mips_m4k.c
Normal file
File diff suppressed because it is too large
Load Diff
48
debuggers/openocd/src/target/mips_m4k.h
Normal file
48
debuggers/openocd/src/target/mips_m4k.h
Normal 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*/
|
||||
410
debuggers/openocd/src/target/oocd_trace.c
Normal file
410
debuggers/openocd/src/target/oocd_trace.c
Normal 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,
|
||||
};
|
||||
55
debuggers/openocd/src/target/oocd_trace.h
Normal file
55
debuggers/openocd/src/target/oocd_trace.h
Normal 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 */
|
||||
107
debuggers/openocd/src/target/register.c
Normal file
107
debuggers/openocd/src/target/register.c
Normal 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;
|
||||
}
|
||||
58
debuggers/openocd/src/target/register.h
Normal file
58
debuggers/openocd/src/target/register.h
Normal 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 */
|
||||
101
debuggers/openocd/src/target/smp.c
Normal file
101
debuggers/openocd/src/target/smp.c
Normal 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
Reference in New Issue
Block a user