aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Thompson <ianst@cadence.com>2022-06-24 22:27:32 -0700
committerAntonio Borneo <borneo.antonio@gmail.com>2022-08-20 15:38:41 +0000
commitce5ca9f7ba782ea9fba8ecd5fc1cb9407fd27949 (patch)
tree4bffcfcf737def7c23ccc7b1b53c8a56e0a63ee9
parentbe2e5c6c35f77fecb4df2a19cec05cceac500ca9 (diff)
downloadriscv-openocd-ce5ca9f7ba782ea9fba8ecd5fc1cb9407fd27949.zip
riscv-openocd-ce5ca9f7ba782ea9fba8ecd5fc1cb9407fd27949.tar.gz
riscv-openocd-ce5ca9f7ba782ea9fba8ecd5fc1cb9407fd27949.tar.bz2
target: add generic Xtensa LX support
Generic Xtensa LX support extends the original Espressif/Xtensa patch-set to support arbitrary Xtensa configurations, as defined in a core-specific .cfg file. Not yet fully-featured. Additional functionality to be added: - Xtensa NX support - DAP/SWD support - File-IO support - Generic Xtensa multi-core support Valgrind-clean, no new Clang analyzer warnings Signed-off-by: Ian Thompson <ianst@cadence.com> Change-Id: I08e7bf8fa57c25b5d0cb75a1aa7a2ac13a380c52 Reviewed-on: https://review.openocd.org/c/openocd/+/7055 Tested-by: jenkins Reviewed-by: Erhan Kurubas <erhan.kurubas@espressif.com> Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
-rw-r--r--doc/openocd.texi161
-rw-r--r--src/target/espressif/Makefile.am5
-rw-r--r--src/target/espressif/esp32.c205
-rw-r--r--src/target/espressif/esp32.h31
-rw-r--r--src/target/espressif/esp32s2.c196
-rw-r--r--src/target/espressif/esp32s2.h28
-rw-r--r--src/target/espressif/esp32s3.c239
-rw-r--r--src/target/espressif/esp32s3.h54
-rw-r--r--src/target/espressif/esp_xtensa.c3
-rw-r--r--src/target/espressif/esp_xtensa.h1
-rw-r--r--src/target/espressif/esp_xtensa_smp.c192
-rw-r--r--src/target/espressif/esp_xtensa_smp.h1
-rw-r--r--src/target/target.c2
-rw-r--r--src/target/xtensa/Makefile.am2
-rw-r--r--src/target/xtensa/xtensa.c2852
-rw-r--r--src/target/xtensa/xtensa.h211
-rw-r--r--src/target/xtensa/xtensa_chip.c170
-rw-r--r--src/target/xtensa/xtensa_chip.h34
-rw-r--r--src/target/xtensa/xtensa_regs.h224
-rw-r--r--tcl/target/esp32.cfg2
-rw-r--r--tcl/target/esp32s2.cfg2
-rw-r--r--tcl/target/esp32s3.cfg2
-rw-r--r--tcl/target/xtensa-core-esp32.cfg260
-rw-r--r--tcl/target/xtensa-core-esp32s2.cfg223
-rw-r--r--tcl/target/xtensa-core-esp32s3.cfg297
25 files changed, 3593 insertions, 1804 deletions
diff --git a/doc/openocd.texi b/doc/openocd.texi
index 9a5ab9a..0df2540 100644
--- a/doc/openocd.texi
+++ b/doc/openocd.texi
@@ -4906,6 +4906,7 @@ And two debug interfaces cores:
@item @code{testee} -- a dummy target for cases without a real CPU, e.g. CPLD.
@item @code{xscale} -- this is actually an architecture,
not a CPU type. It is based on the ARMv5 architecture.
+@item @code{xtensa} -- this is a generic Cadence/Tensilica Xtensa core.
@end itemize
@end deffn
@@ -10935,33 +10936,150 @@ OpenOCD supports debugging STM8 through the STMicroelectronics debug
protocol SWIM, @pxref{swimtransport,,SWIM}.
@section Xtensa Architecture
-Xtensa processors are based on a modular, highly flexible 32-bit RISC architecture
-that can easily scale from a tiny, cache-less controller or task engine to a high-performance
-SIMD/VLIW DSP provided by Cadence.
-@url{https://www.cadence.com/en_US/home/tools/ip/tensilica-ip/tensilica-xtensa-controllers-and-extensible-processors.html}.
-OpenOCD supports generic Xtensa processors implementation which can be customized by
-simply providing vendor-specific core configuration which controls every configurable
+Xtensa is a highly-customizable, user-extensible microprocessor and DSP
+architecture for complex embedded systems provided by Cadence Design
+Systems, Inc. See the
+@uref{https://www.cadence.com/en_US/home/tools/ip/tensilica-ip.html, Tensilica IP}
+website for additional information and documentation.
+
+OpenOCD supports generic Xtensa processor implementations which can be customized by
+providing a core-specific configuration file which describes every enabled
Xtensa architecture option, e.g. number of address registers, exceptions, reduced
-size instructions support, memory banks configuration etc. Also OpenOCD supports SMP
-configurations for Xtensa processors with any number of cores and allows to configure
-their debug signals interconnection (so-called "break/stall networks") which control how
-debug signals are distributed among cores. Xtensa "break networks" are compatible with
-ARM's Cross Trigger Interface (CTI). For debugging code on Xtensa chips OpenOCD
-uses JTAG protocol. Currently OpenOCD implements several Epsressif Xtensa-based chips of
+size instructions support, memory banks configuration etc. OpenOCD also supports SMP
+configurations for Xtensa processors with any number of cores and allows configuring
+their debug interconnect (termed "break/stall networks"), which control how debug
+signals are distributed among cores. Xtensa "break networks" are compatible with
+ARM's Cross Trigger Interface (CTI). OpenOCD implements both generic Xtensa targets
+as well as several Espressif Xtensa-based chips from the
@uref{https://www.espressif.com/en/products/socs, ESP32 family}.
-@subsection General Xtensa Commands
+OCD sessions for Xtensa processor and DSP targets are accessed via the Xtensa
+Debug Module (XDM), which provides external connectivity either through a
+traditional JTAG interface or an ARM DAP interface. If used, the DAP interface
+can control Xtensa targets through JTAG or SWD probes.
+
+@subsection Xtensa Core Configuration
+
+Due to the high level of configurability in Xtensa cores, the Xtensa target
+configuration comprises two categories:
+
+@enumerate
+@item Base Xtensa support common to all core configurations, and
+@item Core-specific support as configured for individual cores.
+@end enumerate
+
+All common Xtensa support is built into the OpenOCD Xtensa target layer and
+is enabled through a combination of TCL scripts: the target-specific
+@file{target/xtensa.cfg} and a board-specific @file{board/xtensa-*.cfg},
+similar to other target architectures.
+
+Importantly, core-specific configuration information must be provided by
+the user, and takes the form of an @file{xtensa-core-XXX.cfg} TCL script that
+defines the core's configurable features through a series of Xtensa
+configuration commands (detailed below).
+
+This core-specific @file{xtensa-core-XXX.cfg} file is typically either:
+
+@itemize @bullet
+@item Located within the Xtensa core configuration build as
+@file{src/config/xtensa-core-openocd.cfg}, or
+@item Generated by running the command @code{xt-gdb --dump-oocd-config}
+from the Xtensa processor tool-chain's command-line tools.
+@end itemize
+
+NOTE: @file{xtensa-core-XXX.cfg} must match the target Xtensa hardware
+connected to OpenOCD.
+
+Some example Xtensa configurations are bundled with OpenOCD for reference:
+@itemize @bullet
+@item Cadence Palladium VDebug emulation target. The user can combine their
+@file{xtensa-core-XXX.cfg} with the provided
+@file{board/xtensa-palladium-vdebug.cfg} to debug an emulated Xtensa RTL design.
+@item NXP MIMXRT685-EVK evaluation kit. The relevant configuration files are
+@file{board/xtensa-rt685-jlink.cfg} and @file{board/xtensa-core-nxp_rt600.cfg}.
+Additional information is provided by
+@uref{https://www.nxp.com/design/development-boards/i-mx-evaluation-and-development-boards/i-mx-rt600-evaluation-kit:MIMXRT685-EVK,
+NXP}.
+@end itemize
+
+@subsection Xtensa Configuration Commands
+
+@deffn {Command} {xtensa xtdef} (@option{LX}|@option{NX})
+Configure the Xtensa target architecture. Currently, Xtensa support is limited
+to LX6, LX7, and NX cores.
+@end deffn
+
+@deffn {Command} {xtensa xtopt} option value
+Configure Xtensa target options that are relevant to the debug subsystem.
+@var{option} is one of: @option{arnum}, @option{windowed},
+@option{cpenable}, @option{exceptions}, @option{intnum}, @option{hipriints},
+@option{excmlevel}, @option{intlevels}, @option{debuglevel},
+@option{ibreaknum}, or @option{dbreaknum}. @var{value} is an integer with
+the exact range determined by each particular option.
+
+NOTE: Some options are specific to Xtensa LX or Xtensa NX architecture, while
+others may be common to both but have different valid ranges.
+@end deffn
+
+@deffn {Command} {xtensa xtmem} (@option{iram}|@option{dram}|@option{sram}|@option{irom}|@option{drom}|@option{srom}) baseaddr bytes
+Configure Xtensa target memory. Memory type determines access rights,
+where RAMs are read/write while ROMs are read-only. @var{baseaddr} and
+@var{bytes} are both integers, typically hexadecimal and decimal, respectively.
+@end deffn
+
+@deffn {Command} {xtensa xtmem} (@option{icache}|@option{dcache}) linebytes cachebytes ways [writeback]
+Configure Xtensa processor cache. All parameters are required except for
+the optional @option{writeback} parameter; all are integers.
+@end deffn
+
+@deffn {Command} {xtensa xtmpu} numfgseg minsegsz lockable execonly
+Configure an Xtensa Memory Protection Unit (MPU). MPUs can restrict access
+and/or control cacheability of specific address ranges, but are lighter-weight
+than a full traditional MMU. All parameters are required; all are integers.
+@end deffn
+
+@deffn {Command} {xtensa xtmmu} numirefillentries numdrefillentries
+(Xtensa-LX only) Configure an Xtensa Memory Management Unit (MMU). Both
+parameters are required; both are integers.
+@end deffn
+
+@deffn {Command} {xtensa xtregs} numregs
+Configure the total number of registers for the Xtensa core. Configuration
+logic expects to subsequently process this number of @code{xtensa xtreg}
+definitions. @var{numregs} is an integer.
+@end deffn
+
+@deffn {Command} {xtensa xtregfmt} (@option{sparse}|@option{contiguous}) [general]
+Configure the type of register map used by GDB to access the Xtensa core.
+Generic Xtensa tools (e.g. xt-gdb) require @option{sparse} mapping (default) while
+Espressif tools expect @option{contiguous} mapping. Contiguous mapping takes an
+additional, optional integer parameter @option{numgregs}, which specifies the number
+of general registers used in handling g/G packets.
+@end deffn
+
+@deffn {Command} {xtensa xtreg} name offset
+Configure an Xtensa core register. All core registers are 32 bits wide,
+while TIE and user registers may have variable widths. @var{name} is a
+character string identifier while @var{offset} is a hexadecimal integer.
+@end deffn
+
+@subsection Xtensa Operation Commands
+
+@deffn {Command} {xtensa maskisr} (@option{on}|@option{off})
+(Xtensa-LX only) Mask or unmask Xtensa interrupts during instruction step.
+When masked, an interrupt that occurs during a step operation is handled and
+its ISR is executed, with the user's debug session returning after potentially
+executing many instructions. When unmasked, a triggered interrupt will result
+in execution progressing the requested number of instructions into the relevant
+vector/ISR code.
+@end deffn
@deffn {Command} {xtensa set_permissive} (0|1)
By default accessing memory beyond defined regions is forbidden. This commnd controls memory access address check.
When set to (1), skips access controls and address range check before read/write memory.
@end deffn
-@deffn {Command} {xtensa maskisr} (on|off)
-Selects whether interrupts will be disabled during stepping over single instruction. The default configuration is (off).
-@end deffn
-
@deffn {Command} {xtensa smpbreak} [none|breakinout|runstall] | [BreakIn] [BreakOut] [RunStallIn] [DebugModeOut]
Configures debug signals connection ("break network") for currently selected core.
@itemize @bullet
@@ -10985,6 +11103,13 @@ This feature is not well implemented and tested yet.
@end itemize
@end deffn
+@deffn {Command} {xtensa exe} <ascii-encoded hexadecimal instruction bytes>
+Execute arbitrary instruction(s) provided as an ascii string. The string represents an integer
+number of instruction bytes, thus its length must be even.
+@end deffn
+
+@subsection Xtensa Performance Monitor Configuration
+
@deffn {Command} {xtensa perfmon_enable} <counter_id> <select> [mask] [kernelcnt] [tracelevel]
Enable and start performance counter.
@itemize @bullet
@@ -11004,6 +11129,8 @@ whether to count.
Dump performance counter value. If no argument specified, dumps all counters.
@end deffn
+@subsection Xtensa Trace Configuration
+
@deffn {Command} {xtensa tracestart} [pc <pcval>/[<maskbitcount>]] [after <n> [ins|words]]
Set up and start a HW trace. Optionally set PC address range to trigger tracing stop when reached during program execution.
This command also allows to specify the amount of data to capture after stop trigger activation.
diff --git a/src/target/espressif/Makefile.am b/src/target/espressif/Makefile.am
index df002b3..1b4f806 100644
--- a/src/target/espressif/Makefile.am
+++ b/src/target/espressif/Makefile.am
@@ -7,8 +7,5 @@ noinst_LTLIBRARIES += %D%/libespressif.la
%D%/esp_xtensa_smp.c \
%D%/esp_xtensa_smp.h \
%D%/esp32.c \
- %D%/esp32.h \
%D%/esp32s2.c \
- %D%/esp32s2.h \
- %D%/esp32s3.c \
- %D%/esp32s3.h
+ %D%/esp32s3.c
diff --git a/src/target/espressif/esp32.c b/src/target/espressif/esp32.c
index de8f1aa..a083627 100644
--- a/src/target/espressif/esp32.c
+++ b/src/target/espressif/esp32.c
@@ -14,7 +14,6 @@
#include <target/target_type.h>
#include <target/smp.h>
#include "assert.h"
-#include "esp32.h"
#include "esp_xtensa_smp.h"
/*
@@ -70,204 +69,6 @@ implementation.
#define ESP32_RTC_CNTL_SW_CPU_STALL_REG (ESP32_RTCCNTL_BASE + 0xac)
#define ESP32_RTC_CNTL_SW_CPU_STALL_DEF 0x0
-
-/* this should map local reg IDs to GDB reg mapping as defined in xtensa-config.c 'rmap' in
- *xtensa-overlay */
-static const unsigned int esp32_gdb_regs_mapping[ESP32_NUM_REGS] = {
- XT_REG_IDX_PC,
- XT_REG_IDX_AR0, XT_REG_IDX_AR1, XT_REG_IDX_AR2, XT_REG_IDX_AR3,
- XT_REG_IDX_AR4, XT_REG_IDX_AR5, XT_REG_IDX_AR6, XT_REG_IDX_AR7,
- XT_REG_IDX_AR8, XT_REG_IDX_AR9, XT_REG_IDX_AR10, XT_REG_IDX_AR11,
- XT_REG_IDX_AR12, XT_REG_IDX_AR13, XT_REG_IDX_AR14, XT_REG_IDX_AR15,
- XT_REG_IDX_AR16, XT_REG_IDX_AR17, XT_REG_IDX_AR18, XT_REG_IDX_AR19,
- XT_REG_IDX_AR20, XT_REG_IDX_AR21, XT_REG_IDX_AR22, XT_REG_IDX_AR23,
- XT_REG_IDX_AR24, XT_REG_IDX_AR25, XT_REG_IDX_AR26, XT_REG_IDX_AR27,
- XT_REG_IDX_AR28, XT_REG_IDX_AR29, XT_REG_IDX_AR30, XT_REG_IDX_AR31,
- XT_REG_IDX_AR32, XT_REG_IDX_AR33, XT_REG_IDX_AR34, XT_REG_IDX_AR35,
- XT_REG_IDX_AR36, XT_REG_IDX_AR37, XT_REG_IDX_AR38, XT_REG_IDX_AR39,
- XT_REG_IDX_AR40, XT_REG_IDX_AR41, XT_REG_IDX_AR42, XT_REG_IDX_AR43,
- XT_REG_IDX_AR44, XT_REG_IDX_AR45, XT_REG_IDX_AR46, XT_REG_IDX_AR47,
- XT_REG_IDX_AR48, XT_REG_IDX_AR49, XT_REG_IDX_AR50, XT_REG_IDX_AR51,
- XT_REG_IDX_AR52, XT_REG_IDX_AR53, XT_REG_IDX_AR54, XT_REG_IDX_AR55,
- XT_REG_IDX_AR56, XT_REG_IDX_AR57, XT_REG_IDX_AR58, XT_REG_IDX_AR59,
- XT_REG_IDX_AR60, XT_REG_IDX_AR61, XT_REG_IDX_AR62, XT_REG_IDX_AR63,
- XT_REG_IDX_LBEG, XT_REG_IDX_LEND, XT_REG_IDX_LCOUNT, XT_REG_IDX_SAR,
- XT_REG_IDX_WINDOWBASE, XT_REG_IDX_WINDOWSTART, XT_REG_IDX_CONFIGID0, XT_REG_IDX_CONFIGID1,
- XT_REG_IDX_PS, XT_REG_IDX_THREADPTR, XT_REG_IDX_BR, XT_REG_IDX_SCOMPARE1,
- XT_REG_IDX_ACCLO, XT_REG_IDX_ACCHI,
- XT_REG_IDX_M0, XT_REG_IDX_M1, XT_REG_IDX_M2, XT_REG_IDX_M3,
- ESP32_REG_IDX_EXPSTATE,
- ESP32_REG_IDX_F64R_LO,
- ESP32_REG_IDX_F64R_HI,
- ESP32_REG_IDX_F64S,
- XT_REG_IDX_F0, XT_REG_IDX_F1, XT_REG_IDX_F2, XT_REG_IDX_F3,
- XT_REG_IDX_F4, XT_REG_IDX_F5, XT_REG_IDX_F6, XT_REG_IDX_F7,
- XT_REG_IDX_F8, XT_REG_IDX_F9, XT_REG_IDX_F10, XT_REG_IDX_F11,
- XT_REG_IDX_F12, XT_REG_IDX_F13, XT_REG_IDX_F14, XT_REG_IDX_F15,
- XT_REG_IDX_FCR, XT_REG_IDX_FSR, XT_REG_IDX_MMID, XT_REG_IDX_IBREAKENABLE,
- XT_REG_IDX_MEMCTL, XT_REG_IDX_ATOMCTL, XT_REG_IDX_OCD_DDR,
- XT_REG_IDX_IBREAKA0, XT_REG_IDX_IBREAKA1, XT_REG_IDX_DBREAKA0, XT_REG_IDX_DBREAKA1,
- XT_REG_IDX_DBREAKC0, XT_REG_IDX_DBREAKC1,
- XT_REG_IDX_EPC1, XT_REG_IDX_EPC2, XT_REG_IDX_EPC3, XT_REG_IDX_EPC4,
- XT_REG_IDX_EPC5, XT_REG_IDX_EPC6, XT_REG_IDX_EPC7, XT_REG_IDX_DEPC,
- XT_REG_IDX_EPS2, XT_REG_IDX_EPS3, XT_REG_IDX_EPS4, XT_REG_IDX_EPS5,
- XT_REG_IDX_EPS6, XT_REG_IDX_EPS7,
- XT_REG_IDX_EXCSAVE1, XT_REG_IDX_EXCSAVE2, XT_REG_IDX_EXCSAVE3, XT_REG_IDX_EXCSAVE4,
- XT_REG_IDX_EXCSAVE5, XT_REG_IDX_EXCSAVE6, XT_REG_IDX_EXCSAVE7, XT_REG_IDX_CPENABLE,
- XT_REG_IDX_INTERRUPT, XT_REG_IDX_INTSET, XT_REG_IDX_INTCLEAR, XT_REG_IDX_INTENABLE,
- XT_REG_IDX_VECBASE, XT_REG_IDX_EXCCAUSE, XT_REG_IDX_DEBUGCAUSE, XT_REG_IDX_CCOUNT,
- XT_REG_IDX_PRID, XT_REG_IDX_ICOUNT, XT_REG_IDX_ICOUNTLEVEL, XT_REG_IDX_EXCVADDR,
- XT_REG_IDX_CCOMPARE0, XT_REG_IDX_CCOMPARE1, XT_REG_IDX_CCOMPARE2,
- XT_REG_IDX_MISC0, XT_REG_IDX_MISC1, XT_REG_IDX_MISC2, XT_REG_IDX_MISC3,
- XT_REG_IDX_A0, XT_REG_IDX_A1, XT_REG_IDX_A2, XT_REG_IDX_A3,
- XT_REG_IDX_A4, XT_REG_IDX_A5, XT_REG_IDX_A6, XT_REG_IDX_A7,
- XT_REG_IDX_A8, XT_REG_IDX_A9, XT_REG_IDX_A10, XT_REG_IDX_A11,
- XT_REG_IDX_A12, XT_REG_IDX_A13, XT_REG_IDX_A14, XT_REG_IDX_A15,
- XT_REG_IDX_PWRCTL, XT_REG_IDX_PWRSTAT, XT_REG_IDX_ERISTAT,
- XT_REG_IDX_CS_ITCTRL, XT_REG_IDX_CS_CLAIMSET, XT_REG_IDX_CS_CLAIMCLR,
- XT_REG_IDX_CS_LOCKACCESS, XT_REG_IDX_CS_LOCKSTATUS, XT_REG_IDX_CS_AUTHSTATUS,
- XT_REG_IDX_FAULT_INFO,
- XT_REG_IDX_TRAX_ID, XT_REG_IDX_TRAX_CTRL, XT_REG_IDX_TRAX_STAT,
- XT_REG_IDX_TRAX_DATA, XT_REG_IDX_TRAX_ADDR, XT_REG_IDX_TRAX_PCTRIGGER,
- XT_REG_IDX_TRAX_PCMATCH, XT_REG_IDX_TRAX_DELAY, XT_REG_IDX_TRAX_MEMSTART,
- XT_REG_IDX_TRAX_MEMEND,
- XT_REG_IDX_PMG, XT_REG_IDX_PMPC, XT_REG_IDX_PM0, XT_REG_IDX_PM1,
- XT_REG_IDX_PMCTRL0, XT_REG_IDX_PMCTRL1, XT_REG_IDX_PMSTAT0, XT_REG_IDX_PMSTAT1,
- XT_REG_IDX_OCD_ID, XT_REG_IDX_OCD_DCRCLR, XT_REG_IDX_OCD_DCRSET, XT_REG_IDX_OCD_DSR,
-};
-
-static const struct xtensa_user_reg_desc esp32_user_regs[ESP32_NUM_REGS - XT_NUM_REGS] = {
- { "expstate", 0xE6, 0, 32, &xtensa_user_reg_u32_type },
- { "f64r_lo", 0xEA, 0, 32, &xtensa_user_reg_u32_type },
- { "f64r_hi", 0xEB, 0, 32, &xtensa_user_reg_u32_type },
- { "f64s", 0xEC, 0, 32, &xtensa_user_reg_u32_type },
-};
-
-static const struct xtensa_config esp32_xtensa_cfg = {
- .density = true,
- .aregs_num = XT_AREGS_NUM_MAX,
- .windowed = true,
- .coproc = true,
- .fp_coproc = true,
- .loop = true,
- .miscregs_num = 4,
- .threadptr = true,
- .boolean = true,
- .reloc_vec = true,
- .proc_id = true,
- .cond_store = true,
- .mac16 = true,
- .user_regs_num = ARRAY_SIZE(esp32_user_regs),
- .user_regs = esp32_user_regs,
- .fetch_user_regs = xtensa_fetch_user_regs_u32,
- .queue_write_dirty_user_regs = xtensa_queue_write_dirty_user_regs_u32,
- .gdb_general_regs_num = ESP32_NUM_REGS_G_COMMAND,
- .gdb_regs_mapping = esp32_gdb_regs_mapping,
- .irom = {
- .count = 2,
- .regions = {
- {
- .base = ESP32_IROM_LOW,
- .size = ESP32_IROM_HIGH - ESP32_IROM_LOW,
- .access = XT_MEM_ACCESS_READ,
- },
- {
- .base = ESP32_IROM_MASK_LOW,
- .size = ESP32_IROM_MASK_HIGH - ESP32_IROM_MASK_LOW,
- .access = XT_MEM_ACCESS_READ,
- },
- }
- },
- .iram = {
- .count = 2,
- .regions = {
- {
- .base = ESP32_IRAM_LOW,
- .size = ESP32_IRAM_HIGH - ESP32_IRAM_LOW,
- .access = XT_MEM_ACCESS_READ | XT_MEM_ACCESS_WRITE,
- },
- {
- .base = ESP32_RTC_IRAM_LOW,
- .size = ESP32_RTC_IRAM_HIGH - ESP32_RTC_IRAM_LOW,
- .access = XT_MEM_ACCESS_READ | XT_MEM_ACCESS_WRITE,
- },
- }
- },
- .drom = {
- .count = 1,
- .regions = {
- {
- .base = ESP32_DROM_LOW,
- .size = ESP32_DROM_HIGH - ESP32_DROM_LOW,
- .access = XT_MEM_ACCESS_READ,
- },
- }
- },
- .dram = {
- .count = 6,
- .regions = {
- {
- .base = ESP32_DRAM_LOW,
- .size = ESP32_DRAM_HIGH - ESP32_DRAM_LOW,
- .access = XT_MEM_ACCESS_READ | XT_MEM_ACCESS_WRITE,
- },
- {
- .base = ESP32_RTC_DRAM_LOW,
- .size = ESP32_RTC_DRAM_HIGH - ESP32_RTC_DRAM_LOW,
- .access = XT_MEM_ACCESS_READ | XT_MEM_ACCESS_WRITE,
- },
- {
- .base = ESP32_RTC_DATA_LOW,
- .size = ESP32_RTC_DATA_HIGH - ESP32_RTC_DATA_LOW,
- .access = XT_MEM_ACCESS_READ | XT_MEM_ACCESS_WRITE,
- },
- {
- .base = ESP32_EXTRAM_DATA_LOW,
- .size = ESP32_EXTRAM_DATA_HIGH - ESP32_EXTRAM_DATA_LOW,
- .access = XT_MEM_ACCESS_READ | XT_MEM_ACCESS_WRITE,
- },
- {
- .base = ESP32_DR_REG_LOW,
- .size = ESP32_DR_REG_HIGH - ESP32_DR_REG_LOW,
- .access = XT_MEM_ACCESS_READ | XT_MEM_ACCESS_WRITE,
- },
- {
- .base = ESP32_SYS_RAM_LOW,
- .size = ESP32_SYS_RAM_HIGH - ESP32_SYS_RAM_LOW,
- .access = XT_MEM_ACCESS_READ | XT_MEM_ACCESS_WRITE,
- },
- }
- },
- .exc = {
- .enabled = true,
- },
- .irq = {
- .enabled = true,
- .irq_num = 32,
- },
- .high_irq = {
- .enabled = true,
- .excm_level = 3,
- .nmi_num = 1,
- },
- .tim_irq = {
- .enabled = true,
- .comp_num = 3,
- },
- .debug = {
- .enabled = true,
- .irq_level = 6,
- .ibreaks_num = 2,
- .dbreaks_num = 2,
- .icount_sz = 32,
- },
- .trace = {
- .enabled = true,
- .mem_sz = ESP32_TRACEMEM_BLOCK_SZ,
- .reversed_mem_access = true,
- },
-};
-
/* 0 - don't care, 1 - TMS low, 2 - TMS high */
enum esp32_flash_bootstrap {
FBS_DONTCARE = 0,
@@ -401,7 +202,8 @@ static int esp32_soc_reset(struct target *target)
alive_sleep(10);
xtensa_poll(target);
if (timeval_ms() >= timeout) {
- LOG_TARGET_ERROR(target, "Timed out waiting for CPU to be reset, target state=%d", target->state);
+ LOG_TARGET_ERROR(target, "Timed out waiting for CPU to be reset, target state=%d",
+ target->state);
get_timeout = true;
break;
}
@@ -481,7 +283,6 @@ static int esp32_virt2phys(struct target *target,
return ERROR_FAIL;
}
-
/* The TDI pin is also used as a flash Vcc bootstrap pin. If we reset the CPU externally, the last state of the TDI pin
* can allow the power to an 1.8V flash chip to be raised to 3.3V, or the other way around. Users can use the
* esp32 flashbootstrap command to set a level, and this routine will make sure the tdi line will return to
@@ -544,7 +345,7 @@ static int esp32_target_create(struct target *target, Jim_Interp *interp)
return ERROR_FAIL;
}
- int ret = esp_xtensa_smp_init_arch_info(target, &esp32->esp_xtensa_smp, &esp32_xtensa_cfg,
+ int ret = esp_xtensa_smp_init_arch_info(target, &esp32->esp_xtensa_smp,
&esp32_dm_cfg, &esp32_chip_ops);
if (ret != ERROR_OK) {
LOG_ERROR("Failed to init arch info!");
diff --git a/src/target/espressif/esp32.h b/src/target/espressif/esp32.h
deleted file mode 100644
index f07c08d..0000000
--- a/src/target/espressif/esp32.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-/***************************************************************************
- * ESP32 target for OpenOCD *
- * Copyright (C) 2017 Espressif Systems Ltd. *
- ***************************************************************************/
-
-#ifndef OPENOCD_TARGET_ESP32_H
-#define OPENOCD_TARGET_ESP32_H
-
-#include <target/xtensa/xtensa_regs.h>
-
-#define ESP32_DROM_LOW 0x3F400000
-#define ESP32_DROM_HIGH 0x3F800000
-#define ESP32_IROM_LOW 0x400D0000
-#define ESP32_IROM_HIGH 0x40400000
-
-/* Number of registers returned directly by the G command
- * Corresponds to the amount of regs listed in regformats/reg-xtensa.dat in the gdb source */
-#define ESP32_NUM_REGS_G_COMMAND 105
-
-enum esp32_reg_id {
- /* chip specific registers that extend ISA go after ISA-defined ones */
- ESP32_REG_IDX_EXPSTATE = XT_USR_REG_START,
- ESP32_REG_IDX_F64R_LO,
- ESP32_REG_IDX_F64R_HI,
- ESP32_REG_IDX_F64S,
- ESP32_NUM_REGS,
-};
-
-#endif /* OPENOCD_TARGET_ESP32_H */
diff --git a/src/target/espressif/esp32s2.c b/src/target/espressif/esp32s2.c
index bbf7ff5..0bcd20f 100644
--- a/src/target/espressif/esp32s2.c
+++ b/src/target/espressif/esp32s2.c
@@ -14,7 +14,6 @@
#include <target/target.h>
#include <target/target_type.h>
#include "esp_xtensa.h"
-#include "esp32s2.h"
/* Overall memory map
* TODO: read memory configuration from target registers */
@@ -89,190 +88,6 @@
#define ESP32_S2_DR_REG_UART_BASE 0x3f400000
#define ESP32_S2_REG_UART_BASE(i) (ESP32_S2_DR_REG_UART_BASE + (i) * 0x10000)
#define ESP32_S2_UART_DATE_REG(i) (ESP32_S2_REG_UART_BASE(i) + 0x74)
-
-/* this should map local reg IDs to GDB reg mapping as defined in xtensa-config.c 'rmap' in
- * xtensa-overlay */
-static const unsigned int esp32s2_gdb_regs_mapping[ESP32_S2_NUM_REGS] = {
- XT_REG_IDX_PC,
- XT_REG_IDX_AR0, XT_REG_IDX_AR1, XT_REG_IDX_AR2, XT_REG_IDX_AR3,
- XT_REG_IDX_AR4, XT_REG_IDX_AR5, XT_REG_IDX_AR6, XT_REG_IDX_AR7,
- XT_REG_IDX_AR8, XT_REG_IDX_AR9, XT_REG_IDX_AR10, XT_REG_IDX_AR11,
- XT_REG_IDX_AR12, XT_REG_IDX_AR13, XT_REG_IDX_AR14, XT_REG_IDX_AR15,
- XT_REG_IDX_AR16, XT_REG_IDX_AR17, XT_REG_IDX_AR18, XT_REG_IDX_AR19,
- XT_REG_IDX_AR20, XT_REG_IDX_AR21, XT_REG_IDX_AR22, XT_REG_IDX_AR23,
- XT_REG_IDX_AR24, XT_REG_IDX_AR25, XT_REG_IDX_AR26, XT_REG_IDX_AR27,
- XT_REG_IDX_AR28, XT_REG_IDX_AR29, XT_REG_IDX_AR30, XT_REG_IDX_AR31,
- XT_REG_IDX_AR32, XT_REG_IDX_AR33, XT_REG_IDX_AR34, XT_REG_IDX_AR35,
- XT_REG_IDX_AR36, XT_REG_IDX_AR37, XT_REG_IDX_AR38, XT_REG_IDX_AR39,
- XT_REG_IDX_AR40, XT_REG_IDX_AR41, XT_REG_IDX_AR42, XT_REG_IDX_AR43,
- XT_REG_IDX_AR44, XT_REG_IDX_AR45, XT_REG_IDX_AR46, XT_REG_IDX_AR47,
- XT_REG_IDX_AR48, XT_REG_IDX_AR49, XT_REG_IDX_AR50, XT_REG_IDX_AR51,
- XT_REG_IDX_AR52, XT_REG_IDX_AR53, XT_REG_IDX_AR54, XT_REG_IDX_AR55,
- XT_REG_IDX_AR56, XT_REG_IDX_AR57, XT_REG_IDX_AR58, XT_REG_IDX_AR59,
- XT_REG_IDX_AR60, XT_REG_IDX_AR61, XT_REG_IDX_AR62, XT_REG_IDX_AR63,
- XT_REG_IDX_SAR,
- XT_REG_IDX_WINDOWBASE, XT_REG_IDX_WINDOWSTART, XT_REG_IDX_CONFIGID0, XT_REG_IDX_CONFIGID1,
- XT_REG_IDX_PS, XT_REG_IDX_THREADPTR,
- ESP32_S2_REG_IDX_GPIOOUT,
- XT_REG_IDX_MMID, XT_REG_IDX_IBREAKENABLE, XT_REG_IDX_OCD_DDR,
- XT_REG_IDX_IBREAKA0, XT_REG_IDX_IBREAKA1, XT_REG_IDX_DBREAKA0, XT_REG_IDX_DBREAKA1,
- XT_REG_IDX_DBREAKC0, XT_REG_IDX_DBREAKC1,
- XT_REG_IDX_EPC1, XT_REG_IDX_EPC2, XT_REG_IDX_EPC3, XT_REG_IDX_EPC4,
- XT_REG_IDX_EPC5, XT_REG_IDX_EPC6, XT_REG_IDX_EPC7, XT_REG_IDX_DEPC,
- XT_REG_IDX_EPS2, XT_REG_IDX_EPS3, XT_REG_IDX_EPS4, XT_REG_IDX_EPS5,
- XT_REG_IDX_EPS6, XT_REG_IDX_EPS7,
- XT_REG_IDX_EXCSAVE1, XT_REG_IDX_EXCSAVE2, XT_REG_IDX_EXCSAVE3, XT_REG_IDX_EXCSAVE4,
- XT_REG_IDX_EXCSAVE5, XT_REG_IDX_EXCSAVE6, XT_REG_IDX_EXCSAVE7, XT_REG_IDX_CPENABLE,
- XT_REG_IDX_INTERRUPT, XT_REG_IDX_INTSET, XT_REG_IDX_INTCLEAR, XT_REG_IDX_INTENABLE,
- XT_REG_IDX_VECBASE, XT_REG_IDX_EXCCAUSE, XT_REG_IDX_DEBUGCAUSE, XT_REG_IDX_CCOUNT,
- XT_REG_IDX_PRID, XT_REG_IDX_ICOUNT, XT_REG_IDX_ICOUNTLEVEL, XT_REG_IDX_EXCVADDR,
- XT_REG_IDX_CCOMPARE0, XT_REG_IDX_CCOMPARE1, XT_REG_IDX_CCOMPARE2,
- XT_REG_IDX_MISC0, XT_REG_IDX_MISC1, XT_REG_IDX_MISC2, XT_REG_IDX_MISC3,
- XT_REG_IDX_A0, XT_REG_IDX_A1, XT_REG_IDX_A2, XT_REG_IDX_A3,
- XT_REG_IDX_A4, XT_REG_IDX_A5, XT_REG_IDX_A6, XT_REG_IDX_A7,
- XT_REG_IDX_A8, XT_REG_IDX_A9, XT_REG_IDX_A10, XT_REG_IDX_A11,
- XT_REG_IDX_A12, XT_REG_IDX_A13, XT_REG_IDX_A14, XT_REG_IDX_A15,
- XT_REG_IDX_PWRCTL, XT_REG_IDX_PWRSTAT, XT_REG_IDX_ERISTAT,
- XT_REG_IDX_CS_ITCTRL, XT_REG_IDX_CS_CLAIMSET, XT_REG_IDX_CS_CLAIMCLR,
- XT_REG_IDX_CS_LOCKACCESS, XT_REG_IDX_CS_LOCKSTATUS, XT_REG_IDX_CS_AUTHSTATUS,
- XT_REG_IDX_FAULT_INFO,
- XT_REG_IDX_TRAX_ID, XT_REG_IDX_TRAX_CTRL, XT_REG_IDX_TRAX_STAT,
- XT_REG_IDX_TRAX_DATA, XT_REG_IDX_TRAX_ADDR, XT_REG_IDX_TRAX_PCTRIGGER,
- XT_REG_IDX_TRAX_PCMATCH, XT_REG_IDX_TRAX_DELAY, XT_REG_IDX_TRAX_MEMSTART,
- XT_REG_IDX_TRAX_MEMEND,
- XT_REG_IDX_PMG, XT_REG_IDX_PMPC, XT_REG_IDX_PM0, XT_REG_IDX_PM1,
- XT_REG_IDX_PMCTRL0, XT_REG_IDX_PMCTRL1, XT_REG_IDX_PMSTAT0, XT_REG_IDX_PMSTAT1,
- XT_REG_IDX_OCD_ID, XT_REG_IDX_OCD_DCRCLR, XT_REG_IDX_OCD_DCRSET, XT_REG_IDX_OCD_DSR,
-};
-
-static const struct xtensa_user_reg_desc esp32s2_user_regs[ESP32_S2_NUM_REGS - XT_NUM_REGS] = {
- { "gpio_out", 0x00, 0, 32, &xtensa_user_reg_u32_type },
-};
-
-static const struct xtensa_config esp32s2_xtensa_cfg = {
- .density = true,
- .aregs_num = XT_AREGS_NUM_MAX,
- .windowed = true,
- .coproc = true,
- .miscregs_num = 4,
- .reloc_vec = true,
- .proc_id = true,
- .threadptr = true,
- .user_regs_num = ARRAY_SIZE(esp32s2_user_regs),
- .user_regs = esp32s2_user_regs,
- .fetch_user_regs = xtensa_fetch_user_regs_u32,
- .queue_write_dirty_user_regs = xtensa_queue_write_dirty_user_regs_u32,
- .gdb_general_regs_num = ESP32_S2_NUM_REGS_G_COMMAND,
- .gdb_regs_mapping = esp32s2_gdb_regs_mapping,
- .irom = {
- .count = 2,
- .regions = {
- {
- .base = ESP32_S2_IROM_LOW,
- .size = ESP32_S2_IROM_HIGH - ESP32_S2_IROM_LOW,
- .access = XT_MEM_ACCESS_READ,
- },
- {
- .base = ESP32_S2_IROM_MASK_LOW,
- .size = ESP32_S2_IROM_MASK_HIGH - ESP32_S2_IROM_MASK_LOW,
- .access = XT_MEM_ACCESS_READ,
- },
- }
- },
- .iram = {
- .count = 2,
- .regions = {
- {
- .base = ESP32_S2_IRAM_LOW,
- .size = ESP32_S2_IRAM_HIGH - ESP32_S2_IRAM_LOW,
- .access = XT_MEM_ACCESS_READ | XT_MEM_ACCESS_WRITE,
- },
- {
- .base = ESP32_S2_RTC_IRAM_LOW,
- .size = ESP32_S2_RTC_IRAM_HIGH - ESP32_S2_RTC_IRAM_LOW,
- .access = XT_MEM_ACCESS_READ | XT_MEM_ACCESS_WRITE,
- },
- }
- },
- .drom = {
- .count = 2,
- .regions = {
- {
- .base = ESP32_S2_DROM0_LOW,
- .size = ESP32_S2_DROM0_HIGH - ESP32_S2_DROM0_LOW,
- .access = XT_MEM_ACCESS_READ,
- },
- {
- .base = ESP32_S2_DROM1_LOW,
- .size = ESP32_S2_DROM1_HIGH - ESP32_S2_DROM1_LOW,
- .access = XT_MEM_ACCESS_READ,
- },
- }
- },
- .dram = {
- .count = 6,
- .regions = {
- {
- .base = ESP32_S2_DRAM_LOW,
- .size = ESP32_S2_DRAM_HIGH - ESP32_S2_DRAM_LOW,
- .access = XT_MEM_ACCESS_READ | XT_MEM_ACCESS_WRITE,
- },
- {
- .base = ESP32_S2_RTC_DRAM_LOW,
- .size = ESP32_S2_RTC_DRAM_HIGH - ESP32_S2_RTC_DRAM_LOW,
- .access = XT_MEM_ACCESS_READ | XT_MEM_ACCESS_WRITE,
- },
- {
- .base = ESP32_S2_RTC_DATA_LOW,
- .size = ESP32_S2_RTC_DATA_HIGH - ESP32_S2_RTC_DATA_LOW,
- .access = XT_MEM_ACCESS_READ | XT_MEM_ACCESS_WRITE,
- },
- {
- .base = ESP32_S2_EXTRAM_DATA_LOW,
- .size = ESP32_S2_EXTRAM_DATA_HIGH - ESP32_S2_EXTRAM_DATA_LOW,
- .access = XT_MEM_ACCESS_READ | XT_MEM_ACCESS_WRITE,
- },
- {
- .base = ESP32_S2_DR_REG_LOW,
- .size = ESP32_S2_DR_REG_HIGH - ESP32_S2_DR_REG_LOW,
- .access = XT_MEM_ACCESS_READ | XT_MEM_ACCESS_WRITE,
- },
- {
- .base = ESP32_S2_SYS_RAM_LOW,
- .size = ESP32_S2_SYS_RAM_HIGH - ESP32_S2_SYS_RAM_LOW,
- .access = XT_MEM_ACCESS_READ | XT_MEM_ACCESS_WRITE,
- },
- }
- },
- .exc = {
- .enabled = true,
- },
- .irq = {
- .enabled = true,
- .irq_num = 32,
- },
- .high_irq = {
- .enabled = true,
- .excm_level = 3,
- .nmi_num = 1,
- },
- .tim_irq = {
- .enabled = true,
- .comp_num = 3,
- },
- .debug = {
- .enabled = true,
- .irq_level = 6,
- .ibreaks_num = 2,
- .dbreaks_num = 2,
- .icount_sz = 32,
- },
- .trace = {
- .enabled = true,
- .mem_sz = ESP32_S2_TRACEMEM_BLOCK_SZ,
- },
-};
-
struct esp32s2_common {
struct esp_xtensa_common esp_xtensa;
};
@@ -313,7 +128,7 @@ int esp32s2_soft_reset_halt(struct target *target)
int res = esp32s2_soc_reset(target);
if (res != ERROR_OK)
return res;
- return xtensa_assert_reset(target);
+ return xtensa_soft_reset_halt(target);
}
static int esp32s2_set_peri_reg_mask(struct target *target,
@@ -476,7 +291,8 @@ static int esp32s2_soc_reset(struct target *target)
alive_sleep(10);
xtensa_poll(target);
if (timeval_ms() >= timeout) {
- LOG_TARGET_ERROR(target, "Timed out waiting for CPU to be reset, target state=%d", target->state);
+ LOG_TARGET_ERROR(target, "Timed out waiting for CPU to be reset, target state=%d",
+ target->state);
return ERROR_TARGET_TIMEOUT;
}
}
@@ -638,7 +454,7 @@ static int esp32s2_target_create(struct target *target, Jim_Interp *interp)
return ERROR_FAIL;
}
- int ret = esp_xtensa_init_arch_info(target, &esp32->esp_xtensa, &esp32s2_xtensa_cfg, &esp32s2_dm_cfg);
+ int ret = esp_xtensa_init_arch_info(target, &esp32->esp_xtensa, &esp32s2_dm_cfg);
if (ret != ERROR_OK) {
LOG_ERROR("Failed to init arch info!");
free(esp32);
@@ -653,10 +469,6 @@ static int esp32s2_target_create(struct target *target, Jim_Interp *interp)
static const struct command_registration esp32s2_command_handlers[] = {
{
- .name = "xtensa",
- .mode = COMMAND_ANY,
- .help = "Xtensa commands group",
- .usage = "",
.chain = xtensa_command_handlers,
},
COMMAND_REGISTRATION_DONE
diff --git a/src/target/espressif/esp32s2.h b/src/target/espressif/esp32s2.h
deleted file mode 100644
index 26fc7a1..0000000
--- a/src/target/espressif/esp32s2.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-/***************************************************************************
- * ESP32-S2 target for OpenOCD *
- * Copyright (C) 2019 Espressif Systems Ltd. *
- ***************************************************************************/
-
-#ifndef OPENOCD_TARGET_ESP32S2_H
-#define OPENOCD_TARGET_ESP32S2_H
-
-#include <target/xtensa/xtensa_regs.h>
-
-#define ESP32_S2_DROM_LOW 0x3f000000
-#define ESP32_S2_DROM_HIGH 0x3ff80000
-#define ESP32_S2_IROM_LOW 0x40080000
-#define ESP32_S2_IROM_HIGH 0x40800000
-
-/* Number of registers returned directly by the G command
- * Corresponds to the amount of regs listed in regformats/reg-xtensa.dat in the gdb source */
-#define ESP32_S2_NUM_REGS_G_COMMAND 72
-
-enum esp32s2_reg_id {
- /* chip specific registers that extend ISA go after ISA-defined ones */
- ESP32_S2_REG_IDX_GPIOOUT = XT_USR_REG_START,
- ESP32_S2_NUM_REGS,
-};
-
-#endif /* OPENOCD_TARGET_ESP32S2_H */
diff --git a/src/target/espressif/esp32s3.c b/src/target/espressif/esp32s3.c
index b548740..b870059 100644
--- a/src/target/espressif/esp32s3.c
+++ b/src/target/espressif/esp32s3.c
@@ -14,7 +14,6 @@
#include <target/target_type.h>
#include <target/smp.h>
#include "assert.h"
-#include "esp32s3.h"
#include "esp_xtensa_smp.h"
/*
@@ -75,246 +74,10 @@ implementation.
#define ESP32_S3_RTC_CNTL_SW_CPU_STALL_REG (ESP32_S3_RTCCNTL_BASE + 0xBC)
#define ESP32_S3_RTC_CNTL_SW_CPU_STALL_DEF 0x0
-/* this should map local reg IDs to GDB reg mapping as defined in xtensa-config.c 'rmap' in
- *xtensa-overlay */
-static const unsigned int esp32s3_gdb_regs_mapping[ESP32_S3_NUM_REGS] = {
- XT_REG_IDX_PC,
- XT_REG_IDX_AR0, XT_REG_IDX_AR1, XT_REG_IDX_AR2, XT_REG_IDX_AR3,
- XT_REG_IDX_AR4, XT_REG_IDX_AR5, XT_REG_IDX_AR6, XT_REG_IDX_AR7,
- XT_REG_IDX_AR8, XT_REG_IDX_AR9, XT_REG_IDX_AR10, XT_REG_IDX_AR11,
- XT_REG_IDX_AR12, XT_REG_IDX_AR13, XT_REG_IDX_AR14, XT_REG_IDX_AR15,
- XT_REG_IDX_AR16, XT_REG_IDX_AR17, XT_REG_IDX_AR18, XT_REG_IDX_AR19,
- XT_REG_IDX_AR20, XT_REG_IDX_AR21, XT_REG_IDX_AR22, XT_REG_IDX_AR23,
- XT_REG_IDX_AR24, XT_REG_IDX_AR25, XT_REG_IDX_AR26, XT_REG_IDX_AR27,
- XT_REG_IDX_AR28, XT_REG_IDX_AR29, XT_REG_IDX_AR30, XT_REG_IDX_AR31,
- XT_REG_IDX_AR32, XT_REG_IDX_AR33, XT_REG_IDX_AR34, XT_REG_IDX_AR35,
- XT_REG_IDX_AR36, XT_REG_IDX_AR37, XT_REG_IDX_AR38, XT_REG_IDX_AR39,
- XT_REG_IDX_AR40, XT_REG_IDX_AR41, XT_REG_IDX_AR42, XT_REG_IDX_AR43,
- XT_REG_IDX_AR44, XT_REG_IDX_AR45, XT_REG_IDX_AR46, XT_REG_IDX_AR47,
- XT_REG_IDX_AR48, XT_REG_IDX_AR49, XT_REG_IDX_AR50, XT_REG_IDX_AR51,
- XT_REG_IDX_AR52, XT_REG_IDX_AR53, XT_REG_IDX_AR54, XT_REG_IDX_AR55,
- XT_REG_IDX_AR56, XT_REG_IDX_AR57, XT_REG_IDX_AR58, XT_REG_IDX_AR59,
- XT_REG_IDX_AR60, XT_REG_IDX_AR61, XT_REG_IDX_AR62, XT_REG_IDX_AR63,
- XT_REG_IDX_LBEG, XT_REG_IDX_LEND, XT_REG_IDX_LCOUNT, XT_REG_IDX_SAR,
- XT_REG_IDX_WINDOWBASE, XT_REG_IDX_WINDOWSTART, XT_REG_IDX_CONFIGID0, XT_REG_IDX_CONFIGID1,
- XT_REG_IDX_PS, XT_REG_IDX_THREADPTR, XT_REG_IDX_BR, XT_REG_IDX_SCOMPARE1,
- XT_REG_IDX_ACCLO, XT_REG_IDX_ACCHI,
- XT_REG_IDX_M0, XT_REG_IDX_M1, XT_REG_IDX_M2, XT_REG_IDX_M3,
- ESP32_S3_REG_IDX_GPIOOUT,
- XT_REG_IDX_F0, XT_REG_IDX_F1, XT_REG_IDX_F2, XT_REG_IDX_F3,
- XT_REG_IDX_F4, XT_REG_IDX_F5, XT_REG_IDX_F6, XT_REG_IDX_F7,
- XT_REG_IDX_F8, XT_REG_IDX_F9, XT_REG_IDX_F10, XT_REG_IDX_F11,
- XT_REG_IDX_F12, XT_REG_IDX_F13, XT_REG_IDX_F14, XT_REG_IDX_F15,
- XT_REG_IDX_FCR, XT_REG_IDX_FSR,
- ESP32_S3_REG_IDX_ACCX_0, ESP32_S3_REG_IDX_ACCX_1,
- ESP32_S3_REG_IDX_QACC_H_0, ESP32_S3_REG_IDX_QACC_H_1, ESP32_S3_REG_IDX_QACC_H_2,
- ESP32_S3_REG_IDX_QACC_H_3, ESP32_S3_REG_IDX_QACC_H_4,
- ESP32_S3_REG_IDX_QACC_L_0, ESP32_S3_REG_IDX_QACC_L_1, ESP32_S3_REG_IDX_QACC_L_2,
- ESP32_S3_REG_IDX_QACC_L_3, ESP32_S3_REG_IDX_QACC_L_4,
- ESP32_S3_REG_IDX_SAR_BYTE, ESP32_S3_REG_IDX_FFT_BIT_WIDTH,
- ESP32_S3_REG_IDX_UA_STATE_0, ESP32_S3_REG_IDX_UA_STATE_1, ESP32_S3_REG_IDX_UA_STATE_2,
- ESP32_S3_REG_IDX_UA_STATE_3,
- ESP32_S3_REG_IDX_Q0, ESP32_S3_REG_IDX_Q1, ESP32_S3_REG_IDX_Q2, ESP32_S3_REG_IDX_Q3,
- ESP32_S3_REG_IDX_Q4, ESP32_S3_REG_IDX_Q5, ESP32_S3_REG_IDX_Q6, ESP32_S3_REG_IDX_Q7,
-
- XT_REG_IDX_MMID, XT_REG_IDX_IBREAKENABLE,
- XT_REG_IDX_MEMCTL, XT_REG_IDX_ATOMCTL, XT_REG_IDX_OCD_DDR,
- XT_REG_IDX_IBREAKA0, XT_REG_IDX_IBREAKA1, XT_REG_IDX_DBREAKA0, XT_REG_IDX_DBREAKA1,
- XT_REG_IDX_DBREAKC0, XT_REG_IDX_DBREAKC1,
- XT_REG_IDX_EPC1, XT_REG_IDX_EPC2, XT_REG_IDX_EPC3, XT_REG_IDX_EPC4,
- XT_REG_IDX_EPC5, XT_REG_IDX_EPC6, XT_REG_IDX_EPC7, XT_REG_IDX_DEPC,
- XT_REG_IDX_EPS2, XT_REG_IDX_EPS3, XT_REG_IDX_EPS4, XT_REG_IDX_EPS5,
- XT_REG_IDX_EPS6, XT_REG_IDX_EPS7,
- XT_REG_IDX_EXCSAVE1, XT_REG_IDX_EXCSAVE2, XT_REG_IDX_EXCSAVE3, XT_REG_IDX_EXCSAVE4,
- XT_REG_IDX_EXCSAVE5, XT_REG_IDX_EXCSAVE6, XT_REG_IDX_EXCSAVE7, XT_REG_IDX_CPENABLE,
- XT_REG_IDX_INTERRUPT, XT_REG_IDX_INTSET, XT_REG_IDX_INTCLEAR, XT_REG_IDX_INTENABLE,
- XT_REG_IDX_VECBASE, XT_REG_IDX_EXCCAUSE, XT_REG_IDX_DEBUGCAUSE, XT_REG_IDX_CCOUNT,
- XT_REG_IDX_PRID, XT_REG_IDX_ICOUNT, XT_REG_IDX_ICOUNTLEVEL, XT_REG_IDX_EXCVADDR,
- XT_REG_IDX_CCOMPARE0, XT_REG_IDX_CCOMPARE1, XT_REG_IDX_CCOMPARE2,
- XT_REG_IDX_MISC0, XT_REG_IDX_MISC1, XT_REG_IDX_MISC2, XT_REG_IDX_MISC3,
-
- XT_REG_IDX_PWRCTL, XT_REG_IDX_PWRSTAT, XT_REG_IDX_ERISTAT,
- XT_REG_IDX_CS_ITCTRL, XT_REG_IDX_CS_CLAIMSET, XT_REG_IDX_CS_CLAIMCLR,
- XT_REG_IDX_CS_LOCKACCESS, XT_REG_IDX_CS_LOCKSTATUS, XT_REG_IDX_CS_AUTHSTATUS,
- XT_REG_IDX_FAULT_INFO,
- XT_REG_IDX_TRAX_ID, XT_REG_IDX_TRAX_CTRL, XT_REG_IDX_TRAX_STAT,
- XT_REG_IDX_TRAX_DATA, XT_REG_IDX_TRAX_ADDR, XT_REG_IDX_TRAX_PCTRIGGER,
- XT_REG_IDX_TRAX_PCMATCH, XT_REG_IDX_TRAX_DELAY, XT_REG_IDX_TRAX_MEMSTART,
- XT_REG_IDX_TRAX_MEMEND,
- XT_REG_IDX_PMG, XT_REG_IDX_PMPC, XT_REG_IDX_PM0, XT_REG_IDX_PM1,
- XT_REG_IDX_PMCTRL0, XT_REG_IDX_PMCTRL1, XT_REG_IDX_PMSTAT0, XT_REG_IDX_PMSTAT1,
- XT_REG_IDX_OCD_ID, XT_REG_IDX_OCD_DCRCLR, XT_REG_IDX_OCD_DCRSET, XT_REG_IDX_OCD_DSR,
- XT_REG_IDX_A0, XT_REG_IDX_A1, XT_REG_IDX_A2, XT_REG_IDX_A3,
- XT_REG_IDX_A4, XT_REG_IDX_A5, XT_REG_IDX_A6, XT_REG_IDX_A7,
- XT_REG_IDX_A8, XT_REG_IDX_A9, XT_REG_IDX_A10, XT_REG_IDX_A11,
- XT_REG_IDX_A12, XT_REG_IDX_A13, XT_REG_IDX_A14, XT_REG_IDX_A15,
-};
-
-/* actually this table contains user + TIE registers
- * TODO: for TIE registers we need to specify custom access functions instead of `xtensa_user_reg_xxx_type`*/
-static const struct xtensa_user_reg_desc esp32s3_user_regs[ESP32_S3_NUM_REGS - XT_NUM_REGS] = {
- { "gpio_out", 0x00, 0, 32, &xtensa_user_reg_u32_type },
- { "accx_0", 0x01, 0, 32, &xtensa_user_reg_u32_type },
- { "accx_1", 0x02, 0, 32, &xtensa_user_reg_u32_type },
- { "qacc_h_0", 0x03, 0, 32, &xtensa_user_reg_u32_type },
- { "qacc_h_1", 0x04, 0, 32, &xtensa_user_reg_u32_type },
- { "qacc_h_2", 0x05, 0, 32, &xtensa_user_reg_u32_type },
- { "qacc_h_3", 0x06, 0, 32, &xtensa_user_reg_u32_type },
- { "qacc_h_4", 0x07, 0, 32, &xtensa_user_reg_u32_type },
- { "qacc_l_0", 0x08, 0, 32, &xtensa_user_reg_u32_type },
- { "qacc_l_1", 0x09, 0, 32, &xtensa_user_reg_u32_type },
- { "qacc_l_2", 0x0A, 0, 32, &xtensa_user_reg_u32_type },
- { "qacc_l_3", 0x0B, 0, 32, &xtensa_user_reg_u32_type },
- { "qacc_l_4", 0x0C, 0, 32, &xtensa_user_reg_u32_type },
- { "sar_byte", 0x0D, 0, 32, &xtensa_user_reg_u32_type },
- { "fft_bit_width", 0x0E, 0, 32, &xtensa_user_reg_u32_type },
- { "ua_state_0", 0x0F, 0, 32, &xtensa_user_reg_u32_type },
- { "ua_state_1", 0x10, 0, 32, &xtensa_user_reg_u32_type },
- { "ua_state_2", 0x11, 0, 32, &xtensa_user_reg_u32_type },
- { "ua_state_3", 0x12, 0, 32, &xtensa_user_reg_u32_type },
- { "q0", 0x13, 0, 128, &xtensa_user_reg_u128_type },
- { "q1", 0x14, 0, 128, &xtensa_user_reg_u128_type },
- { "q2", 0x15, 0, 128, &xtensa_user_reg_u128_type },
- { "q3", 0x16, 0, 128, &xtensa_user_reg_u128_type },
- { "q4", 0x17, 0, 128, &xtensa_user_reg_u128_type },
- { "q5", 0x18, 0, 128, &xtensa_user_reg_u128_type },
- { "q6", 0x19, 0, 128, &xtensa_user_reg_u128_type },
- { "q7", 0x20, 0, 128, &xtensa_user_reg_u128_type },
-};
-
struct esp32s3_common {
struct esp_xtensa_smp_common esp_xtensa_smp;
};
-static int esp32s3_fetch_user_regs(struct target *target);
-static int esp32s3_queue_write_dirty_user_regs(struct target *target);
-
-static const struct xtensa_config esp32s3_xtensa_cfg = {
- .density = true,
- .aregs_num = XT_AREGS_NUM_MAX,
- .windowed = true,
- .coproc = true,
- .fp_coproc = true,
- .loop = true,
- .miscregs_num = 4,
- .threadptr = true,
- .boolean = true,
- .reloc_vec = true,
- .proc_id = true,
- .cond_store = true,
- .mac16 = true,
- .user_regs_num = ARRAY_SIZE(esp32s3_user_regs),
- .user_regs = esp32s3_user_regs,
- .fetch_user_regs = esp32s3_fetch_user_regs,
- .queue_write_dirty_user_regs = esp32s3_queue_write_dirty_user_regs,
- .gdb_general_regs_num = ESP32_S3_NUM_REGS_G_COMMAND,
- .gdb_regs_mapping = esp32s3_gdb_regs_mapping,
- .irom = {
- .count = 2,
- .regions = {
- {
- .base = ESP32_S3_IROM_LOW,
- .size = ESP32_S3_IROM_HIGH - ESP32_S3_IROM_LOW,
- .access = XT_MEM_ACCESS_READ,
- },
- {
- .base = ESP32_S3_IROM_MASK_LOW,
- .size = ESP32_S3_IROM_MASK_HIGH - ESP32_S3_IROM_MASK_LOW,
- .access = XT_MEM_ACCESS_READ,
- }
- }
- },
- .iram = {
- .count = 2,
- .regions = {
- {
- .base = ESP32_S3_IRAM_LOW,
- .size = ESP32_S3_IRAM_HIGH - ESP32_S3_IRAM_LOW,
- .access = XT_MEM_ACCESS_READ | XT_MEM_ACCESS_WRITE,
- },
- {
- .base = ESP32_S3_RTC_IRAM_LOW,
- .size = ESP32_S3_RTC_IRAM_HIGH - ESP32_S3_RTC_IRAM_LOW,
- .access = XT_MEM_ACCESS_READ | XT_MEM_ACCESS_WRITE,
- },
- }
- },
- .drom = {
- .count = 1,
- .regions = {
- {
- .base = ESP32_S3_DROM_LOW,
- .size = ESP32_S3_DROM_HIGH - ESP32_S3_DROM_LOW,
- .access = XT_MEM_ACCESS_READ,
- },
- }
- },
- .dram = {
- .count = 4,
- .regions = {
- {
- .base = ESP32_S3_DRAM_LOW,
- .size = ESP32_S3_DRAM_HIGH - ESP32_S3_DRAM_LOW,
- .access = XT_MEM_ACCESS_READ | XT_MEM_ACCESS_WRITE,
- },
- {
- .base = ESP32_S3_RTC_DRAM_LOW,
- .size = ESP32_S3_RTC_DRAM_HIGH - ESP32_S3_RTC_DRAM_LOW,
- .access = XT_MEM_ACCESS_READ | XT_MEM_ACCESS_WRITE,
- },
- {
- .base = ESP32_S3_RTC_DATA_LOW,
- .size = ESP32_S3_RTC_DATA_HIGH - ESP32_S3_RTC_DATA_LOW,
- .access = XT_MEM_ACCESS_READ | XT_MEM_ACCESS_WRITE,
- },
- {
- .base = ESP32_S3_SYS_RAM_LOW,
- .size = ESP32_S3_SYS_RAM_HIGH - ESP32_S3_SYS_RAM_LOW,
- .access = XT_MEM_ACCESS_READ | XT_MEM_ACCESS_WRITE,
- },
- }
- },
- .exc = {
- .enabled = true,
- },
- .irq = {
- .enabled = true,
- .irq_num = 32,
- },
- .high_irq = {
- .enabled = true,
- .excm_level = 3,
- .nmi_num = 1,
- },
- .tim_irq = {
- .enabled = true,
- .comp_num = 3,
- },
- .debug = {
- .enabled = true,
- .irq_level = 6,
- .ibreaks_num = 2,
- .dbreaks_num = 2,
- .icount_sz = 32,
- },
- .trace = {
- .enabled = true,
- .mem_sz = ESP32_S3_TRACEMEM_BLOCK_SZ,
- },
-};
-
-static int esp32s3_fetch_user_regs(struct target *target)
-{
- LOG_DEBUG("%s: user regs fetching is not implemented!", target_name(target));
- return ERROR_OK;
-}
-
-static int esp32s3_queue_write_dirty_user_regs(struct target *target)
-{
- LOG_DEBUG("%s: user regs writing is not implemented!", target_name(target));
- return ERROR_OK;
-}
-
/* Reset ESP32-S3's peripherals.
* 1. OpenOCD makes sure the target is halted; if not, tries to halt it.
* If that fails, tries to reset it (via OCD) and then halt.
@@ -537,7 +300,6 @@ static int esp32s3_virt2phys(struct target *target,
return ERROR_FAIL;
}
-
static int esp32s3_target_init(struct command_context *cmd_ctx, struct target *target)
{
return esp_xtensa_target_init(cmd_ctx, target);
@@ -577,7 +339,6 @@ static int esp32s3_target_create(struct target *target, Jim_Interp *interp)
int ret = esp_xtensa_smp_init_arch_info(target,
&esp32s3->esp_xtensa_smp,
- &esp32s3_xtensa_cfg,
&esp32s3_dm_cfg,
&esp32s3_chip_ops);
if (ret != ERROR_OK) {
diff --git a/src/target/espressif/esp32s3.h b/src/target/espressif/esp32s3.h
deleted file mode 100644
index a7d57ec..0000000
--- a/src/target/espressif/esp32s3.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-/***************************************************************************
- * ESP32-S3 target for OpenOCD *
- * Copyright (C) 2020 Espressif Systems Ltd. *
- ***************************************************************************/
-
-#ifndef OPENOCD_TARGET_ESP32S3_H
-#define OPENOCD_TARGET_ESP32S3_H
-
-#include <target/xtensa/xtensa_regs.h>
-
-#define ESP32_S3_DROM_LOW 0x3C000000
-#define ESP32_S3_DROM_HIGH 0x3D000000
-#define ESP32_S3_IROM_LOW 0x42000000
-#define ESP32_S3_IROM_HIGH 0x44000000
-
-/*Number of registers returned directly by the G command
- *Corresponds to the amount of regs listed in regformats/reg-xtensa.dat in the gdb source */
-#define ESP32_S3_NUM_REGS_G_COMMAND 128
-
-enum esp32s3_reg_id {
- /* chip specific registers that extend ISA go after ISA-defined ones */
- ESP32_S3_REG_IDX_GPIOOUT = XT_NUM_REGS,
- ESP32_S3_REG_IDX_ACCX_0,
- ESP32_S3_REG_IDX_ACCX_1,
- ESP32_S3_REG_IDX_QACC_H_0,
- ESP32_S3_REG_IDX_QACC_H_1,
- ESP32_S3_REG_IDX_QACC_H_2,
- ESP32_S3_REG_IDX_QACC_H_3,
- ESP32_S3_REG_IDX_QACC_H_4,
- ESP32_S3_REG_IDX_QACC_L_0,
- ESP32_S3_REG_IDX_QACC_L_1,
- ESP32_S3_REG_IDX_QACC_L_2,
- ESP32_S3_REG_IDX_QACC_L_3,
- ESP32_S3_REG_IDX_QACC_L_4,
- ESP32_S3_REG_IDX_SAR_BYTE,
- ESP32_S3_REG_IDX_FFT_BIT_WIDTH,
- ESP32_S3_REG_IDX_UA_STATE_0,
- ESP32_S3_REG_IDX_UA_STATE_1,
- ESP32_S3_REG_IDX_UA_STATE_2,
- ESP32_S3_REG_IDX_UA_STATE_3,
- ESP32_S3_REG_IDX_Q0,
- ESP32_S3_REG_IDX_Q1,
- ESP32_S3_REG_IDX_Q2,
- ESP32_S3_REG_IDX_Q3,
- ESP32_S3_REG_IDX_Q4,
- ESP32_S3_REG_IDX_Q5,
- ESP32_S3_REG_IDX_Q6,
- ESP32_S3_REG_IDX_Q7,
- ESP32_S3_NUM_REGS,
-};
-
-#endif /* OPENOCD_TARGET_ESP32S3_H */
diff --git a/src/target/espressif/esp_xtensa.c b/src/target/espressif/esp_xtensa.c
index ce16012..fcd42ea 100644
--- a/src/target/espressif/esp_xtensa.c
+++ b/src/target/espressif/esp_xtensa.c
@@ -17,10 +17,9 @@
int esp_xtensa_init_arch_info(struct target *target,
struct esp_xtensa_common *esp_xtensa,
- const struct xtensa_config *xtensa_cfg,
struct xtensa_debug_module_config *dm_cfg)
{
- return xtensa_init_arch_info(target, &esp_xtensa->xtensa, xtensa_cfg, dm_cfg);
+ return xtensa_init_arch_info(target, &esp_xtensa->xtensa, dm_cfg);
}
int esp_xtensa_target_init(struct command_context *cmd_ctx, struct target *target)
diff --git a/src/target/espressif/esp_xtensa.h b/src/target/espressif/esp_xtensa.h
index 4bbbd75..61e87c0 100644
--- a/src/target/espressif/esp_xtensa.h
+++ b/src/target/espressif/esp_xtensa.h
@@ -23,7 +23,6 @@ static inline struct esp_xtensa_common *target_to_esp_xtensa(struct target *targ
int esp_xtensa_init_arch_info(struct target *target,
struct esp_xtensa_common *esp_xtensa,
- const struct xtensa_config *xtensa_cfg,
struct xtensa_debug_module_config *dm_cfg);
int esp_xtensa_target_init(struct command_context *cmd_ctx, struct target *target);
void esp_xtensa_target_deinit(struct target *target);
diff --git a/src/target/espressif/esp_xtensa_smp.c b/src/target/espressif/esp_xtensa_smp.c
index 6060662..b109f3c 100644
--- a/src/target/espressif/esp_xtensa_smp.c
+++ b/src/target/espressif/esp_xtensa_smp.c
@@ -450,11 +450,10 @@ int esp_xtensa_smp_watchpoint_remove(struct target *target, struct watchpoint *w
int esp_xtensa_smp_init_arch_info(struct target *target,
struct esp_xtensa_smp_common *esp_xtensa_smp,
- const struct xtensa_config *xtensa_cfg,
struct xtensa_debug_module_config *dm_cfg,
const struct esp_xtensa_smp_chip_ops *chip_ops)
{
- int ret = esp_xtensa_init_arch_info(target, &esp_xtensa_smp->esp_xtensa, xtensa_cfg, dm_cfg);
+ int ret = esp_xtensa_init_arch_info(target, &esp_xtensa_smp->esp_xtensa, dm_cfg);
if (ret != ERROR_OK)
return ret;
esp_xtensa_smp->chip_ops = chip_ops;
@@ -467,6 +466,139 @@ int esp_xtensa_smp_target_init(struct command_context *cmd_ctx, struct target *t
return esp_xtensa_target_init(cmd_ctx, target);
}
+COMMAND_HANDLER(esp_xtensa_smp_cmd_xtdef)
+{
+ struct target *target = get_current_target(CMD_CTX);
+ if (target->smp && CMD_ARGC > 0) {
+ struct target_list *head;
+ struct target *curr;
+ foreach_smp_target(head, target->smp_targets) {
+ curr = head->target;
+ int ret = CALL_COMMAND_HANDLER(xtensa_cmd_xtdef_do,
+ target_to_xtensa(curr));
+ if (ret != ERROR_OK)
+ return ret;
+ }
+ return ERROR_OK;
+ }
+ return CALL_COMMAND_HANDLER(xtensa_cmd_xtdef_do,
+ target_to_xtensa(target));
+}
+
+COMMAND_HANDLER(esp_xtensa_smp_cmd_xtopt)
+{
+ struct target *target = get_current_target(CMD_CTX);
+ if (target->smp && CMD_ARGC > 0) {
+ struct target_list *head;
+ struct target *curr;
+ foreach_smp_target(head, target->smp_targets) {
+ curr = head->target;
+ int ret = CALL_COMMAND_HANDLER(xtensa_cmd_xtopt_do,
+ target_to_xtensa(curr));
+ if (ret != ERROR_OK)
+ return ret;
+ }
+ return ERROR_OK;
+ }
+ return CALL_COMMAND_HANDLER(xtensa_cmd_xtopt_do,
+ target_to_xtensa(target));
+}
+
+COMMAND_HANDLER(esp_xtensa_smp_cmd_xtmem)
+{
+ struct target *target = get_current_target(CMD_CTX);
+ if (target->smp && CMD_ARGC > 0) {
+ struct target_list *head;
+ struct target *curr;
+ foreach_smp_target(head, target->smp_targets) {
+ curr = head->target;
+ int ret = CALL_COMMAND_HANDLER(xtensa_cmd_xtmem_do,
+ target_to_xtensa(curr));
+ if (ret != ERROR_OK)
+ return ret;
+ }
+ return ERROR_OK;
+ }
+ return CALL_COMMAND_HANDLER(xtensa_cmd_xtmem_do,
+ target_to_xtensa(target));
+}
+
+COMMAND_HANDLER(esp_xtensa_smp_cmd_xtmpu)
+{
+ struct target *target = get_current_target(CMD_CTX);
+ if (target->smp && CMD_ARGC > 0) {
+ struct target_list *head;
+ struct target *curr;
+ foreach_smp_target(head, target->smp_targets) {
+ curr = head->target;
+ int ret = CALL_COMMAND_HANDLER(xtensa_cmd_xtmpu_do,
+ target_to_xtensa(curr));
+ if (ret != ERROR_OK)
+ return ret;
+ }
+ return ERROR_OK;
+ }
+ return CALL_COMMAND_HANDLER(xtensa_cmd_xtmpu_do,
+ target_to_xtensa(target));
+}
+
+COMMAND_HANDLER(esp_xtensa_smp_cmd_xtmmu)
+{
+ struct target *target = get_current_target(CMD_CTX);
+ if (target->smp && CMD_ARGC > 0) {
+ struct target_list *head;
+ struct target *curr;
+ foreach_smp_target(head, target->smp_targets) {
+ curr = head->target;
+ int ret = CALL_COMMAND_HANDLER(xtensa_cmd_xtmmu_do,
+ target_to_xtensa(curr));
+ if (ret != ERROR_OK)
+ return ret;
+ }
+ return ERROR_OK;
+ }
+ return CALL_COMMAND_HANDLER(xtensa_cmd_xtmmu_do,
+ target_to_xtensa(target));
+}
+
+COMMAND_HANDLER(esp_xtensa_smp_cmd_xtreg)
+{
+ struct target *target = get_current_target(CMD_CTX);
+ if (target->smp && CMD_ARGC > 0) {
+ struct target_list *head;
+ struct target *curr;
+ foreach_smp_target(head, target->smp_targets) {
+ curr = head->target;
+ int ret = CALL_COMMAND_HANDLER(xtensa_cmd_xtreg_do,
+ target_to_xtensa(curr));
+ if (ret != ERROR_OK)
+ return ret;
+ }
+ return ERROR_OK;
+ }
+ return CALL_COMMAND_HANDLER(xtensa_cmd_xtreg_do,
+ target_to_xtensa(target));
+}
+
+COMMAND_HANDLER(esp_xtensa_smp_cmd_xtregfmt)
+{
+ struct target *target = get_current_target(CMD_CTX);
+ if (target->smp && CMD_ARGC > 0) {
+ struct target_list *head;
+ struct target *curr;
+ foreach_smp_target(head, target->smp_targets) {
+ curr = head->target;
+ int ret = CALL_COMMAND_HANDLER(xtensa_cmd_xtregfmt_do,
+ target_to_xtensa(curr));
+ if (ret != ERROR_OK)
+ return ret;
+ }
+ return ERROR_OK;
+ }
+ return CALL_COMMAND_HANDLER(xtensa_cmd_xtregfmt_do,
+ target_to_xtensa(target));
+}
+
COMMAND_HANDLER(esp_xtensa_smp_cmd_permissive_mode)
{
struct target *target = get_current_target(CMD_CTX);
@@ -633,6 +765,62 @@ COMMAND_HANDLER(esp_xtensa_smp_cmd_tracedump)
const struct command_registration esp_xtensa_smp_xtensa_command_handlers[] = {
{
+ .name = "xtdef",
+ .handler = esp_xtensa_smp_cmd_xtdef,
+ .mode = COMMAND_CONFIG,
+ .help = "Configure Xtensa core type",
+ .usage = "<type>",
+ },
+ {
+ .name = "xtopt",
+ .handler = esp_xtensa_smp_cmd_xtopt,
+ .mode = COMMAND_CONFIG,
+ .help = "Configure Xtensa core option",
+ .usage = "<name> <value>",
+ },
+ {
+ .name = "xtmem",
+ .handler = esp_xtensa_smp_cmd_xtmem,
+ .mode = COMMAND_CONFIG,
+ .help = "Configure Xtensa memory/cache option",
+ .usage = "<type> [parameters]",
+ },
+ {
+ .name = "xtmmu",
+ .handler = esp_xtensa_smp_cmd_xtmmu,
+ .mode = COMMAND_CONFIG,
+ .help = "Configure Xtensa MMU option",
+ .usage = "<NIREFILLENTRIES> <NDREFILLENTRIES> <IVARWAY56> <DVARWAY56>",
+ },
+ {
+ .name = "xtmpu",
+ .handler = esp_xtensa_smp_cmd_xtmpu,
+ .mode = COMMAND_CONFIG,
+ .help = "Configure Xtensa MPU option",
+ .usage = "<num FG seg> <min seg size> <lockable> <executeonly>",
+ },
+ {
+ .name = "xtreg",
+ .handler = esp_xtensa_smp_cmd_xtreg,
+ .mode = COMMAND_CONFIG,
+ .help = "Configure Xtensa register",
+ .usage = "<regname> <regnum>",
+ },
+ {
+ .name = "xtregs",
+ .handler = esp_xtensa_smp_cmd_xtreg,
+ .mode = COMMAND_CONFIG,
+ .help = "Configure number of Xtensa registers",
+ .usage = "<numregs>",
+ },
+ {
+ .name = "xtregfmt",
+ .handler = esp_xtensa_smp_cmd_xtregfmt,
+ .mode = COMMAND_CONFIG,
+ .help = "Configure format of Xtensa register map",
+ .usage = "<numgregs>",
+ },
+ {
.name = "set_permissive",
.handler = esp_xtensa_smp_cmd_permissive_mode,
.mode = COMMAND_ANY,
diff --git a/src/target/espressif/esp_xtensa_smp.h b/src/target/espressif/esp_xtensa_smp.h
index 159125d..bafd420 100644
--- a/src/target/espressif/esp_xtensa_smp.h
+++ b/src/target/espressif/esp_xtensa_smp.h
@@ -43,7 +43,6 @@ int esp_xtensa_smp_handle_target_event(struct target *target, enum target_event
int esp_xtensa_smp_target_init(struct command_context *cmd_ctx, struct target *target);
int esp_xtensa_smp_init_arch_info(struct target *target,
struct esp_xtensa_smp_common *esp_xtensa_smp,
- const struct xtensa_config *xtensa_cfg,
struct xtensa_debug_module_config *dm_cfg,
const struct esp_xtensa_smp_chip_ops *chip_ops);
diff --git a/src/target/target.c b/src/target/target.c
index 10a25ef..9b07dbf 100644
--- a/src/target/target.c
+++ b/src/target/target.c
@@ -77,6 +77,7 @@ extern struct target_type fa526_target;
extern struct target_type feroceon_target;
extern struct target_type dragonite_target;
extern struct target_type xscale_target;
+extern struct target_type xtensa_chip_target;
extern struct target_type cortexm_target;
extern struct target_type cortexa_target;
extern struct target_type aarch64_target;
@@ -118,6 +119,7 @@ static struct target_type *target_types[] = {
&feroceon_target,
&dragonite_target,
&xscale_target,
+ &xtensa_chip_target,
&cortexm_target,
&cortexa_target,
&cortexr4_target,
diff --git a/src/target/xtensa/Makefile.am b/src/target/xtensa/Makefile.am
index a11e585..94c7c4a 100644
--- a/src/target/xtensa/Makefile.am
+++ b/src/target/xtensa/Makefile.am
@@ -4,6 +4,8 @@ noinst_LTLIBRARIES += %D%/libxtensa.la
%C%_libxtensa_la_SOURCES = \
%D%/xtensa.c \
%D%/xtensa.h \
+ %D%/xtensa_chip.c \
+ %D%/xtensa_chip.h \
%D%/xtensa_debug_module.c \
%D%/xtensa_debug_module.h \
%D%/xtensa_regs.h
diff --git a/src/target/xtensa/xtensa.c b/src/target/xtensa/xtensa.c
index 6f9d77e..fe0f438 100644
--- a/src/target/xtensa/xtensa.c
+++ b/src/target/xtensa/xtensa.c
@@ -2,6 +2,7 @@
/***************************************************************************
* Generic Xtensa target API for OpenOCD *
+ * Copyright (C) 2020-2022 Cadence Design Systems, Inc. *
* Copyright (C) 2016-2019 Espressif Systems Ltd. *
* Derived from esp108.c *
* Author: Angus Gratton gus@projectgus.com *
@@ -16,325 +17,270 @@
#include <helper/align.h>
#include <target/register.h>
+#include "xtensa_chip.h"
#include "xtensa.h"
-
-#define _XT_INS_FORMAT_RSR(OPCODE, SR, T) ((OPCODE) \
- | (((SR) & 0xFF) << 8) \
+/* Swap 4-bit Xtensa opcodes and fields */
+#define XT_NIBSWAP8(V) \
+ ((((V) & 0x0F) << 4) \
+ | (((V) & 0xF0) >> 4))
+
+#define XT_NIBSWAP16(V) \
+ ((((V) & 0x000F) << 12) \
+ | (((V) & 0x00F0) << 4) \
+ | (((V) & 0x0F00) >> 4) \
+ | (((V) & 0xF000) >> 12))
+
+#define XT_NIBSWAP24(V) \
+ ((((V) & 0x00000F) << 20) \
+ | (((V) & 0x0000F0) << 12) \
+ | (((V) & 0x000F00) << 4) \
+ | (((V) & 0x00F000) >> 4) \
+ | (((V) & 0x0F0000) >> 12) \
+ | (((V) & 0xF00000) >> 20))
+
+/* _XT_INS_FORMAT_*()
+ * Instruction formatting converted from little-endian inputs
+ * and shifted to the MSB-side of DIR for BE systems.
+ */
+#define _XT_INS_FORMAT_RSR(X, OPCODE, SR, T) \
+ (XT_ISBE(X) ? (XT_NIBSWAP24(OPCODE) \
+ | (((T) & 0x0F) << 16) \
+ | (((SR) & 0xFF) << 8)) << 8 \
+ : (OPCODE) \
+ | (((SR) & 0xFF) << 8) \
| (((T) & 0x0F) << 4))
-#define _XT_INS_FORMAT_RRR(OPCODE, ST, R) ((OPCODE) \
- | (((ST) & 0xFF) << 4) \
+#define _XT_INS_FORMAT_RRR(X, OPCODE, ST, R) \
+ (XT_ISBE(X) ? (XT_NIBSWAP24(OPCODE) \
+ | ((XT_NIBSWAP8((ST) & 0xFF)) << 12) \
+ | (((R) & 0x0F) << 8)) << 8 \
+ : (OPCODE) \
+ | (((ST) & 0xFF) << 4) \
| (((R) & 0x0F) << 12))
-#define _XT_INS_FORMAT_RRRN(OPCODE, S, T, IMM4) ((OPCODE) \
- | (((T) & 0x0F) << 4) \
- | (((S) & 0x0F) << 8) \
+#define _XT_INS_FORMAT_RRRN(X, OPCODE, S, T, IMM4) \
+ (XT_ISBE(X) ? (XT_NIBSWAP16(OPCODE) \
+ | (((T) & 0x0F) << 8) \
+ | (((S) & 0x0F) << 4) \
+ | ((IMM4) & 0x0F)) << 16 \
+ : (OPCODE) \
+ | (((T) & 0x0F) << 4) \
+ | (((S) & 0x0F) << 8) \
| (((IMM4) & 0x0F) << 12))
-#define _XT_INS_FORMAT_RRI8(OPCODE, R, S, T, IMM8) ((OPCODE) \
- | (((IMM8) & 0xFF) << 16) \
- | (((R) & 0x0F) << 12) \
- | (((S) & 0x0F) << 8) \
+#define _XT_INS_FORMAT_RRI8(X, OPCODE, R, S, T, IMM8) \
+ (XT_ISBE(X) ? (XT_NIBSWAP24(OPCODE) \
+ | (((T) & 0x0F) << 16) \
+ | (((S) & 0x0F) << 12) \
+ | (((R) & 0x0F) << 8) \
+ | ((IMM8) & 0xFF)) << 8 \
+ : (OPCODE) \
+ | (((IMM8) & 0xFF) << 16) \
+ | (((R) & 0x0F) << 12) \
+ | (((S) & 0x0F) << 8) \
| (((T) & 0x0F) << 4))
-#define _XT_INS_FORMAT_RRI4(OPCODE, IMM4, R, S, T) ((OPCODE) \
- | (((IMM4) & 0x0F) << 20) \
- | (((R) & 0x0F) << 12) \
- | (((S) & 0x0F) << 8) \
+#define _XT_INS_FORMAT_RRI4(X, OPCODE, IMM4, R, S, T) \
+ (XT_ISBE(X) ? (XT_NIBSWAP24(OPCODE) \
+ | (((T) & 0x0F) << 16) \
+ | (((S) & 0x0F) << 12) \
+ | (((R) & 0x0F) << 8)) << 8 \
+ | ((IMM4) & 0x0F) \
+ : (OPCODE) \
+ | (((IMM4) & 0x0F) << 20) \
+ | (((R) & 0x0F) << 12) \
+ | (((S) & 0x0F) << 8) \
| (((T) & 0x0F) << 4))
/* Xtensa processor instruction opcodes
- * "Return From Debug Operation" to Normal */
-#define XT_INS_RFDO 0xf1e000
+*/
+/* "Return From Debug Operation" to Normal */
+#define XT_INS_RFDO(X) (XT_ISBE(X) ? 0x000e1f << 8 : 0xf1e000)
/* "Return From Debug and Dispatch" - allow sw debugging stuff to take over */
-#define XT_INS_RFDD 0xf1e010
+#define XT_INS_RFDD(X) (XT_ISBE(X) ? 0x010e1f << 8 : 0xf1e010)
/* Load to DDR register, increase addr register */
-#define XT_INS_LDDR32P(S) (0x0070E0 | ((S) << 8))
+#define XT_INS_LDDR32P(X, S) (XT_ISBE(X) ? (0x0E0700 | ((S) << 12)) << 8 : (0x0070E0 | ((S) << 8)))
/* Store from DDR register, increase addr register */
-#define XT_INS_SDDR32P(S) (0x0070F0 | ((S) << 8))
-
-/* Load 32-bit Indirect from A(S) + 4 * IMM8 to A(T) */
-#define XT_INS_L32I(S, T, IMM8) _XT_INS_FORMAT_RRI8(0x002002, 0, S, T, IMM8)
-/* Load 16-bit Unsigned from A(S) + 2 * IMM8 to A(T) */
-#define XT_INS_L16UI(S, T, IMM8) _XT_INS_FORMAT_RRI8(0x001002, 0, S, T, IMM8)
-/* Load 8-bit Unsigned from A(S) + IMM8 to A(T) */
-#define XT_INS_L8UI(S, T, IMM8) _XT_INS_FORMAT_RRI8(0x000002, 0, S, T, IMM8)
-
-/* Store 32-bit Indirect to A(S) + 4 * IMM8 from A(T) */
-#define XT_INS_S32I(S, T, IMM8) _XT_INS_FORMAT_RRI8(0x006002, 0, S, T, IMM8)
-/* Store 16-bit to A(S) + 2 * IMM8 from A(T) */
-#define XT_INS_S16I(S, T, IMM8) _XT_INS_FORMAT_RRI8(0x005002, 0, S, T, IMM8)
-/* Store 8-bit to A(S) + IMM8 from A(T) */
-#define XT_INS_S8I(S, T, IMM8) _XT_INS_FORMAT_RRI8(0x004002, 0, S, T, IMM8)
+#define XT_INS_SDDR32P(X, S) (XT_ISBE(X) ? (0x0F0700 | ((S) << 12)) << 8 : (0x0070F0 | ((S) << 8)))
+
+/* Load 32-bit Indirect from A(S)+4*IMM8 to A(T) */
+#define XT_INS_L32I(X, S, T, IMM8) _XT_INS_FORMAT_RRI8(X, 0x002002, 0, S, T, IMM8)
+/* Load 16-bit Unsigned from A(S)+2*IMM8 to A(T) */
+#define XT_INS_L16UI(X, S, T, IMM8) _XT_INS_FORMAT_RRI8(X, 0x001002, 0, S, T, IMM8)
+/* Load 8-bit Unsigned from A(S)+IMM8 to A(T) */
+#define XT_INS_L8UI(X, S, T, IMM8) _XT_INS_FORMAT_RRI8(X, 0x000002, 0, S, T, IMM8)
+
+/* Store 32-bit Indirect to A(S)+4*IMM8 from A(T) */
+#define XT_INS_S32I(X, S, T, IMM8) _XT_INS_FORMAT_RRI8(X, 0x006002, 0, S, T, IMM8)
+/* Store 16-bit to A(S)+2*IMM8 from A(T) */
+#define XT_INS_S16I(X, S, T, IMM8) _XT_INS_FORMAT_RRI8(X, 0x005002, 0, S, T, IMM8)
+/* Store 8-bit to A(S)+IMM8 from A(T) */
+#define XT_INS_S8I(X, S, T, IMM8) _XT_INS_FORMAT_RRI8(X, 0x004002, 0, S, T, IMM8)
+
+/* Cache Instructions */
+#define XT_INS_IHI(X, S, IMM8) _XT_INS_FORMAT_RRI8(X, 0x0070E2, 0, S, 0, IMM8)
+#define XT_INS_DHWBI(X, S, IMM8) _XT_INS_FORMAT_RRI8(X, 0x007052, 0, S, 0, IMM8)
+#define XT_INS_DHWB(X, S, IMM8) _XT_INS_FORMAT_RRI8(X, 0x007042, 0, S, 0, IMM8)
+#define XT_INS_ISYNC(X) (XT_ISBE(X) ? 0x000200 << 8 : 0x002000)
+
+/* Control Instructions */
+#define XT_INS_JX(X, S) (XT_ISBE(X) ? (0x050000 | ((S) << 12)) : (0x0000a0 | ((S) << 8)))
+#define XT_INS_CALL0(X, IMM18) (XT_ISBE(X) ? (0x500000 | ((IMM18) & 0x3ffff)) : (0x000005 | (((IMM18) & 0x3ffff) << 6)))
/* Read Special Register */
-#define XT_INS_RSR(SR, T) _XT_INS_FORMAT_RSR(0x030000, SR, T)
+#define XT_INS_RSR(X, SR, T) _XT_INS_FORMAT_RSR(X, 0x030000, SR, T)
/* Write Special Register */
-#define XT_INS_WSR(SR, T) _XT_INS_FORMAT_RSR(0x130000, SR, T)
+#define XT_INS_WSR(X, SR, T) _XT_INS_FORMAT_RSR(X, 0x130000, SR, T)
/* Swap Special Register */
-#define XT_INS_XSR(SR, T) _XT_INS_FORMAT_RSR(0x610000, SR, T)
+#define XT_INS_XSR(X, SR, T) _XT_INS_FORMAT_RSR(X, 0x610000, SR, T)
/* Rotate Window by (-8..7) */
-#define XT_INS_ROTW(N) ((0x408000) | (((N) & 15) << 4))
+#define XT_INS_ROTW(X, N) (XT_ISBE(X) ? ((0x000804) | (((N) & 15) << 16)) << 8 : ((0x408000) | (((N) & 15) << 4)))
/* Read User Register */
-#define XT_INS_RUR(UR, T) _XT_INS_FORMAT_RRR(0xE30000, UR, T)
+#define XT_INS_RUR(X, UR, T) _XT_INS_FORMAT_RRR(X, 0xE30000, UR, T)
/* Write User Register */
-#define XT_INS_WUR(UR, T) _XT_INS_FORMAT_RSR(0xF30000, UR, T)
+#define XT_INS_WUR(X, UR, T) _XT_INS_FORMAT_RSR(X, 0xF30000, UR, T)
/* Read Floating-Point Register */
-#define XT_INS_RFR(FR, T) _XT_INS_FORMAT_RRR(0xFA0000, (((FR) << 4) | 0x4), T)
+#define XT_INS_RFR(X, FR, T) _XT_INS_FORMAT_RRR(X, 0xFA0000, ((FR << 4) | 0x4), T)
/* Write Floating-Point Register */
-#define XT_INS_WFR(FR, T) _XT_INS_FORMAT_RRR(0xFA0000, (((FR) << 4) | 0x5), T)
+#define XT_INS_WFR(X, FR, T) _XT_INS_FORMAT_RRR(X, 0xFA0000, ((T << 4) | 0x5), FR)
-/* 32-bit break */
-#define XT_INS_BREAK(IMM1, IMM2) _XT_INS_FORMAT_RRR(0x000000, \
- (((IMM1) & 0x0F) << 4) | ((IMM2) & 0x0F), 0x4)
-/* 16-bit break */
-#define XT_INS_BREAKN(IMM4) _XT_INS_FORMAT_RRRN(0x00000D, IMM4, 0x2, 0xF)
+#define XT_INS_L32E(X, R, S, T) _XT_INS_FORMAT_RRI4(X, 0x090000, 0, R, S, T)
+#define XT_INS_S32E(X, R, S, T) _XT_INS_FORMAT_RRI4(X, 0x490000, 0, R, S, T)
+#define XT_INS_L32E_S32E_MASK(X) (XT_ISBE(X) ? 0xF000FF << 8 : 0xFF000F)
-#define XT_INS_L32E(R, S, T) _XT_INS_FORMAT_RRI4(0x90000, 0, R, S, T)
-#define XT_INS_S32E(R, S, T) _XT_INS_FORMAT_RRI4(0x490000, 0, R, S, T)
-#define XT_INS_L32E_S32E_MASK 0xFF000F
-
-#define XT_INS_RFWO 0x3400
-#define XT_INS_RFWU 0x3500
-#define XT_INS_RFWO_RFWU_MASK 0xFFFFFF
+#define XT_INS_RFWO(X) (XT_ISBE(X) ? 0x004300 << 8 : 0x003400)
+#define XT_INS_RFWU(X) (XT_ISBE(X) ? 0x005300 << 8 : 0x003500)
+#define XT_INS_RFWO_RFWU_MASK(X) (XT_ISBE(X) ? 0xFFFFFF << 8 : 0xFFFFFF)
#define XT_WATCHPOINTS_NUM_MAX 2
-/* Special register number macro for DDR register.
-* this gets used a lot so making a shortcut to it is
-* useful.
-*/
-#define XT_SR_DDR (xtensa_regs[XT_REG_IDX_OCD_DDR].reg_num)
-
-/*Same thing for A3/A4 */
+/* Special register number macro for DDR, PS, WB, A3, A4 registers.
+ * These get used a lot so making a shortcut is useful.
+ */
+#define XT_SR_DDR (xtensa_regs[XT_REG_IDX_DDR].reg_num)
+#define XT_SR_PS (xtensa_regs[XT_REG_IDX_PS].reg_num)
+#define XT_SR_WB (xtensa_regs[XT_REG_IDX_WINDOWBASE].reg_num)
#define XT_REG_A3 (xtensa_regs[XT_REG_IDX_AR3].reg_num)
#define XT_REG_A4 (xtensa_regs[XT_REG_IDX_AR4].reg_num)
-#define XT_PC_REG_NUM_BASE (176)
-#define XT_SW_BREAKPOINTS_MAX_NUM 32
-
-const struct xtensa_reg_desc xtensa_regs[XT_NUM_REGS] = {
- { "pc", XT_PC_REG_NUM_BASE /*+XT_DEBUGLEVEL*/, XT_REG_SPECIAL, 0 }, /* actually epc[debuglevel] */
- { "ar0", 0x00, XT_REG_GENERAL, 0 },
- { "ar1", 0x01, XT_REG_GENERAL, 0 },
- { "ar2", 0x02, XT_REG_GENERAL, 0 },
- { "ar3", 0x03, XT_REG_GENERAL, 0 },
- { "ar4", 0x04, XT_REG_GENERAL, 0 },
- { "ar5", 0x05, XT_REG_GENERAL, 0 },
- { "ar6", 0x06, XT_REG_GENERAL, 0 },
- { "ar7", 0x07, XT_REG_GENERAL, 0 },
- { "ar8", 0x08, XT_REG_GENERAL, 0 },
- { "ar9", 0x09, XT_REG_GENERAL, 0 },
- { "ar10", 0x0A, XT_REG_GENERAL, 0 },
- { "ar11", 0x0B, XT_REG_GENERAL, 0 },
- { "ar12", 0x0C, XT_REG_GENERAL, 0 },
- { "ar13", 0x0D, XT_REG_GENERAL, 0 },
- { "ar14", 0x0E, XT_REG_GENERAL, 0 },
- { "ar15", 0x0F, XT_REG_GENERAL, 0 },
- { "ar16", 0x10, XT_REG_GENERAL, 0 },
- { "ar17", 0x11, XT_REG_GENERAL, 0 },
- { "ar18", 0x12, XT_REG_GENERAL, 0 },
- { "ar19", 0x13, XT_REG_GENERAL, 0 },
- { "ar20", 0x14, XT_REG_GENERAL, 0 },
- { "ar21", 0x15, XT_REG_GENERAL, 0 },
- { "ar22", 0x16, XT_REG_GENERAL, 0 },
- { "ar23", 0x17, XT_REG_GENERAL, 0 },
- { "ar24", 0x18, XT_REG_GENERAL, 0 },
- { "ar25", 0x19, XT_REG_GENERAL, 0 },
- { "ar26", 0x1A, XT_REG_GENERAL, 0 },
- { "ar27", 0x1B, XT_REG_GENERAL, 0 },
- { "ar28", 0x1C, XT_REG_GENERAL, 0 },
- { "ar29", 0x1D, XT_REG_GENERAL, 0 },
- { "ar30", 0x1E, XT_REG_GENERAL, 0 },
- { "ar31", 0x1F, XT_REG_GENERAL, 0 },
- { "ar32", 0x20, XT_REG_GENERAL, 0 },
- { "ar33", 0x21, XT_REG_GENERAL, 0 },
- { "ar34", 0x22, XT_REG_GENERAL, 0 },
- { "ar35", 0x23, XT_REG_GENERAL, 0 },
- { "ar36", 0x24, XT_REG_GENERAL, 0 },
- { "ar37", 0x25, XT_REG_GENERAL, 0 },
- { "ar38", 0x26, XT_REG_GENERAL, 0 },
- { "ar39", 0x27, XT_REG_GENERAL, 0 },
- { "ar40", 0x28, XT_REG_GENERAL, 0 },
- { "ar41", 0x29, XT_REG_GENERAL, 0 },
- { "ar42", 0x2A, XT_REG_GENERAL, 0 },
- { "ar43", 0x2B, XT_REG_GENERAL, 0 },
- { "ar44", 0x2C, XT_REG_GENERAL, 0 },
- { "ar45", 0x2D, XT_REG_GENERAL, 0 },
- { "ar46", 0x2E, XT_REG_GENERAL, 0 },
- { "ar47", 0x2F, XT_REG_GENERAL, 0 },
- { "ar48", 0x30, XT_REG_GENERAL, 0 },
- { "ar49", 0x31, XT_REG_GENERAL, 0 },
- { "ar50", 0x32, XT_REG_GENERAL, 0 },
- { "ar51", 0x33, XT_REG_GENERAL, 0 },
- { "ar52", 0x34, XT_REG_GENERAL, 0 },
- { "ar53", 0x35, XT_REG_GENERAL, 0 },
- { "ar54", 0x36, XT_REG_GENERAL, 0 },
- { "ar55", 0x37, XT_REG_GENERAL, 0 },
- { "ar56", 0x38, XT_REG_GENERAL, 0 },
- { "ar57", 0x39, XT_REG_GENERAL, 0 },
- { "ar58", 0x3A, XT_REG_GENERAL, 0 },
- { "ar59", 0x3B, XT_REG_GENERAL, 0 },
- { "ar60", 0x3C, XT_REG_GENERAL, 0 },
- { "ar61", 0x3D, XT_REG_GENERAL, 0 },
- { "ar62", 0x3E, XT_REG_GENERAL, 0 },
- { "ar63", 0x3F, XT_REG_GENERAL, 0 },
- { "lbeg", 0x00, XT_REG_SPECIAL, 0 },
- { "lend", 0x01, XT_REG_SPECIAL, 0 },
- { "lcount", 0x02, XT_REG_SPECIAL, 0 },
- { "sar", 0x03, XT_REG_SPECIAL, 0 },
- { "windowbase", 0x48, XT_REG_SPECIAL, 0 },
- { "windowstart", 0x49, XT_REG_SPECIAL, 0 },
- { "configid0", 0xB0, XT_REG_SPECIAL, 0 },
- { "configid1", 0xD0, XT_REG_SPECIAL, 0 },
- { "ps", 0xC6, XT_REG_SPECIAL, 0 }, /* actually EPS[debuglevel] */
- { "threadptr", 0xE7, XT_REG_USER, 0 },
- { "br", 0x04, XT_REG_SPECIAL, 0 },
- { "scompare1", 0x0C, XT_REG_SPECIAL, 0 },
- { "acclo", 0x10, XT_REG_SPECIAL, 0 },
- { "acchi", 0x11, XT_REG_SPECIAL, 0 },
- { "m0", 0x20, XT_REG_SPECIAL, 0 },
- { "m1", 0x21, XT_REG_SPECIAL, 0 },
- { "m2", 0x22, XT_REG_SPECIAL, 0 },
- { "m3", 0x23, XT_REG_SPECIAL, 0 },
- { "f0", 0x00, XT_REG_FR, XT_REGF_COPROC0 },
- { "f1", 0x01, XT_REG_FR, XT_REGF_COPROC0 },
- { "f2", 0x02, XT_REG_FR, XT_REGF_COPROC0 },
- { "f3", 0x03, XT_REG_FR, XT_REGF_COPROC0 },
- { "f4", 0x04, XT_REG_FR, XT_REGF_COPROC0 },
- { "f5", 0x05, XT_REG_FR, XT_REGF_COPROC0 },
- { "f6", 0x06, XT_REG_FR, XT_REGF_COPROC0 },
- { "f7", 0x07, XT_REG_FR, XT_REGF_COPROC0 },
- { "f8", 0x08, XT_REG_FR, XT_REGF_COPROC0 },
- { "f9", 0x09, XT_REG_FR, XT_REGF_COPROC0 },
- { "f10", 0x0A, XT_REG_FR, XT_REGF_COPROC0 },
- { "f11", 0x0B, XT_REG_FR, XT_REGF_COPROC0 },
- { "f12", 0x0C, XT_REG_FR, XT_REGF_COPROC0 },
- { "f13", 0x0D, XT_REG_FR, XT_REGF_COPROC0 },
- { "f14", 0x0E, XT_REG_FR, XT_REGF_COPROC0 },
- { "f15", 0x0F, XT_REG_FR, XT_REGF_COPROC0 },
- { "fcr", 0xE8, XT_REG_USER, XT_REGF_COPROC0 },
- { "fsr", 0xE9, XT_REG_USER, XT_REGF_COPROC0 },
- { "mmid", 0x59, XT_REG_SPECIAL, XT_REGF_NOREAD },
- { "ibreakenable", 0x60, XT_REG_SPECIAL, 0 },
- { "memctl", 0x61, XT_REG_SPECIAL, 0 },
- { "atomctl", 0x63, XT_REG_SPECIAL, 0 },
- { "ibreaka0", 0x80, XT_REG_SPECIAL, 0 },
- { "ibreaka1", 0x81, XT_REG_SPECIAL, 0 },
- { "dbreaka0", 0x90, XT_REG_SPECIAL, 0 },
- { "dbreaka1", 0x91, XT_REG_SPECIAL, 0 },
- { "dbreakc0", 0xA0, XT_REG_SPECIAL, 0 },
- { "dbreakc1", 0xA1, XT_REG_SPECIAL, 0 },
- { "epc1", 0xB1, XT_REG_SPECIAL, 0 },
- { "epc2", 0xB2, XT_REG_SPECIAL, 0 },
- { "epc3", 0xB3, XT_REG_SPECIAL, 0 },
- { "epc4", 0xB4, XT_REG_SPECIAL, 0 },
- { "epc5", 0xB5, XT_REG_SPECIAL, 0 },
- { "epc6", 0xB6, XT_REG_SPECIAL, 0 },
- { "epc7", 0xB7, XT_REG_SPECIAL, 0 },
- { "depc", 0xC0, XT_REG_SPECIAL, 0 },
- { "eps2", 0xC2, XT_REG_SPECIAL, 0 },
- { "eps3", 0xC3, XT_REG_SPECIAL, 0 },
- { "eps4", 0xC4, XT_REG_SPECIAL, 0 },
- { "eps5", 0xC5, XT_REG_SPECIAL, 0 },
- { "eps6", 0xC6, XT_REG_SPECIAL, 0 },
- { "eps7", 0xC7, XT_REG_SPECIAL, 0 },
- { "excsave1", 0xD1, XT_REG_SPECIAL, 0 },
- { "excsave2", 0xD2, XT_REG_SPECIAL, 0 },
- { "excsave3", 0xD3, XT_REG_SPECIAL, 0 },
- { "excsave4", 0xD4, XT_REG_SPECIAL, 0 },
- { "excsave5", 0xD5, XT_REG_SPECIAL, 0 },
- { "excsave6", 0xD6, XT_REG_SPECIAL, 0 },
- { "excsave7", 0xD7, XT_REG_SPECIAL, 0 },
- { "cpenable", 0xE0, XT_REG_SPECIAL, 0 },
- { "interrupt", 0xE2, XT_REG_SPECIAL, 0 },
- { "intset", 0xE2, XT_REG_SPECIAL, XT_REGF_NOREAD },
- { "intclear", 0xE3, XT_REG_SPECIAL, XT_REGF_NOREAD },
- { "intenable", 0xE4, XT_REG_SPECIAL, 0 },
- { "vecbase", 0xE7, XT_REG_SPECIAL, 0 },
- { "exccause", 0xE8, XT_REG_SPECIAL, 0 },
- { "debugcause", 0xE9, XT_REG_SPECIAL, 0 },
- { "ccount", 0xEA, XT_REG_SPECIAL, 0 },
- { "prid", 0xEB, XT_REG_SPECIAL, 0 },
- { "icount", 0xEC, XT_REG_SPECIAL, 0 },
- { "icountlevel", 0xED, XT_REG_SPECIAL, 0 },
- { "excvaddr", 0xEE, XT_REG_SPECIAL, 0 },
- { "ccompare0", 0xF0, XT_REG_SPECIAL, 0 },
- { "ccompare1", 0xF1, XT_REG_SPECIAL, 0 },
- { "ccompare2", 0xF2, XT_REG_SPECIAL, 0 },
- { "misc0", 0xF4, XT_REG_SPECIAL, 0 },
- { "misc1", 0xF5, XT_REG_SPECIAL, 0 },
- { "misc2", 0xF6, XT_REG_SPECIAL, 0 },
- { "misc3", 0xF7, XT_REG_SPECIAL, 0 },
- { "litbase", 0x05, XT_REG_SPECIAL, 0 },
- { "ptevaddr", 0x53, XT_REG_SPECIAL, 0 },
- { "rasid", 0x5A, XT_REG_SPECIAL, 0 },
- { "itlbcfg", 0x5B, XT_REG_SPECIAL, 0 },
- { "dtlbcfg", 0x5C, XT_REG_SPECIAL, 0 },
- { "mepc", 0x6A, XT_REG_SPECIAL, 0 },
- { "meps", 0x6B, XT_REG_SPECIAL, 0 },
- { "mesave", 0x6C, XT_REG_SPECIAL, 0 },
- { "mesr", 0x6D, XT_REG_SPECIAL, 0 },
- { "mecr", 0x6E, XT_REG_SPECIAL, 0 },
- { "mevaddr", 0x6F, XT_REG_SPECIAL, 0 },
- { "a0", XT_REG_IDX_AR0, XT_REG_RELGEN, 0 }, /* WARNING: For these registers, regnum points to the */
- { "a1", XT_REG_IDX_AR1, XT_REG_RELGEN, 0 }, /* index of the corresponding ARxregisters, NOT to */
- { "a2", XT_REG_IDX_AR2, XT_REG_RELGEN, 0 }, /* the processor register number! */
- { "a3", XT_REG_IDX_AR3, XT_REG_RELGEN, 0 },
- { "a4", XT_REG_IDX_AR4, XT_REG_RELGEN, 0 },
- { "a5", XT_REG_IDX_AR5, XT_REG_RELGEN, 0 },
- { "a6", XT_REG_IDX_AR6, XT_REG_RELGEN, 0 },
- { "a7", XT_REG_IDX_AR7, XT_REG_RELGEN, 0 },
- { "a8", XT_REG_IDX_AR8, XT_REG_RELGEN, 0 },
- { "a9", XT_REG_IDX_AR9, XT_REG_RELGEN, 0 },
- { "a10", XT_REG_IDX_AR10, XT_REG_RELGEN, 0 },
- { "a11", XT_REG_IDX_AR11, XT_REG_RELGEN, 0 },
- { "a12", XT_REG_IDX_AR12, XT_REG_RELGEN, 0 },
- { "a13", XT_REG_IDX_AR13, XT_REG_RELGEN, 0 },
- { "a14", XT_REG_IDX_AR14, XT_REG_RELGEN, 0 },
- { "a15", XT_REG_IDX_AR15, XT_REG_RELGEN, 0 },
-
- { "pwrctl", 0x68, XT_REG_DEBUG, XT_REGF_NOREAD },
- { "pwrstat", 0x68, XT_REG_DEBUG, XT_REGF_NOREAD },
- { "eristat", 0x68, XT_REG_DEBUG, XT_REGF_NOREAD },
- { "cs_itctrl", 0x68, XT_REG_DEBUG, XT_REGF_NOREAD },
- { "cs_claimset", 0x68, XT_REG_DEBUG, XT_REGF_NOREAD },
- { "cs_claimclr", 0x68, XT_REG_DEBUG, XT_REGF_NOREAD },
- { "cs_lockaccess", 0x68, XT_REG_DEBUG, XT_REGF_NOREAD },
- { "cs_lockstatus", 0x68, XT_REG_DEBUG, XT_REGF_NOREAD },
- { "cs_authstatus", 0x68, XT_REG_DEBUG, XT_REGF_NOREAD },
- { "fault_info", 0x68, XT_REG_DEBUG, XT_REGF_NOREAD },
- { "trax_id", 0x68, XT_REG_DEBUG, XT_REGF_NOREAD },
- { "trax_ctrl", 0x68, XT_REG_DEBUG, XT_REGF_NOREAD },
- { "trax_stat", 0x68, XT_REG_DEBUG, XT_REGF_NOREAD },
- { "trax_data", 0x68, XT_REG_DEBUG, XT_REGF_NOREAD },
- { "trax_addr", 0x68, XT_REG_DEBUG, XT_REGF_NOREAD },
- { "trax_pctrigger", 0x68, XT_REG_DEBUG, XT_REGF_NOREAD },
- { "trax_pcmatch", 0x68, XT_REG_DEBUG, XT_REGF_NOREAD },
- { "trax_delay", 0x68, XT_REG_DEBUG, XT_REGF_NOREAD },
- { "trax_memstart", 0x68, XT_REG_DEBUG, XT_REGF_NOREAD },
- { "trax_memend", 0x68, XT_REG_DEBUG, XT_REGF_NOREAD },
- { "pmg", 0x68, XT_REG_DEBUG, XT_REGF_NOREAD },
- { "pmoc", 0x68, XT_REG_DEBUG, XT_REGF_NOREAD },
- { "pm0", 0x68, XT_REG_DEBUG, XT_REGF_NOREAD },
- { "pm1", 0x68, XT_REG_DEBUG, XT_REGF_NOREAD },
- { "pmctrl0", 0x68, XT_REG_DEBUG, XT_REGF_NOREAD },
- { "pmctrl1", 0x68, XT_REG_DEBUG, XT_REGF_NOREAD },
- { "pmstat0", 0x68, XT_REG_DEBUG, XT_REGF_NOREAD },
- { "pmstat1", 0x68, XT_REG_DEBUG, XT_REGF_NOREAD },
- { "ocd_id", 0x68, XT_REG_DEBUG, XT_REGF_NOREAD },
- { "ocd_dcrclr", 0x68, XT_REG_DEBUG, XT_REGF_NOREAD },
- { "ocd_dcrset", 0x68, XT_REG_DEBUG, XT_REGF_NOREAD },
- { "ocd_dsr", 0x68, XT_REG_DEBUG, XT_REGF_NOREAD },
- { "ddr", 0x68, XT_REG_DEBUG, XT_REGF_NOREAD },
+#define XT_PS_REG_NUM_BASE (0xc0U) /* (EPS2 - 2), for adding DBGLEVEL */
+#define XT_PC_REG_NUM_BASE (0xb0U) /* (EPC1 - 1), for adding DBGLEVEL */
+#define XT_PC_REG_NUM_VIRTUAL (0xffU) /* Marker for computing PC (EPC[DBGLEVEL) */
+#define XT_PC_DBREG_NUM_BASE (0x20U) /* External (i.e., GDB) access */
+
+#define XT_SW_BREAKPOINTS_MAX_NUM 32
+#define XT_HW_IBREAK_MAX_NUM 2
+#define XT_HW_DBREAK_MAX_NUM 2
+
+struct xtensa_reg_desc xtensa_regs[XT_NUM_REGS] = {
+ XT_MK_REG_DESC("pc", XT_PC_REG_NUM_VIRTUAL, XT_REG_SPECIAL, 0),
+ XT_MK_REG_DESC("ar0", 0x00, XT_REG_GENERAL, 0),
+ XT_MK_REG_DESC("ar1", 0x01, XT_REG_GENERAL, 0),
+ XT_MK_REG_DESC("ar2", 0x02, XT_REG_GENERAL, 0),
+ XT_MK_REG_DESC("ar3", 0x03, XT_REG_GENERAL, 0),
+ XT_MK_REG_DESC("ar4", 0x04, XT_REG_GENERAL, 0),
+ XT_MK_REG_DESC("ar5", 0x05, XT_REG_GENERAL, 0),
+ XT_MK_REG_DESC("ar6", 0x06, XT_REG_GENERAL, 0),
+ XT_MK_REG_DESC("ar7", 0x07, XT_REG_GENERAL, 0),
+ XT_MK_REG_DESC("ar8", 0x08, XT_REG_GENERAL, 0),
+ XT_MK_REG_DESC("ar9", 0x09, XT_REG_GENERAL, 0),
+ XT_MK_REG_DESC("ar10", 0x0A, XT_REG_GENERAL, 0),
+ XT_MK_REG_DESC("ar11", 0x0B, XT_REG_GENERAL, 0),
+ XT_MK_REG_DESC("ar12", 0x0C, XT_REG_GENERAL, 0),
+ XT_MK_REG_DESC("ar13", 0x0D, XT_REG_GENERAL, 0),
+ XT_MK_REG_DESC("ar14", 0x0E, XT_REG_GENERAL, 0),
+ XT_MK_REG_DESC("ar15", 0x0F, XT_REG_GENERAL, 0),
+ XT_MK_REG_DESC("ar16", 0x10, XT_REG_GENERAL, 0),
+ XT_MK_REG_DESC("ar17", 0x11, XT_REG_GENERAL, 0),
+ XT_MK_REG_DESC("ar18", 0x12, XT_REG_GENERAL, 0),
+ XT_MK_REG_DESC("ar19", 0x13, XT_REG_GENERAL, 0),
+ XT_MK_REG_DESC("ar20", 0x14, XT_REG_GENERAL, 0),
+ XT_MK_REG_DESC("ar21", 0x15, XT_REG_GENERAL, 0),
+ XT_MK_REG_DESC("ar22", 0x16, XT_REG_GENERAL, 0),
+ XT_MK_REG_DESC("ar23", 0x17, XT_REG_GENERAL, 0),
+ XT_MK_REG_DESC("ar24", 0x18, XT_REG_GENERAL, 0),
+ XT_MK_REG_DESC("ar25", 0x19, XT_REG_GENERAL, 0),
+ XT_MK_REG_DESC("ar26", 0x1A, XT_REG_GENERAL, 0),
+ XT_MK_REG_DESC("ar27", 0x1B, XT_REG_GENERAL, 0),
+ XT_MK_REG_DESC("ar28", 0x1C, XT_REG_GENERAL, 0),
+ XT_MK_REG_DESC("ar29", 0x1D, XT_REG_GENERAL, 0),
+ XT_MK_REG_DESC("ar30", 0x1E, XT_REG_GENERAL, 0),
+ XT_MK_REG_DESC("ar31", 0x1F, XT_REG_GENERAL, 0),
+ XT_MK_REG_DESC("ar32", 0x20, XT_REG_GENERAL, 0),
+ XT_MK_REG_DESC("ar33", 0x21, XT_REG_GENERAL, 0),
+ XT_MK_REG_DESC("ar34", 0x22, XT_REG_GENERAL, 0),
+ XT_MK_REG_DESC("ar35", 0x23, XT_REG_GENERAL, 0),
+ XT_MK_REG_DESC("ar36", 0x24, XT_REG_GENERAL, 0),
+ XT_MK_REG_DESC("ar37", 0x25, XT_REG_GENERAL, 0),
+ XT_MK_REG_DESC("ar38", 0x26, XT_REG_GENERAL, 0),
+ XT_MK_REG_DESC("ar39", 0x27, XT_REG_GENERAL, 0),
+ XT_MK_REG_DESC("ar40", 0x28, XT_REG_GENERAL, 0),
+ XT_MK_REG_DESC("ar41", 0x29, XT_REG_GENERAL, 0),
+ XT_MK_REG_DESC("ar42", 0x2A, XT_REG_GENERAL, 0),
+ XT_MK_REG_DESC("ar43", 0x2B, XT_REG_GENERAL, 0),
+ XT_MK_REG_DESC("ar44", 0x2C, XT_REG_GENERAL, 0),
+ XT_MK_REG_DESC("ar45", 0x2D, XT_REG_GENERAL, 0),
+ XT_MK_REG_DESC("ar46", 0x2E, XT_REG_GENERAL, 0),
+ XT_MK_REG_DESC("ar47", 0x2F, XT_REG_GENERAL, 0),
+ XT_MK_REG_DESC("ar48", 0x30, XT_REG_GENERAL, 0),
+ XT_MK_REG_DESC("ar49", 0x31, XT_REG_GENERAL, 0),
+ XT_MK_REG_DESC("ar50", 0x32, XT_REG_GENERAL, 0),
+ XT_MK_REG_DESC("ar51", 0x33, XT_REG_GENERAL, 0),
+ XT_MK_REG_DESC("ar52", 0x34, XT_REG_GENERAL, 0),
+ XT_MK_REG_DESC("ar53", 0x35, XT_REG_GENERAL, 0),
+ XT_MK_REG_DESC("ar54", 0x36, XT_REG_GENERAL, 0),
+ XT_MK_REG_DESC("ar55", 0x37, XT_REG_GENERAL, 0),
+ XT_MK_REG_DESC("ar56", 0x38, XT_REG_GENERAL, 0),
+ XT_MK_REG_DESC("ar57", 0x39, XT_REG_GENERAL, 0),
+ XT_MK_REG_DESC("ar58", 0x3A, XT_REG_GENERAL, 0),
+ XT_MK_REG_DESC("ar59", 0x3B, XT_REG_GENERAL, 0),
+ XT_MK_REG_DESC("ar60", 0x3C, XT_REG_GENERAL, 0),
+ XT_MK_REG_DESC("ar61", 0x3D, XT_REG_GENERAL, 0),
+ XT_MK_REG_DESC("ar62", 0x3E, XT_REG_GENERAL, 0),
+ XT_MK_REG_DESC("ar63", 0x3F, XT_REG_GENERAL, 0),
+ XT_MK_REG_DESC("windowbase", 0x48, XT_REG_SPECIAL, 0),
+ XT_MK_REG_DESC("windowstart", 0x49, XT_REG_SPECIAL, 0),
+ XT_MK_REG_DESC("ps", 0xE6, XT_REG_SPECIAL, 0), /* PS (not mapped through EPS[]) */
+ XT_MK_REG_DESC("ibreakenable", 0x60, XT_REG_SPECIAL, 0),
+ XT_MK_REG_DESC("ddr", 0x68, XT_REG_DEBUG, XT_REGF_NOREAD),
+ XT_MK_REG_DESC("ibreaka0", 0x80, XT_REG_SPECIAL, 0),
+ XT_MK_REG_DESC("ibreaka1", 0x81, XT_REG_SPECIAL, 0),
+ XT_MK_REG_DESC("dbreaka0", 0x90, XT_REG_SPECIAL, 0),
+ XT_MK_REG_DESC("dbreaka1", 0x91, XT_REG_SPECIAL, 0),
+ XT_MK_REG_DESC("dbreakc0", 0xA0, XT_REG_SPECIAL, 0),
+ XT_MK_REG_DESC("dbreakc1", 0xA1, XT_REG_SPECIAL, 0),
+ XT_MK_REG_DESC("cpenable", 0xE0, XT_REG_SPECIAL, 0),
+ XT_MK_REG_DESC("exccause", 0xE8, XT_REG_SPECIAL, 0),
+ XT_MK_REG_DESC("debugcause", 0xE9, XT_REG_SPECIAL, 0),
+ XT_MK_REG_DESC("icount", 0xEC, XT_REG_SPECIAL, 0),
+ XT_MK_REG_DESC("icountlevel", 0xED, XT_REG_SPECIAL, 0),
+
+ /* WARNING: For these registers, regnum points to the
+ * index of the corresponding ARx registers, NOT to
+ * the processor register number! */
+ XT_MK_REG_DESC("a0", XT_REG_IDX_AR0, XT_REG_RELGEN, 0),
+ XT_MK_REG_DESC("a1", XT_REG_IDX_AR1, XT_REG_RELGEN, 0),
+ XT_MK_REG_DESC("a2", XT_REG_IDX_AR2, XT_REG_RELGEN, 0),
+ XT_MK_REG_DESC("a3", XT_REG_IDX_AR3, XT_REG_RELGEN, 0),
+ XT_MK_REG_DESC("a4", XT_REG_IDX_AR4, XT_REG_RELGEN, 0),
+ XT_MK_REG_DESC("a5", XT_REG_IDX_AR5, XT_REG_RELGEN, 0),
+ XT_MK_REG_DESC("a6", XT_REG_IDX_AR6, XT_REG_RELGEN, 0),
+ XT_MK_REG_DESC("a7", XT_REG_IDX_AR7, XT_REG_RELGEN, 0),
+ XT_MK_REG_DESC("a8", XT_REG_IDX_AR8, XT_REG_RELGEN, 0),
+ XT_MK_REG_DESC("a9", XT_REG_IDX_AR9, XT_REG_RELGEN, 0),
+ XT_MK_REG_DESC("a10", XT_REG_IDX_AR10, XT_REG_RELGEN, 0),
+ XT_MK_REG_DESC("a11", XT_REG_IDX_AR11, XT_REG_RELGEN, 0),
+ XT_MK_REG_DESC("a12", XT_REG_IDX_AR12, XT_REG_RELGEN, 0),
+ XT_MK_REG_DESC("a13", XT_REG_IDX_AR13, XT_REG_RELGEN, 0),
+ XT_MK_REG_DESC("a14", XT_REG_IDX_AR14, XT_REG_RELGEN, 0),
+ XT_MK_REG_DESC("a15", XT_REG_IDX_AR15, XT_REG_RELGEN, 0),
};
-
/**
* Types of memory used at xtensa target
*/
@@ -343,11 +289,27 @@ enum xtensa_mem_region_type {
XTENSA_MEM_REG_IRAM,
XTENSA_MEM_REG_DROM,
XTENSA_MEM_REG_DRAM,
- XTENSA_MEM_REG_URAM,
- XTENSA_MEM_REG_XLMI,
+ XTENSA_MEM_REG_SRAM,
+ XTENSA_MEM_REG_SROM,
XTENSA_MEM_REGS_NUM
};
+/* Register definition as union for list allocation */
+union xtensa_reg_val_u {
+ xtensa_reg_val_t val;
+ uint8_t buf[4];
+};
+
+const struct xtensa_keyval_info_s xt_qerr[XT_QERR_NUM] = {
+ { .chrval = "E00", .intval = ERROR_FAIL },
+ { .chrval = "E01", .intval = ERROR_FAIL },
+ { .chrval = "E02", .intval = ERROR_COMMAND_ARGUMENT_INVALID },
+ { .chrval = "E03", .intval = ERROR_FAIL },
+};
+
+/* Set to true for extra debug logging */
+static const bool xtensa_extra_debug_log;
+
/**
* Gets a config for the specific mem type
*/
@@ -364,10 +326,10 @@ static inline const struct xtensa_local_mem_config *xtensa_get_mem_config(
return &xtensa->core_config->drom;
case XTENSA_MEM_REG_DRAM:
return &xtensa->core_config->dram;
- case XTENSA_MEM_REG_URAM:
- return &xtensa->core_config->uram;
- case XTENSA_MEM_REG_XLMI:
- return &xtensa->core_config->xlmi;
+ case XTENSA_MEM_REG_SRAM:
+ return &xtensa->core_config->sram;
+ case XTENSA_MEM_REG_SROM:
+ return &xtensa->core_config->srom;
default:
return NULL;
}
@@ -410,14 +372,47 @@ static inline const struct xtensa_local_mem_region_config *xtensa_target_memory_
return NULL;
}
+static inline bool xtensa_is_cacheable(const struct xtensa_cache_config *cache,
+ const struct xtensa_local_mem_config *mem,
+ target_addr_t address)
+{
+ if (!cache->size)
+ return false;
+ return xtensa_memory_region_find(mem, address);
+}
+
+static inline bool xtensa_is_icacheable(struct xtensa *xtensa, target_addr_t address)
+{
+ return xtensa_is_cacheable(&xtensa->core_config->icache, &xtensa->core_config->iram, address) ||
+ xtensa_is_cacheable(&xtensa->core_config->icache, &xtensa->core_config->irom, address) ||
+ xtensa_is_cacheable(&xtensa->core_config->icache, &xtensa->core_config->sram, address) ||
+ xtensa_is_cacheable(&xtensa->core_config->icache, &xtensa->core_config->srom, address);
+}
+
+static inline bool xtensa_is_dcacheable(struct xtensa *xtensa, target_addr_t address)
+{
+ return xtensa_is_cacheable(&xtensa->core_config->dcache, &xtensa->core_config->dram, address) ||
+ xtensa_is_cacheable(&xtensa->core_config->dcache, &xtensa->core_config->drom, address) ||
+ xtensa_is_cacheable(&xtensa->core_config->dcache, &xtensa->core_config->sram, address) ||
+ xtensa_is_cacheable(&xtensa->core_config->dcache, &xtensa->core_config->srom, address);
+}
+
static int xtensa_core_reg_get(struct reg *reg)
{
- /*We don't need this because we read all registers on halt anyway. */
+ /* We don't need this because we read all registers on halt anyway. */
struct xtensa *xtensa = (struct xtensa *)reg->arch_info;
struct target *target = xtensa->target;
if (target->state != TARGET_HALTED)
return ERROR_TARGET_NOT_HALTED;
+ if (!reg->exist) {
+ if (strncmp(reg->name, "?0x", 3) == 0) {
+ unsigned int regnum = strtoul(reg->name + 1, 0, 0);
+ LOG_WARNING("Read unknown register 0x%04x ignored", regnum);
+ return ERROR_OK;
+ }
+ return ERROR_COMMAND_ARGUMENT_INVALID;
+ }
return ERROR_OK;
}
@@ -430,7 +425,31 @@ static int xtensa_core_reg_set(struct reg *reg, uint8_t *buf)
if (target->state != TARGET_HALTED)
return ERROR_TARGET_NOT_HALTED;
+ if (!reg->exist) {
+ if (strncmp(reg->name, "?0x", 3) == 0) {
+ unsigned int regnum = strtoul(reg->name + 1, 0, 0);
+ LOG_WARNING("Write unknown register 0x%04x ignored", regnum);
+ return ERROR_OK;
+ }
+ return ERROR_COMMAND_ARGUMENT_INVALID;
+ }
+
buf_cpy(buf, reg->value, reg->size);
+
+ if (xtensa->core_config->windowed) {
+ /* If the user updates a potential scratch register, track for conflicts */
+ for (enum xtensa_ar_scratch_set_e s = 0; s < XT_AR_SCRATCH_NUM; s++) {
+ if (strcmp(reg->name, xtensa->scratch_ars[s].chrval) == 0) {
+ LOG_DEBUG("Scratch reg %s [0x%08" PRIx32 "] set from gdb", reg->name,
+ buf_get_u32(reg->value, 0, 32));
+ LOG_DEBUG("scratch_ars mapping: a3/%s, a4/%s",
+ xtensa->scratch_ars[XT_AR_SCRATCH_AR3].chrval,
+ xtensa->scratch_ars[XT_AR_SCRATCH_AR4].chrval);
+ xtensa->scratch_ars[s].intval = true;
+ break;
+ }
+ }
+ }
reg->dirty = true;
reg->valid = true;
@@ -442,26 +461,13 @@ static const struct reg_arch_type xtensa_reg_type = {
.set = xtensa_core_reg_set,
};
-const struct reg_arch_type xtensa_user_reg_u32_type = {
- .get = xtensa_core_reg_get,
- .set = xtensa_core_reg_set,
-};
-
-const struct reg_arch_type xtensa_user_reg_u128_type = {
- .get = xtensa_core_reg_get,
- .set = xtensa_core_reg_set,
-};
-
-static inline size_t xtensa_insn_size_get(uint32_t insn)
-{
- return insn & BIT(3) ? 2 : XT_ISNS_SZ_MAX;
-}
-
/* Convert a register index that's indexed relative to windowbase, to the real address. */
-static enum xtensa_reg_id xtensa_windowbase_offset_to_canonical(enum xtensa_reg_id reg_idx, int windowbase)
+static enum xtensa_reg_id xtensa_windowbase_offset_to_canonical(struct xtensa *xtensa,
+ enum xtensa_reg_id reg_idx,
+ int windowbase)
{
unsigned int idx;
- if (reg_idx >= XT_REG_IDX_AR0 && reg_idx <= XT_REG_IDX_AR63) {
+ if (reg_idx >= XT_REG_IDX_AR0 && reg_idx <= XT_REG_IDX_ARLAST) {
idx = reg_idx - XT_REG_IDX_AR0;
} else if (reg_idx >= XT_REG_IDX_A0 && reg_idx <= XT_REG_IDX_A15) {
idx = reg_idx - XT_REG_IDX_A0;
@@ -469,12 +475,14 @@ static enum xtensa_reg_id xtensa_windowbase_offset_to_canonical(enum xtensa_reg_
LOG_ERROR("Error: can't convert register %d to non-windowbased register!", reg_idx);
return -1;
}
- return ((idx + windowbase * 4) & 63) + XT_REG_IDX_AR0;
+ return ((idx + windowbase * 4) & (xtensa->core_config->aregs_num - 1)) + XT_REG_IDX_AR0;
}
-static enum xtensa_reg_id xtensa_canonical_to_windowbase_offset(enum xtensa_reg_id reg_idx, int windowbase)
+static enum xtensa_reg_id xtensa_canonical_to_windowbase_offset(struct xtensa *xtensa,
+ enum xtensa_reg_id reg_idx,
+ int windowbase)
{
- return xtensa_windowbase_offset_to_canonical(reg_idx, -windowbase);
+ return xtensa_windowbase_offset_to_canonical(xtensa, reg_idx, -windowbase);
}
static void xtensa_mark_register_dirty(struct xtensa *xtensa, enum xtensa_reg_id reg_idx)
@@ -483,42 +491,25 @@ static void xtensa_mark_register_dirty(struct xtensa *xtensa, enum xtensa_reg_id
reg_list[reg_idx].dirty = true;
}
-static int xtensa_queue_dbg_reg_read(struct xtensa *xtensa, unsigned int reg, uint8_t *data)
-{
- struct xtensa_debug_module *dm = &xtensa->dbg_mod;
-
- if (!xtensa->core_config->trace.enabled &&
- (reg <= NARADR_MEMADDREND || (reg >= NARADR_PMG && reg <= NARADR_PMSTAT7))) {
- LOG_ERROR("Can not access %u reg when Trace Port option disabled!", reg);
- return ERROR_FAIL;
- }
- return dm->dbg_ops->queue_reg_read(dm, reg, data);
-}
-
-static int xtensa_queue_dbg_reg_write(struct xtensa *xtensa, unsigned int reg, uint32_t data)
-{
- struct xtensa_debug_module *dm = &xtensa->dbg_mod;
-
- if (!xtensa->core_config->trace.enabled &&
- (reg <= NARADR_MEMADDREND || (reg >= NARADR_PMG && reg <= NARADR_PMSTAT7))) {
- LOG_ERROR("Can not access %u reg when Trace Port option disabled!", reg);
- return ERROR_FAIL;
- }
- return dm->dbg_ops->queue_reg_write(dm, reg, data);
-}
-
static void xtensa_queue_exec_ins(struct xtensa *xtensa, uint32_t ins)
{
xtensa_queue_dbg_reg_write(xtensa, NARADR_DIR0EXEC, ins);
}
-static bool xtensa_reg_is_readable(enum xtensa_reg_flags flags, xtensa_reg_val_t cpenable)
+static void xtensa_queue_exec_ins_wide(struct xtensa *xtensa, uint8_t *ops, uint8_t oplen)
{
- if (flags & XT_REGF_NOREAD)
- return false;
- if ((flags & XT_REGF_COPROC0) && (cpenable & BIT(0)) == 0)
- return false;
- return true;
+ if ((oplen > 0) && (oplen <= 64)) {
+ uint32_t opsw[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; /* 8 DIRx regs: max width 64B */
+ uint8_t oplenw = (oplen + 3) / 4;
+ if (xtensa->target->endianness == TARGET_BIG_ENDIAN)
+ buf_bswap32((uint8_t *)opsw, ops, oplenw * 4);
+ else
+ memcpy(opsw, ops, oplen);
+ for (int32_t i = oplenw - 1; i > 0; i--)
+ xtensa_queue_dbg_reg_write(xtensa, NARADR_DIR0 + i, opsw[i]);
+ /* Write DIR0EXEC last */
+ xtensa_queue_dbg_reg_write(xtensa, NARADR_DIR0EXEC, opsw[0]);
+ }
}
static int xtensa_queue_pwr_reg_write(struct xtensa *xtensa, unsigned int reg, uint32_t data)
@@ -527,63 +518,67 @@ static int xtensa_queue_pwr_reg_write(struct xtensa *xtensa, unsigned int reg, u
return dm->pwr_ops->queue_reg_write(dm, reg, data);
}
-static bool xtensa_special_reg_exists(struct xtensa *xtensa, enum xtensa_reg_id reg_idx)
-{
- /* TODO: array of size XT_NUM_REGS can be used here to map special register ID to
- * corresponding config option 'enabled' flag */
- if (reg_idx >= XT_REG_IDX_LBEG && reg_idx <= XT_REG_IDX_LCOUNT)
- return xtensa->core_config->loop;
- else if (reg_idx == XT_REG_IDX_BR)
- return xtensa->core_config->boolean;
- else if (reg_idx == XT_REG_IDX_LITBASE)
- return xtensa->core_config->ext_l32r;
- else if (reg_idx == XT_REG_IDX_SCOMPARE1 || reg_idx == XT_REG_IDX_ATOMCTL)
- return xtensa->core_config->cond_store;
- else if (reg_idx >= XT_REG_IDX_ACCLO && reg_idx <= XT_REG_IDX_M3)
- return xtensa->core_config->mac16;
- else if (reg_idx == XT_REG_IDX_WINDOWBASE || reg_idx == XT_REG_IDX_WINDOWSTART)
- return xtensa->core_config->windowed;
- else if (reg_idx >= XT_REG_IDX_PTEVADDR && reg_idx <= XT_REG_IDX_DTLBCFG)
- return xtensa->core_config->mmu.enabled;
- else if (reg_idx == XT_REG_IDX_MMID)
- return xtensa->core_config->trace.enabled;
- else if (reg_idx >= XT_REG_IDX_MEPC && reg_idx <= XT_REG_IDX_MEVADDR)
- return xtensa->core_config->mem_err_check;
- else if (reg_idx == XT_REG_IDX_CPENABLE)
- return xtensa->core_config->coproc;
- else if (reg_idx == XT_REG_IDX_VECBASE)
- return xtensa->core_config->reloc_vec;
- else if (reg_idx == XT_REG_IDX_CCOUNT)
- return xtensa->core_config->tim_irq.enabled;
- else if (reg_idx >= XT_REG_IDX_CCOMPARE0 && reg_idx <= XT_REG_IDX_CCOMPARE2)
- return xtensa->core_config->tim_irq.enabled &&
- (reg_idx - XT_REG_IDX_CCOMPARE0 < xtensa->core_config->tim_irq.comp_num);
- else if (reg_idx == XT_REG_IDX_PRID)
- return xtensa->core_config->proc_id;
- else if (reg_idx >= XT_REG_IDX_MISC0 && reg_idx <= XT_REG_IDX_MISC3)
- return reg_idx - XT_REG_IDX_MISC0 < xtensa->core_config->miscregs_num;
- return true;
+/* NOTE: Assumes A3 has already been saved */
+int xtensa_window_state_save(struct target *target, uint32_t *woe)
+{
+ struct xtensa *xtensa = target_to_xtensa(target);
+ int woe_dis;
+ uint8_t woe_buf[4];
+
+ if (xtensa->core_config->windowed) {
+ /* Save PS (LX) and disable window overflow exceptions prior to AR save */
+ xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_PS, XT_REG_A3));
+ xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, XT_SR_DDR, XT_REG_A3));
+ xtensa_queue_dbg_reg_read(xtensa, NARADR_DDR, woe_buf);
+ int res = jtag_execute_queue();
+ if (res != ERROR_OK) {
+ LOG_ERROR("Failed to read PS (%d)!", res);
+ return res;
+ }
+ xtensa_core_status_check(target);
+ *woe = buf_get_u32(woe_buf, 0, 32);
+ woe_dis = *woe & ~XT_PS_WOE_MSK;
+ LOG_DEBUG("Clearing PS.WOE (0x%08" PRIx32 " -> 0x%08" PRIx32 ")", *woe, woe_dis);
+ xtensa_queue_dbg_reg_write(xtensa, NARADR_DDR, woe_dis);
+ xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3));
+ xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, XT_SR_PS, XT_REG_A3));
+ }
+ return ERROR_OK;
}
-static bool xtensa_user_reg_exists(struct xtensa *xtensa, enum xtensa_reg_id reg_idx)
+/* NOTE: Assumes A3 has already been saved */
+void xtensa_window_state_restore(struct target *target, uint32_t woe)
{
- if (reg_idx == XT_REG_IDX_THREADPTR)
- return xtensa->core_config->threadptr;
- if (reg_idx == XT_REG_IDX_FCR || reg_idx == XT_REG_IDX_FSR)
- return xtensa->core_config->fp_coproc;
- return false;
+ struct xtensa *xtensa = target_to_xtensa(target);
+ if (xtensa->core_config->windowed) {
+ /* Restore window overflow exception state */
+ xtensa_queue_dbg_reg_write(xtensa, NARADR_DDR, woe);
+ xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3));
+ xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, XT_SR_PS, XT_REG_A3));
+ LOG_DEBUG("Restored PS.WOE (0x%08" PRIx32 ")", woe);
+ }
}
-static inline bool xtensa_fp_reg_exists(struct xtensa *xtensa, enum xtensa_reg_id reg_idx)
+static bool xtensa_reg_is_readable(int flags, int cpenable)
{
- return xtensa->core_config->fp_coproc;
+ if (flags & XT_REGF_NOREAD)
+ return false;
+ if ((flags & XT_REGF_COPROC0) && (cpenable & BIT(0)) == 0)
+ return false;
+ return true;
}
-static inline bool xtensa_regular_reg_exists(struct xtensa *xtensa, enum xtensa_reg_id reg_idx)
+static bool xtensa_scratch_regs_fixup(struct xtensa *xtensa, struct reg *reg_list, int i, int j, int a_idx, int ar_idx)
{
- if (reg_idx >= XT_REG_IDX_AR0 && reg_idx <= XT_REG_IDX_AR63)
- return reg_idx - XT_REG_IDX_AR0 < xtensa->core_config->aregs_num;
- return true;
+ int a_name = (a_idx == XT_AR_SCRATCH_A3) ? 3 : 4;
+ if (xtensa->scratch_ars[a_idx].intval && !xtensa->scratch_ars[ar_idx].intval) {
+ LOG_DEBUG("AR conflict: a%d -> ar%d", a_name, j - XT_REG_IDX_AR0);
+ memcpy(reg_list[j].value, reg_list[i].value, sizeof(xtensa_reg_val_t));
+ } else {
+ LOG_DEBUG("AR conflict: ar%d -> a%d", j - XT_REG_IDX_AR0, a_name);
+ memcpy(reg_list[i].value, reg_list[j].value, sizeof(xtensa_reg_val_t));
+ }
+ return xtensa->scratch_ars[a_idx].intval && xtensa->scratch_ars[ar_idx].intval;
}
static int xtensa_write_dirty_registers(struct target *target)
@@ -591,45 +586,50 @@ static int xtensa_write_dirty_registers(struct target *target)
struct xtensa *xtensa = target_to_xtensa(target);
int res;
xtensa_reg_val_t regval, windowbase = 0;
- bool scratch_reg_dirty = false;
+ bool scratch_reg_dirty = false, delay_cpenable = false;
struct reg *reg_list = xtensa->core_cache->reg_list;
+ unsigned int reg_list_size = xtensa->core_cache->num_regs;
+ bool preserve_a3 = false;
+ uint8_t a3_buf[4];
+ xtensa_reg_val_t a3, woe;
LOG_TARGET_DEBUG(target, "start");
- /*We need to write the dirty registers in the cache list back to the processor.
- *Start by writing the SFR/user registers. */
- for (unsigned int i = 0; i < XT_NUM_REGS; i++) {
+ /* We need to write the dirty registers in the cache list back to the processor.
+ * Start by writing the SFR/user registers. */
+ for (unsigned int i = 0; i < reg_list_size; i++) {
+ struct xtensa_reg_desc *rlist = (i < XT_NUM_REGS) ? xtensa_regs : xtensa->optregs;
+ unsigned int ridx = (i < XT_NUM_REGS) ? i : i - XT_NUM_REGS;
if (reg_list[i].dirty) {
- if (xtensa_regs[i].type == XT_REG_SPECIAL ||
- xtensa_regs[i].type == XT_REG_USER ||
- xtensa_regs[i].type == XT_REG_FR) {
+ if (rlist[ridx].type == XT_REG_SPECIAL ||
+ rlist[ridx].type == XT_REG_USER ||
+ rlist[ridx].type == XT_REG_FR) {
scratch_reg_dirty = true;
+ if (i == XT_REG_IDX_CPENABLE) {
+ delay_cpenable = true;
+ continue;
+ }
regval = xtensa_reg_get(target, i);
- LOG_TARGET_DEBUG(target, "Writing back reg %s val %08" PRIX32,
- xtensa_regs[i].name,
+ LOG_TARGET_DEBUG(target, "Writing back reg %s (%d) val %08" PRIX32,
+ reg_list[i].name,
+ rlist[ridx].reg_num,
regval);
xtensa_queue_dbg_reg_write(xtensa, NARADR_DDR, regval);
- xtensa_queue_exec_ins(xtensa, XT_INS_RSR(XT_SR_DDR, XT_REG_A3));
- if (xtensa_regs[i].type == XT_REG_USER) {
- if (reg_list[i].exist)
- xtensa_queue_exec_ins(xtensa,
- XT_INS_WUR(xtensa_regs[i].reg_num,
- XT_REG_A3));
- } else if (xtensa_regs[i].type == XT_REG_FR) {
- if (reg_list[i].exist)
- xtensa_queue_exec_ins(xtensa,
- XT_INS_WFR(xtensa_regs[i].reg_num,
- XT_REG_A3));
- } else {/*SFR */
- if (reg_list[i].exist) {
- unsigned int reg_num = xtensa_regs[i].reg_num;
- if (reg_num == XT_PC_REG_NUM_BASE)
- /* reg number of PC for debug interrupt
- * depends on NDEBUGLEVEL */
- reg_num += xtensa->core_config->debug.irq_level;
-
- xtensa_queue_exec_ins(xtensa,
- XT_INS_WSR(reg_num, XT_REG_A3));
+ xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3));
+ if (reg_list[i].exist) {
+ unsigned int reg_num = rlist[ridx].reg_num;
+ if (rlist[ridx].type == XT_REG_USER) {
+ xtensa_queue_exec_ins(xtensa, XT_INS_WUR(xtensa, reg_num, XT_REG_A3));
+ } else if (rlist[ridx].type == XT_REG_FR) {
+ xtensa_queue_exec_ins(xtensa, XT_INS_WFR(xtensa, reg_num, XT_REG_A3));
+ } else {/*SFR */
+ if (reg_num == XT_PC_REG_NUM_VIRTUAL)
+ /* reg number of PC for debug interrupt depends on NDEBUGLEVEL
+ **/
+ reg_num =
+ (XT_PC_REG_NUM_BASE +
+ xtensa->core_config->debug.irq_level);
+ xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, reg_num, XT_REG_A3));
}
}
reg_list[i].dirty = false;
@@ -638,31 +638,64 @@ static int xtensa_write_dirty_registers(struct target *target)
}
if (scratch_reg_dirty)
xtensa_mark_register_dirty(xtensa, XT_REG_IDX_A3);
+ if (delay_cpenable) {
+ regval = xtensa_reg_get(target, XT_REG_IDX_CPENABLE);
+ LOG_TARGET_DEBUG(target, "Writing back reg cpenable (224) val %08" PRIX32, regval);
+ xtensa_queue_dbg_reg_write(xtensa, NARADR_DDR, regval);
+ xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3));
+ xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa,
+ xtensa_regs[XT_REG_IDX_CPENABLE].reg_num,
+ XT_REG_A3));
+ reg_list[XT_REG_IDX_CPENABLE].dirty = false;
+ }
- if (xtensa->core_config->user_regs_num > 0 &&
- xtensa->core_config->queue_write_dirty_user_regs)
- xtensa->core_config->queue_write_dirty_user_regs(target);
+ preserve_a3 = (xtensa->core_config->windowed);
+ if (preserve_a3) {
+ /* Save (windowed) A3 for scratch use */
+ xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, XT_SR_DDR, XT_REG_A3));
+ xtensa_queue_dbg_reg_read(xtensa, NARADR_DDR, a3_buf);
+ res = jtag_execute_queue();
+ xtensa_core_status_check(target);
+ a3 = buf_get_u32(a3_buf, 0, 32);
+ }
if (xtensa->core_config->windowed) {
- /*Grab the windowbase, we need it. */
+ res = xtensa_window_state_save(target, &woe);
+ if (res != ERROR_OK)
+ return res;
+ /* Grab the windowbase, we need it. */
windowbase = xtensa_reg_get(target, XT_REG_IDX_WINDOWBASE);
- /*Check if there are problems with both the ARx as well as the corresponding Rx
- * registers set and dirty. */
- /*Warn the user if this happens, not much else we can do... */
+ /* Check if there are mismatches between the ARx and corresponding Ax registers.
+ * When the user sets a register on a windowed config, xt-gdb may set the ARx
+ * register directly. Thus we take ARx as priority over Ax if both are dirty
+ * and it's unclear if the user set one over the other explicitly.
+ */
for (unsigned int i = XT_REG_IDX_A0; i <= XT_REG_IDX_A15; i++) {
- unsigned int j = xtensa_windowbase_offset_to_canonical(i, windowbase);
+ unsigned int j = xtensa_windowbase_offset_to_canonical(xtensa, i, windowbase);
if (reg_list[i].dirty && reg_list[j].dirty) {
- if (memcmp(reg_list[i].value, reg_list[j].value,
- sizeof(xtensa_reg_val_t)) != 0)
- LOG_WARNING(
- "Warning: Both A%d as well as the physical register it points to (AR%d) are dirty and differs in value. Results are undefined!",
- i - XT_REG_IDX_A0,
- j - XT_REG_IDX_AR0);
+ if (memcmp(reg_list[i].value, reg_list[j].value, sizeof(xtensa_reg_val_t)) != 0) {
+ bool show_warning = true;
+ if (i == XT_REG_IDX_A3)
+ show_warning = xtensa_scratch_regs_fixup(xtensa,
+ reg_list, i, j, XT_AR_SCRATCH_A3, XT_AR_SCRATCH_AR3);
+ else if (i == XT_REG_IDX_A4)
+ show_warning = xtensa_scratch_regs_fixup(xtensa,
+ reg_list, i, j, XT_AR_SCRATCH_A4, XT_AR_SCRATCH_AR4);
+ if (show_warning)
+ LOG_WARNING(
+ "Warning: Both A%d [0x%08" PRIx32
+ "] as well as its underlying physical register "
+ "(AR%d) [0x%08" PRIx32 "] are dirty and differ in value",
+ i - XT_REG_IDX_A0,
+ buf_get_u32(reg_list[i].value, 0, 32),
+ j - XT_REG_IDX_AR0,
+ buf_get_u32(reg_list[j].value, 0, 32));
+ }
}
}
}
- /*Write A0-A16 */
+ /* Write A0-A16. */
for (unsigned int i = 0; i < 16; i++) {
if (reg_list[XT_REG_IDX_A0 + i].dirty) {
regval = xtensa_reg_get(target, XT_REG_IDX_A0 + i);
@@ -671,21 +704,25 @@ static int xtensa_write_dirty_registers(struct target *target)
regval,
xtensa_regs[XT_REG_IDX_A0 + i].reg_num);
xtensa_queue_dbg_reg_write(xtensa, NARADR_DDR, regval);
- xtensa_queue_exec_ins(xtensa, XT_INS_RSR(XT_SR_DDR, i));
+ xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, i));
reg_list[XT_REG_IDX_A0 + i].dirty = false;
+ if (i == 3) {
+ /* Avoid stomping A3 during restore at end of function */
+ a3 = regval;
+ }
}
}
if (xtensa->core_config->windowed) {
- /*Now write AR0-AR63. */
- for (unsigned int j = 0; j < 64; j += 16) {
- /*Write the 16 registers we can see */
+ /* Now write AR registers */
+ for (unsigned int j = 0; j < XT_REG_IDX_ARLAST; j += 16) {
+ /* Write the 16 registers we can see */
for (unsigned int i = 0; i < 16; i++) {
if (i + j < xtensa->core_config->aregs_num) {
enum xtensa_reg_id realadr =
- xtensa_windowbase_offset_to_canonical(XT_REG_IDX_AR0 + i + j,
+ xtensa_windowbase_offset_to_canonical(xtensa, XT_REG_IDX_AR0 + i + j,
windowbase);
- /*Write back any dirty un-windowed registers */
+ /* Write back any dirty un-windowed registers */
if (reg_list[realadr].dirty) {
regval = xtensa_reg_get(target, realadr);
LOG_TARGET_DEBUG(
@@ -696,53 +733,36 @@ static int xtensa_write_dirty_registers(struct target *target)
xtensa_regs[realadr].reg_num);
xtensa_queue_dbg_reg_write(xtensa, NARADR_DDR, regval);
xtensa_queue_exec_ins(xtensa,
- XT_INS_RSR(XT_SR_DDR, xtensa_regs[XT_REG_IDX_AR0 + i].reg_num));
+ XT_INS_RSR(xtensa, XT_SR_DDR,
+ xtensa_regs[XT_REG_IDX_AR0 + i].reg_num));
reg_list[realadr].dirty = false;
+ if ((i + j) == 3)
+ /* Avoid stomping AR during A3 restore at end of function */
+ a3 = regval;
}
}
}
/*Now rotate the window so we'll see the next 16 registers. The final rotate
* will wraparound, */
/*leaving us in the state we were. */
- xtensa_queue_exec_ins(xtensa, XT_INS_ROTW(4));
+ xtensa_queue_exec_ins(xtensa, XT_INS_ROTW(xtensa, 4));
}
- }
- res = jtag_execute_queue();
- xtensa_core_status_check(target);
- return res;
-}
+ xtensa_window_state_restore(target, woe);
-int xtensa_queue_write_dirty_user_regs_u32(struct target *target)
-{
- struct xtensa *xtensa = target_to_xtensa(target);
- struct reg *reg_list = xtensa->core_cache->reg_list;
- xtensa_reg_val_t reg_val;
- bool scratch_reg_dirty = false;
-
- LOG_TARGET_DEBUG(target, "start");
+ for (enum xtensa_ar_scratch_set_e s = 0; s < XT_AR_SCRATCH_NUM; s++)
+ xtensa->scratch_ars[s].intval = false;
+ }
- /* We need to write the dirty registers in the cache list back to the processor.
- * Start by writing the SFR/user registers. */
- for (unsigned int i = 0; i < xtensa->core_config->user_regs_num; i++) {
- if (!reg_list[XT_USR_REG_START + i].dirty)
- continue;
- scratch_reg_dirty = true;
- reg_val = xtensa_reg_get(target, XT_USR_REG_START + i);
- LOG_TARGET_DEBUG(target, "Writing back reg %s val %08" PRIX32,
- xtensa->core_config->user_regs[i].name,
- reg_val);
- xtensa_queue_dbg_reg_write(xtensa, NARADR_DDR, reg_val);
- xtensa_queue_exec_ins(xtensa, XT_INS_RSR(XT_SR_DDR, XT_REG_A3));
- xtensa_queue_exec_ins(xtensa,
- XT_INS_WUR(xtensa->core_config->user_regs[i].reg_num,
- XT_REG_A3));
- reg_list[XT_USR_REG_START + i].dirty = false;
+ if (preserve_a3) {
+ xtensa_queue_dbg_reg_write(xtensa, NARADR_DDR, a3);
+ xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3));
}
- if (scratch_reg_dirty)
- xtensa_mark_register_dirty(xtensa, XT_REG_IDX_A3);
- return ERROR_OK;
+ res = jtag_execute_queue();
+ xtensa_core_status_check(target);
+
+ return res;
}
static inline bool xtensa_is_stopped(struct target *target)
@@ -757,6 +777,12 @@ int xtensa_examine(struct target *target)
unsigned int cmd = PWRCTL_DEBUGWAKEUP | PWRCTL_MEMWAKEUP | PWRCTL_COREWAKEUP;
LOG_DEBUG("coreid = %d", target->coreid);
+
+ if (xtensa->core_config->core_type == XT_UNDEF) {
+ LOG_ERROR("XTensa core not configured; is xtensa-core-openocd.cfg missing?");
+ return ERROR_FAIL;
+ }
+
xtensa_queue_pwr_reg_write(xtensa, DMREG_PWRCTL, cmd);
xtensa_queue_pwr_reg_write(xtensa, DMREG_PWRCTL, cmd | PWRCTL_JTAGDEBUGUSE);
xtensa_dm_queue_enable(&xtensa->dbg_mod);
@@ -878,7 +904,7 @@ int xtensa_core_status_check(struct target *target)
OCDDSR_EXECEXCEPTION | OCDDSR_EXECOVERRUN);
if (res != ERROR_OK && !xtensa->suppress_dsr_errors)
LOG_TARGET_ERROR(target, "clearing DSR failed!");
- return xtensa->suppress_dsr_errors ? ERROR_OK : ERROR_FAIL;
+ return ERROR_FAIL;
}
return ERROR_OK;
}
@@ -887,7 +913,6 @@ xtensa_reg_val_t xtensa_reg_get(struct target *target, enum xtensa_reg_id reg_id
{
struct xtensa *xtensa = target_to_xtensa(target);
struct reg *reg = &xtensa->core_cache->reg_list[reg_id];
- assert(reg_id < xtensa->core_cache->num_regs && "Attempt to access non-existing reg!");
return xtensa_reg_get_value(reg);
}
@@ -895,12 +920,35 @@ void xtensa_reg_set(struct target *target, enum xtensa_reg_id reg_id, xtensa_reg
{
struct xtensa *xtensa = target_to_xtensa(target);
struct reg *reg = &xtensa->core_cache->reg_list[reg_id];
- assert(reg_id < xtensa->core_cache->num_regs && "Attempt to access non-existing reg!");
if (xtensa_reg_get_value(reg) == value)
return;
xtensa_reg_set_value(reg, value);
}
+/* Set Ax (XT_REG_RELGEN) register along with its underlying ARx (XT_REG_GENERAL) */
+void xtensa_reg_set_deep_relgen(struct target *target, enum xtensa_reg_id a_idx, xtensa_reg_val_t value)
+{
+ struct xtensa *xtensa = target_to_xtensa(target);
+ uint32_t windowbase = (xtensa->core_config->windowed ?
+ xtensa_reg_get(target, XT_REG_IDX_WINDOWBASE) : 0);
+ int ar_idx = xtensa_windowbase_offset_to_canonical(xtensa, a_idx, windowbase);
+ xtensa_reg_set(target, a_idx, value);
+ xtensa_reg_set(target, ar_idx, value);
+}
+
+/* Read cause for entering halted state; return bitmask in DEBUGCAUSE_* format */
+uint32_t xtensa_cause_get(struct target *target)
+{
+ return xtensa_reg_get(target, XT_REG_IDX_DEBUGCAUSE);
+}
+
+void xtensa_cause_clear(struct target *target)
+{
+ struct xtensa *xtensa = target_to_xtensa(target);
+ xtensa_reg_set(target, XT_REG_IDX_DEBUGCAUSE, 0);
+ xtensa->core_cache->reg_list[XT_REG_IDX_DEBUGCAUSE].dirty = false;
+}
+
int xtensa_assert_reset(struct target *target)
{
struct xtensa *xtensa = target_to_xtensa(target);
@@ -940,17 +988,43 @@ int xtensa_deassert_reset(struct target *target)
return res;
}
+int xtensa_soft_reset_halt(struct target *target)
+{
+ LOG_TARGET_DEBUG(target, "begin");
+ return xtensa_assert_reset(target);
+}
+
int xtensa_fetch_all_regs(struct target *target)
{
struct xtensa *xtensa = target_to_xtensa(target);
struct reg *reg_list = xtensa->core_cache->reg_list;
- xtensa_reg_val_t cpenable = 0, windowbase = 0;
- uint8_t regvals[XT_NUM_REGS][sizeof(xtensa_reg_val_t)];
- uint8_t dsrs[XT_NUM_REGS][sizeof(xtensa_dsr_t)];
+ unsigned int reg_list_size = xtensa->core_cache->num_regs;
+ xtensa_reg_val_t cpenable = 0, windowbase = 0, a3;
+ uint32_t woe;
+ uint8_t a3_buf[4];
bool debug_dsrs = !xtensa->regs_fetched || LOG_LEVEL_IS(LOG_LVL_DEBUG);
+ union xtensa_reg_val_u *regvals = calloc(reg_list_size, sizeof(*regvals));
+ if (!regvals) {
+ LOG_TARGET_ERROR(target, "unable to allocate memory for regvals!");
+ return ERROR_FAIL;
+ }
+ union xtensa_reg_val_u *dsrs = calloc(reg_list_size, sizeof(*dsrs));
+ if (!dsrs) {
+ LOG_TARGET_ERROR(target, "unable to allocate memory for dsrs!");
+ free(regvals);
+ return ERROR_FAIL;
+ }
+
LOG_TARGET_DEBUG(target, "start");
+ /* Save (windowed) A3 so cache matches physical AR3; A3 usable as scratch */
+ xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, XT_SR_DDR, XT_REG_A3));
+ xtensa_queue_dbg_reg_read(xtensa, NARADR_DDR, a3_buf);
+ int res = xtensa_window_state_save(target, &woe);
+ if (res != ERROR_OK)
+ goto xtensa_fetch_all_regs_done;
+
/* Assume the CPU has just halted. We now want to fill the register cache with all the
* register contents GDB needs. For speed, we pipeline all the read operations, execute them
* in one go, then sort everything out from the regvals variable. */
@@ -961,176 +1035,178 @@ int xtensa_fetch_all_regs(struct target *target)
for (unsigned int i = 0; i < 16; i++) {
if (i + j < xtensa->core_config->aregs_num) {
xtensa_queue_exec_ins(xtensa,
- XT_INS_WSR(XT_SR_DDR, xtensa_regs[XT_REG_IDX_AR0 + i].reg_num));
- xtensa_queue_dbg_reg_read(xtensa, NARADR_DDR, regvals[XT_REG_IDX_AR0 + i + j]);
+ XT_INS_WSR(xtensa, XT_SR_DDR, xtensa_regs[XT_REG_IDX_AR0 + i].reg_num));
+ xtensa_queue_dbg_reg_read(xtensa, NARADR_DDR,
+ regvals[XT_REG_IDX_AR0 + i + j].buf);
if (debug_dsrs)
- xtensa_queue_dbg_reg_read(xtensa, NARADR_DSR, dsrs[XT_REG_IDX_AR0 + i + j]);
+ xtensa_queue_dbg_reg_read(xtensa, NARADR_DSR,
+ dsrs[XT_REG_IDX_AR0 + i + j].buf);
}
}
- if (xtensa->core_config->windowed) {
+ if (xtensa->core_config->windowed)
/* Now rotate the window so we'll see the next 16 registers. The final rotate
* will wraparound, */
/* leaving us in the state we were. */
- xtensa_queue_exec_ins(xtensa, XT_INS_ROTW(4));
- }
+ xtensa_queue_exec_ins(xtensa, XT_INS_ROTW(xtensa, 4));
}
+ xtensa_window_state_restore(target, woe);
+
if (xtensa->core_config->coproc) {
- /* As the very first thing after AREGS, go grab the CPENABLE registers. It indicates
- * if we can also grab the FP */
- /* (and theoretically other coprocessor) registers, or if this is a bad thing to do.*/
- xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa_regs[XT_REG_IDX_CPENABLE].reg_num, XT_REG_A3));
- xtensa_queue_exec_ins(xtensa, XT_INS_WSR(XT_SR_DDR, XT_REG_A3));
- xtensa_queue_dbg_reg_read(xtensa, NARADR_DDR, regvals[XT_REG_IDX_CPENABLE]);
+ /* As the very first thing after AREGS, go grab CPENABLE */
+ xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, xtensa_regs[XT_REG_IDX_CPENABLE].reg_num, XT_REG_A3));
+ xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, XT_SR_DDR, XT_REG_A3));
+ xtensa_queue_dbg_reg_read(xtensa, NARADR_DDR, regvals[XT_REG_IDX_CPENABLE].buf);
}
- int res = jtag_execute_queue();
+ res = jtag_execute_queue();
if (res != ERROR_OK) {
LOG_ERROR("Failed to read ARs (%d)!", res);
- return res;
+ goto xtensa_fetch_all_regs_done;
}
xtensa_core_status_check(target);
- if (xtensa->core_config->coproc)
- cpenable = buf_get_u32(regvals[XT_REG_IDX_CPENABLE], 0, 32);
+ a3 = buf_get_u32(a3_buf, 0, 32);
+
+ if (xtensa->core_config->coproc) {
+ cpenable = buf_get_u32(regvals[XT_REG_IDX_CPENABLE].buf, 0, 32);
+
+ /* Enable all coprocessors (by setting all bits in CPENABLE) so we can read FP and user registers. */
+ xtensa_queue_dbg_reg_write(xtensa, NARADR_DDR, 0xffffffff);
+ xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3));
+ xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, xtensa_regs[XT_REG_IDX_CPENABLE].reg_num, XT_REG_A3));
+
+ /* Save CPENABLE; flag dirty later (when regcache updated) so original value is always restored */
+ LOG_TARGET_DEBUG(target, "CPENABLE: was 0x%" PRIx32 ", all enabled", cpenable);
+ xtensa_reg_set(target, XT_REG_IDX_CPENABLE, cpenable);
+ }
/* We're now free to use any of A0-A15 as scratch registers
* Grab the SFRs and user registers first. We use A3 as a scratch register. */
- for (unsigned int i = 0; i < XT_NUM_REGS; i++) {
- if (xtensa_reg_is_readable(xtensa_regs[i].flags, cpenable) && reg_list[i].exist &&
- (xtensa_regs[i].type == XT_REG_SPECIAL ||
- xtensa_regs[i].type == XT_REG_USER || xtensa_regs[i].type == XT_REG_FR)) {
- if (xtensa_regs[i].type == XT_REG_USER) {
- xtensa_queue_exec_ins(xtensa, XT_INS_RUR(xtensa_regs[i].reg_num, XT_REG_A3));
- } else if (xtensa_regs[i].type == XT_REG_FR) {
- xtensa_queue_exec_ins(xtensa, XT_INS_RFR(xtensa_regs[i].reg_num, XT_REG_A3));
- } else { /*SFR */
- unsigned int reg_num = xtensa_regs[i].reg_num;
- if (reg_num == XT_PC_REG_NUM_BASE) {
+ for (unsigned int i = 0; i < reg_list_size; i++) {
+ struct xtensa_reg_desc *rlist = (i < XT_NUM_REGS) ? xtensa_regs : xtensa->optregs;
+ unsigned int ridx = (i < XT_NUM_REGS) ? i : i - XT_NUM_REGS;
+ if (xtensa_reg_is_readable(rlist[ridx].flags, cpenable) && rlist[ridx].exist) {
+ bool reg_fetched = true;
+ unsigned int reg_num = rlist[ridx].reg_num;
+ switch (rlist[ridx].type) {
+ case XT_REG_USER:
+ xtensa_queue_exec_ins(xtensa, XT_INS_RUR(xtensa, reg_num, XT_REG_A3));
+ break;
+ case XT_REG_FR:
+ xtensa_queue_exec_ins(xtensa, XT_INS_RFR(xtensa, reg_num, XT_REG_A3));
+ break;
+ case XT_REG_SPECIAL:
+ if (reg_num == XT_PC_REG_NUM_VIRTUAL) {
/* reg number of PC for debug interrupt depends on NDEBUGLEVEL */
- reg_num += xtensa->core_config->debug.irq_level;
+ reg_num = (XT_PC_REG_NUM_BASE + xtensa->core_config->debug.irq_level);
+ } else if (reg_num == xtensa_regs[XT_REG_IDX_CPENABLE].reg_num) {
+ /* CPENABLE already read/updated; don't re-read */
+ reg_fetched = false;
+ break;
}
- xtensa_queue_exec_ins(xtensa, XT_INS_RSR(reg_num, XT_REG_A3));
+ xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, reg_num, XT_REG_A3));
+ break;
+ default:
+ reg_fetched = false;
+ }
+ if (reg_fetched) {
+ xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, XT_SR_DDR, XT_REG_A3));
+ xtensa_queue_dbg_reg_read(xtensa, NARADR_DDR, regvals[i].buf);
+ if (debug_dsrs)
+ xtensa_queue_dbg_reg_read(xtensa, NARADR_DSR, dsrs[i].buf);
}
- xtensa_queue_exec_ins(xtensa, XT_INS_WSR(XT_SR_DDR, XT_REG_A3));
- xtensa_queue_dbg_reg_read(xtensa, NARADR_DDR, regvals[i]);
- if (debug_dsrs)
- xtensa_queue_dbg_reg_read(xtensa, NARADR_DSR, dsrs[i]);
}
}
/* Ok, send the whole mess to the CPU. */
res = jtag_execute_queue();
if (res != ERROR_OK) {
LOG_ERROR("Failed to fetch AR regs!");
- return res;
+ goto xtensa_fetch_all_regs_done;
}
xtensa_core_status_check(target);
if (debug_dsrs) {
/* DSR checking: follows order in which registers are requested. */
- for (unsigned int i = 0; i < XT_NUM_REGS; i++) {
- if (xtensa_reg_is_readable(xtensa_regs[i].flags, cpenable) && reg_list[i].exist &&
- (xtensa_regs[i].type == XT_REG_SPECIAL || xtensa_regs[i].type == XT_REG_USER ||
- xtensa_regs[i].type == XT_REG_FR)) {
- if (buf_get_u32(dsrs[i], 0, 32) & OCDDSR_EXECEXCEPTION) {
- LOG_ERROR("Exception reading %s!", xtensa_regs[i].name);
- return ERROR_FAIL;
+ for (unsigned int i = 0; i < reg_list_size; i++) {
+ struct xtensa_reg_desc *rlist = (i < XT_NUM_REGS) ? xtensa_regs : xtensa->optregs;
+ unsigned int ridx = (i < XT_NUM_REGS) ? i : i - XT_NUM_REGS;
+ if (xtensa_reg_is_readable(rlist[ridx].flags, cpenable) && rlist[ridx].exist &&
+ (rlist[ridx].type != XT_REG_DEBUG) &&
+ (rlist[ridx].type != XT_REG_RELGEN) &&
+ (rlist[ridx].type != XT_REG_TIE) &&
+ (rlist[ridx].type != XT_REG_OTHER)) {
+ if (buf_get_u32(dsrs[i].buf, 0, 32) & OCDDSR_EXECEXCEPTION) {
+ LOG_ERROR("Exception reading %s!", reg_list[i].name);
+ res = ERROR_FAIL;
+ goto xtensa_fetch_all_regs_done;
}
}
}
}
- if (xtensa->core_config->user_regs_num > 0 && xtensa->core_config->fetch_user_regs) {
- res = xtensa->core_config->fetch_user_regs(target);
- if (res != ERROR_OK)
- return res;
- }
-
- if (xtensa->core_config->windowed) {
+ if (xtensa->core_config->windowed)
/* We need the windowbase to decode the general addresses. */
- windowbase = buf_get_u32(regvals[XT_REG_IDX_WINDOWBASE], 0, 32);
- }
+ windowbase = buf_get_u32(regvals[XT_REG_IDX_WINDOWBASE].buf, 0, 32);
/* Decode the result and update the cache. */
- for (unsigned int i = 0; i < XT_NUM_REGS; i++) {
- if (xtensa_reg_is_readable(xtensa_regs[i].flags, cpenable) && reg_list[i].exist) {
- if (xtensa_regs[i].type == XT_REG_GENERAL) {
- /* TODO: add support for non-windowed configs */
- assert(
- xtensa->core_config->windowed &&
- "Regs fetch is not supported for non-windowed configs!");
+ for (unsigned int i = 0; i < reg_list_size; i++) {
+ struct xtensa_reg_desc *rlist = (i < XT_NUM_REGS) ? xtensa_regs : xtensa->optregs;
+ unsigned int ridx = (i < XT_NUM_REGS) ? i : i - XT_NUM_REGS;
+ if (xtensa_reg_is_readable(rlist[ridx].flags, cpenable) && rlist[ridx].exist) {
+ if ((xtensa->core_config->windowed) && (rlist[ridx].type == XT_REG_GENERAL)) {
/* The 64-value general register set is read from (windowbase) on down.
* We need to get the real register address by subtracting windowbase and
* wrapping around. */
- int realadr = xtensa_canonical_to_windowbase_offset(i, windowbase);
- buf_cpy(regvals[realadr], reg_list[i].value, reg_list[i].size);
- } else if (xtensa_regs[i].type == XT_REG_RELGEN) {
- buf_cpy(regvals[xtensa_regs[i].reg_num], reg_list[i].value, reg_list[i].size);
+ enum xtensa_reg_id realadr = xtensa_canonical_to_windowbase_offset(xtensa, i,
+ windowbase);
+ buf_cpy(regvals[realadr].buf, reg_list[i].value, reg_list[i].size);
+ } else if (rlist[ridx].type == XT_REG_RELGEN) {
+ buf_cpy(regvals[rlist[ridx].reg_num].buf, reg_list[i].value, reg_list[i].size);
+ if (xtensa_extra_debug_log) {
+ xtensa_reg_val_t regval = buf_get_u32(regvals[rlist[ridx].reg_num].buf, 0, 32);
+ LOG_DEBUG("%s = 0x%x", rlist[ridx].name, regval);
+ }
} else {
- buf_cpy(regvals[i], reg_list[i].value, reg_list[i].size);
+ xtensa_reg_val_t regval = buf_get_u32(regvals[i].buf, 0, 32);
+ bool is_dirty = (i == XT_REG_IDX_CPENABLE);
+ if (xtensa_extra_debug_log)
+ LOG_INFO("Register %s: 0x%X", reg_list[i].name, regval);
+ xtensa_reg_set(target, i, regval);
+ reg_list[i].dirty = is_dirty; /*always do this _after_ xtensa_reg_set! */
}
reg_list[i].valid = true;
} else {
- reg_list[i].valid = false;
- }
- }
- /* We have used A3 as a scratch register and we will need to write that back. */
- xtensa_mark_register_dirty(xtensa, XT_REG_IDX_A3);
- xtensa->regs_fetched = true;
-
- return ERROR_OK;
-}
-
-int xtensa_fetch_user_regs_u32(struct target *target)
-{
- struct xtensa *xtensa = target_to_xtensa(target);
- struct reg *reg_list = xtensa->core_cache->reg_list;
- xtensa_reg_val_t cpenable = 0;
- uint8_t regvals[XT_USER_REGS_NUM_MAX][sizeof(xtensa_reg_val_t)];
- uint8_t dsrs[XT_USER_REGS_NUM_MAX][sizeof(xtensa_dsr_t)];
- bool debug_dsrs = !xtensa->regs_fetched || LOG_LEVEL_IS(LOG_LVL_DEBUG);
-
- assert(xtensa->core_config->user_regs_num < XT_USER_REGS_NUM_MAX && "Too many user regs configured!");
- if (xtensa->core_config->coproc)
- cpenable = xtensa_reg_get(target, XT_REG_IDX_CPENABLE);
-
- for (unsigned int i = 0; i < xtensa->core_config->user_regs_num; i++) {
- if (!xtensa_reg_is_readable(xtensa->core_config->user_regs[i].flags, cpenable))
- continue;
- xtensa_queue_exec_ins(xtensa, XT_INS_RUR(xtensa->core_config->user_regs[i].reg_num, XT_REG_A3));
- xtensa_queue_exec_ins(xtensa, XT_INS_WSR(XT_SR_DDR, XT_REG_A3));
- xtensa_queue_dbg_reg_read(xtensa, NARADR_DDR, regvals[i]);
- if (debug_dsrs)
- xtensa_queue_dbg_reg_read(xtensa, NARADR_DSR, dsrs[i]);
- }
- /* Ok, send the whole mess to the CPU. */
- int res = jtag_execute_queue();
- if (res != ERROR_OK) {
- LOG_ERROR("Failed to fetch AR regs!");
- return res;
- }
- xtensa_core_status_check(target);
-
- if (debug_dsrs) {
- /* DSR checking: follows order in which registers are requested. */
- for (unsigned int i = 0; i < xtensa->core_config->user_regs_num; i++) {
- if (!xtensa_reg_is_readable(xtensa->core_config->user_regs[i].flags, cpenable))
- continue;
- if (buf_get_u32(dsrs[i], 0, 32) & OCDDSR_EXECEXCEPTION) {
- LOG_ERROR("Exception reading %s!", xtensa->core_config->user_regs[i].name);
- return ERROR_FAIL;
+ if ((rlist[ridx].flags & XT_REGF_MASK) == XT_REGF_NOREAD) {
+ /* Report read-only registers all-zero but valid */
+ reg_list[i].valid = true;
+ xtensa_reg_set(target, i, 0);
+ } else {
+ reg_list[i].valid = false;
}
}
}
- for (unsigned int i = 0; i < xtensa->core_config->user_regs_num; i++) {
- if (xtensa_reg_is_readable(xtensa->core_config->user_regs[i].flags, cpenable)) {
- buf_cpy(regvals[i], reg_list[XT_USR_REG_START + i].value, reg_list[XT_USR_REG_START + i].size);
- reg_list[XT_USR_REG_START + i].valid = true;
- } else {
- reg_list[XT_USR_REG_START + i].valid = false;
- }
- }
-
- /* We have used A3 as a scratch register and we will need to write that back. */
+ if (xtensa->core_config->windowed) {
+ /* We have used A3 as a scratch register.
+ * Windowed configs: restore A3's AR (XT_REG_GENERAL) and and flag for write-back.
+ */
+ enum xtensa_reg_id ar3_idx = xtensa_windowbase_offset_to_canonical(xtensa, XT_REG_IDX_A3, windowbase);
+ xtensa_reg_set(target, ar3_idx, a3);
+ xtensa_mark_register_dirty(xtensa, ar3_idx);
+
+ /* Reset scratch_ars[] on fetch. .chrval tracks AR mapping and changes w/ window */
+ sprintf(xtensa->scratch_ars[XT_AR_SCRATCH_AR3].chrval, "ar%d", ar3_idx - XT_REG_IDX_AR0);
+ enum xtensa_reg_id ar4_idx = xtensa_windowbase_offset_to_canonical(xtensa, XT_REG_IDX_A4, windowbase);
+ sprintf(xtensa->scratch_ars[XT_AR_SCRATCH_AR4].chrval, "ar%d", ar4_idx - XT_REG_IDX_AR0);
+ for (enum xtensa_ar_scratch_set_e s = 0; s < XT_AR_SCRATCH_NUM; s++)
+ xtensa->scratch_ars[s].intval = false;
+ }
+
+ /* We have used A3 (XT_REG_RELGEN) as a scratch register. Restore and flag for write-back. */
+ xtensa_reg_set(target, XT_REG_IDX_A3, a3);
xtensa_mark_register_dirty(xtensa, XT_REG_IDX_A3);
- return ERROR_OK;
+ xtensa->regs_fetched = true;
+xtensa_fetch_all_regs_done:
+ free(regvals);
+ free(dsrs);
+ return res;
}
int xtensa_get_gdb_reg_list(struct target *target,
@@ -1139,23 +1215,65 @@ int xtensa_get_gdb_reg_list(struct target *target,
enum target_register_class reg_class)
{
struct xtensa *xtensa = target_to_xtensa(target);
- unsigned int num_regs = xtensa->core_config->gdb_general_regs_num;
+ unsigned int num_regs;
- if (reg_class == REG_CLASS_ALL)
- num_regs = xtensa->regs_num;
+ if (reg_class == REG_CLASS_GENERAL) {
+ if ((xtensa->genpkt_regs_num == 0) || !xtensa->contiguous_regs_list) {
+ LOG_ERROR("reg_class %d unhandled; 'xtgregs' not found", reg_class);
+ return ERROR_FAIL;
+ }
+ num_regs = xtensa->genpkt_regs_num;
+ } else {
+ /* Determine whether to return a contiguous or sparse register map */
+ num_regs = xtensa->regmap_contiguous ? xtensa->total_regs_num : xtensa->dbregs_num;
+ }
- LOG_DEBUG("reg_class=%i, num_regs=%d", reg_class, num_regs);
+ LOG_DEBUG("reg_class=%i, num_regs=%d", (int)reg_class, num_regs);
- *reg_list = malloc(num_regs * sizeof(struct reg *));
+ *reg_list = calloc(num_regs, sizeof(struct reg *));
if (!*reg_list)
return ERROR_FAIL;
- for (unsigned int k = 0; k < num_regs; k++) {
- unsigned int reg_id = xtensa->core_config->gdb_regs_mapping[k];
- (*reg_list)[k] = &xtensa->core_cache->reg_list[reg_id];
+ *reg_list_size = num_regs;
+ if (xtensa->regmap_contiguous) {
+ assert((num_regs <= xtensa->total_regs_num) && "contiguous regmap size internal error!");
+ for (unsigned int i = 0; i < num_regs; i++)
+ (*reg_list)[i] = xtensa->contiguous_regs_list[i];
+ return ERROR_OK;
}
- *reg_list_size = num_regs;
+ for (unsigned int i = 0; i < num_regs; i++)
+ (*reg_list)[i] = (struct reg *)&xtensa->empty_regs[i];
+ unsigned int k = 0;
+ for (unsigned int i = 0; i < xtensa->core_cache->num_regs && k < num_regs; i++) {
+ if (xtensa->core_cache->reg_list[i].exist) {
+ struct xtensa_reg_desc *rlist = (i < XT_NUM_REGS) ? xtensa_regs : xtensa->optregs;
+ unsigned int ridx = (i < XT_NUM_REGS) ? i : i - XT_NUM_REGS;
+ int sparse_idx = rlist[ridx].dbreg_num;
+ if (i == XT_REG_IDX_PS) {
+ if (xtensa->eps_dbglevel_idx == 0) {
+ LOG_ERROR("eps_dbglevel_idx not set\n");
+ return ERROR_FAIL;
+ }
+ (*reg_list)[sparse_idx] = &xtensa->core_cache->reg_list[xtensa->eps_dbglevel_idx];
+ if (xtensa_extra_debug_log)
+ LOG_DEBUG("SPARSE GDB reg 0x%x getting EPS%d 0x%x",
+ sparse_idx, xtensa->core_config->debug.irq_level,
+ xtensa_reg_get_value((*reg_list)[sparse_idx]));
+ } else if (rlist[ridx].type == XT_REG_RELGEN) {
+ (*reg_list)[sparse_idx - XT_REG_IDX_ARFIRST] = &xtensa->core_cache->reg_list[i];
+ } else {
+ (*reg_list)[sparse_idx] = &xtensa->core_cache->reg_list[i];
+ }
+ if (i == XT_REG_IDX_PC)
+ /* Make a duplicate copy of PC for external access */
+ (*reg_list)[XT_PC_DBREG_NUM_BASE] = &xtensa->core_cache->reg_list[i];
+ k++;
+ }
+ }
+
+ if (k == num_regs)
+ LOG_ERROR("SPARSE GDB reg list full (size %d)", k);
return ERROR_OK;
}
@@ -1219,21 +1337,21 @@ int xtensa_prepare_resume(struct target *target,
if (address && !current) {
xtensa_reg_set(target, XT_REG_IDX_PC, address);
} else {
- xtensa_reg_val_t cause = xtensa_reg_get(target, XT_REG_IDX_DEBUGCAUSE);
- if (cause & DEBUGCAUSE_DB) {
+ uint32_t cause = xtensa_cause_get(target);
+ LOG_TARGET_DEBUG(target, "DEBUGCAUSE 0x%x (watchpoint %lu) (break %lu)",
+ cause, (cause & DEBUGCAUSE_DB), (cause & (DEBUGCAUSE_BI | DEBUGCAUSE_BN)));
+ if (cause & DEBUGCAUSE_DB)
/* We stopped due to a watchpoint. We can't just resume executing the
* instruction again because */
/* that would trigger the watchpoint again. To fix this, we single-step,
* which ignores watchpoints. */
xtensa_do_step(target, current, address, handle_breakpoints);
- }
- if (cause & (DEBUGCAUSE_BI | DEBUGCAUSE_BN)) {
+ if (cause & (DEBUGCAUSE_BI | DEBUGCAUSE_BN))
/* We stopped due to a break instruction. We can't just resume executing the
* instruction again because */
/* that would trigger the break again. To fix this, we single-step, which
* ignores break. */
xtensa_do_step(target, current, address, handle_breakpoints);
- }
}
/* Write back hw breakpoints. Current FreeRTOS SMP code can set a hw breakpoint on an
@@ -1260,7 +1378,7 @@ int xtensa_do_resume(struct target *target)
LOG_TARGET_DEBUG(target, "start");
- xtensa_queue_exec_ins(xtensa, XT_INS_RFDO);
+ xtensa_queue_exec_ins(xtensa, XT_INS_RFDO(xtensa));
int res = jtag_execute_queue();
if (res != ERROR_OK) {
LOG_TARGET_ERROR(target, "Failed to exec RFDO %d!", res);
@@ -1301,18 +1419,19 @@ int xtensa_resume(struct target *target,
static bool xtensa_pc_in_winexc(struct target *target, target_addr_t pc)
{
+ struct xtensa *xtensa = target_to_xtensa(target);
uint8_t insn_buf[XT_ISNS_SZ_MAX];
int err = xtensa_read_buffer(target, pc, sizeof(insn_buf), insn_buf);
if (err != ERROR_OK)
return false;
xtensa_insn_t insn = buf_get_u32(insn_buf, 0, 24);
- xtensa_insn_t masked = insn & XT_INS_L32E_S32E_MASK;
- if (masked == XT_INS_L32E(0, 0, 0) || masked == XT_INS_S32E(0, 0, 0))
+ xtensa_insn_t masked = insn & XT_INS_L32E_S32E_MASK(xtensa);
+ if (masked == XT_INS_L32E(xtensa, 0, 0, 0) || masked == XT_INS_S32E(xtensa, 0, 0, 0))
return true;
- masked = insn & XT_INS_RFWO_RFWU_MASK;
- if (masked == XT_INS_RFWO || masked == XT_INS_RFWU)
+ masked = insn & XT_INS_RFWO_RFWU_MASK(xtensa);
+ if (masked == XT_INS_RFWO(xtensa) || masked == XT_INS_RFWU(xtensa))
return true;
return false;
@@ -1325,7 +1444,8 @@ int xtensa_do_step(struct target *target, int current, target_addr_t address, in
const uint32_t icount_val = -2; /* ICOUNT value to load for 1 step */
xtensa_reg_val_t dbreakc[XT_WATCHPOINTS_NUM_MAX];
xtensa_reg_val_t icountlvl, cause;
- xtensa_reg_val_t oldps, newps, oldpc, cur_pc;
+ xtensa_reg_val_t oldps, oldpc, cur_pc;
+ bool ps_lowered = false;
LOG_TARGET_DEBUG(target, "current=%d, address=" TARGET_ADDR_FMT ", handle_breakpoints=%i",
current, address, handle_breakpoints);
@@ -1335,16 +1455,16 @@ int xtensa_do_step(struct target *target, int current, target_addr_t address, in
return ERROR_TARGET_NOT_HALTED;
}
- if (xtensa->core_config->debug.icount_sz != 32) {
- LOG_TARGET_WARNING(target, "stepping for ICOUNT less then 32 bits is not implemented!");
+ if (xtensa->eps_dbglevel_idx == 0) {
+ LOG_ERROR("eps_dbglevel_idx not set\n");
return ERROR_FAIL;
}
- /* Save old ps/pc */
- oldps = xtensa_reg_get(target, XT_REG_IDX_PS);
+ /* Save old ps (EPS[dbglvl] on LX), pc */
+ oldps = xtensa_reg_get(target, xtensa->eps_dbglevel_idx);
oldpc = xtensa_reg_get(target, XT_REG_IDX_PC);
- cause = xtensa_reg_get(target, XT_REG_IDX_DEBUGCAUSE);
+ cause = xtensa_cause_get(target);
LOG_TARGET_DEBUG(target, "oldps=%" PRIx32 ", oldpc=%" PRIx32 " dbg_cause=%" PRIx32 " exc_cause=%" PRIx32,
oldps,
oldpc,
@@ -1353,8 +1473,7 @@ int xtensa_do_step(struct target *target, int current, target_addr_t address, in
if (handle_breakpoints && (cause & (DEBUGCAUSE_BI | DEBUGCAUSE_BN))) {
/* handle hard-coded SW breakpoints (e.g. syscalls) */
LOG_TARGET_DEBUG(target, "Increment PC to pass break instruction...");
- xtensa_reg_set(target, XT_REG_IDX_DEBUGCAUSE, 0); /* so we don't recurse into the same routine */
- xtensa->core_cache->reg_list[XT_REG_IDX_DEBUGCAUSE].dirty = false;
+ xtensa_cause_clear(target); /* so we don't recurse into the same routine */
/* pretend that we have stepped */
if (cause & DEBUGCAUSE_BI)
xtensa_reg_set(target, XT_REG_IDX_PC, oldpc + 3); /* PC = PC+3 */
@@ -1363,13 +1482,22 @@ int xtensa_do_step(struct target *target, int current, target_addr_t address, in
return ERROR_OK;
}
- /* Xtensa has an ICOUNTLEVEL register which sets the maximum interrupt level at which the
- * instructions are to be counted while stepping.
- * For example, if we need to step by 2 instructions, and an interrupt occurs inbetween,
- * the processor will execute the interrupt, return, and halt after the 2nd instruction.
- * However, sometimes we don't want the interrupt handlers to be executed at all, while
- * stepping through the code. In this case (XT_STEPPING_ISR_OFF), PS.INTLEVEL can be raised
- * to only allow Debug and NMI interrupts.
+ /* Xtensa LX has an ICOUNTLEVEL register which sets the maximum interrupt level
+ * at which the instructions are to be counted while stepping.
+ *
+ * For example, if we need to step by 2 instructions, and an interrupt occurs
+ * in between, the processor will trigger the interrupt and halt after the 2nd
+ * instruction within the interrupt vector and/or handler.
+ *
+ * However, sometimes we don't want the interrupt handlers to be executed at all
+ * while stepping through the code. In this case (XT_STEPPING_ISR_OFF),
+ * ICOUNTLEVEL can be lowered to the executing code's (level + 1) to prevent ISR
+ * code from being counted during stepping. Note that C exception handlers must
+ * run at level 0 and hence will be counted and stepped into, should one occur.
+ *
+ * TODO: Certain instructions should never be single-stepped and should instead
+ * be emulated (per DUG): RSIL >= DBGLEVEL, RSR/WSR [ICOUNT|ICOUNTLEVEL], and
+ * RFI >= DBGLEVEL.
*/
if (xtensa->stepping_isr_mode == XT_STEPPING_ISR_OFF) {
if (!xtensa->core_config->high_irq.enabled) {
@@ -1378,18 +1506,11 @@ int xtensa_do_step(struct target *target, int current, target_addr_t address, in
"disabling IRQs while stepping is not implemented w/o high prio IRQs option!");
return ERROR_FAIL;
}
- /* Mask all interrupts below Debug, i.e. PS.INTLEVEL = DEBUGLEVEL - 1 */
- xtensa_reg_val_t temp_ps = (oldps & ~0xF) | (xtensa->core_config->debug.irq_level - 1);
- xtensa_reg_set(target, XT_REG_IDX_PS, temp_ps);
+ /* Update ICOUNTLEVEL accordingly */
+ icountlvl = MIN((oldps & 0xF) + 1, xtensa->core_config->debug.irq_level);
+ } else {
+ icountlvl = xtensa->core_config->debug.irq_level;
}
- /* Regardless of ISRs masking mode we need to count instructions at any CINTLEVEL during step.
- So set `icountlvl` to DEBUGLEVEL.
- If ISRs are masked they are disabled in PS (see above), so having `icountlvl` set to DEBUGLEVEL
- will allow to step through any type of the code, e.g. 'high int level' ISR.
- If ISRs are not masked With `icountlvl` set to DEBUGLEVEL, we can step into any ISR
- which can happen (enabled in PS).
- */
- icountlvl = xtensa->core_config->debug.irq_level;
if (cause & DEBUGCAUSE_DB) {
/* We stopped due to a watchpoint. We can't just resume executing the instruction again because
@@ -1398,21 +1519,27 @@ int xtensa_do_step(struct target *target, int current, target_addr_t address, in
LOG_TARGET_DEBUG(
target,
"Single-stepping to get past instruction that triggered the watchpoint...");
- xtensa_reg_set(target, XT_REG_IDX_DEBUGCAUSE, 0); /*so we don't recurse into
- * the same routine */
- xtensa->core_cache->reg_list[XT_REG_IDX_DEBUGCAUSE].dirty = false;
- /*Save all DBREAKCx registers and set to 0 to disable watchpoints */
+ xtensa_cause_clear(target); /* so we don't recurse into the same routine */
+ /* Save all DBREAKCx registers and set to 0 to disable watchpoints */
for (unsigned int slot = 0; slot < xtensa->core_config->debug.dbreaks_num; slot++) {
dbreakc[slot] = xtensa_reg_get(target, XT_REG_IDX_DBREAKC0 + slot);
xtensa_reg_set(target, XT_REG_IDX_DBREAKC0 + slot, 0);
}
}
- if (!handle_breakpoints && (cause & (DEBUGCAUSE_BI | DEBUGCAUSE_BN))) {
+ if (!handle_breakpoints && (cause & (DEBUGCAUSE_BI | DEBUGCAUSE_BN)))
/* handle normal SW breakpoint */
- xtensa_reg_set(target, XT_REG_IDX_DEBUGCAUSE, 0); /*so we don't recurse into
- * the same routine */
- xtensa->core_cache->reg_list[XT_REG_IDX_DEBUGCAUSE].dirty = false;
+ xtensa_cause_clear(target); /* so we don't recurse into the same routine */
+ if ((oldps & 0xf) >= icountlvl) {
+ /* Lower interrupt level to allow stepping, but flag eps[dbglvl] to be restored */
+ ps_lowered = true;
+ uint32_t newps = (oldps & ~0xf) | (icountlvl - 1);
+ xtensa_reg_set(target, xtensa->eps_dbglevel_idx, newps);
+ LOG_TARGET_DEBUG(target,
+ "Lowering PS.INTLEVEL to allow stepping: %s <- 0x%08" PRIx32 " (was 0x%08" PRIx32 ")",
+ xtensa->core_cache->reg_list[xtensa->eps_dbglevel_idx].name,
+ newps,
+ oldps);
}
do {
xtensa_reg_set(target, XT_REG_IDX_ICOUNTLEVEL, icountlvl);
@@ -1467,7 +1594,7 @@ int xtensa_do_step(struct target *target, int current, target_addr_t address, in
"cur_ps=%" PRIx32 ", cur_pc=%" PRIx32 " dbg_cause=%" PRIx32 " exc_cause=%" PRIx32,
xtensa_reg_get(target, XT_REG_IDX_PS),
cur_pc,
- xtensa_reg_get(target, XT_REG_IDX_DEBUGCAUSE),
+ xtensa_cause_get(target),
xtensa_reg_get(target, XT_REG_IDX_EXCCAUSE));
/* Do not step into WindowOverflow if ISRs are masked.
@@ -1500,12 +1627,11 @@ int xtensa_do_step(struct target *target, int current, target_addr_t address, in
}
/* Restore int level */
- /* TODO: Theoretically, this can mess up stepping over an instruction that modifies
- * ps.intlevel by itself. TODO: Look into this. */
- if (xtensa->stepping_isr_mode == XT_STEPPING_ISR_OFF) {
- newps = xtensa_reg_get(target, XT_REG_IDX_PS);
- newps = (newps & ~0xF) | (oldps & 0xf);
- xtensa_reg_set(target, XT_REG_IDX_PS, newps);
+ if (ps_lowered) {
+ LOG_DEBUG("Restoring %s after stepping: 0x%08" PRIx32,
+ xtensa->core_cache->reg_list[xtensa->eps_dbglevel_idx].name,
+ oldps);
+ xtensa_reg_set(target, xtensa->eps_dbglevel_idx, oldps);
}
/* write ICOUNTLEVEL back to zero */
@@ -1553,7 +1679,7 @@ static inline target_addr_t xtensa_get_overlap_size(target_addr_t r1_start,
}
/**
- * Check if the address gets to memory regions, and it's access mode
+ * Check if the address gets to memory regions, and its access mode
*/
static bool xtensa_memory_op_validate_range(struct xtensa *xtensa, target_addr_t address, size_t size, int access)
{
@@ -1584,6 +1710,7 @@ int xtensa_read_memory(struct target *target, target_addr_t address, uint32_t si
target_addr_t addrend_al = ALIGN_UP(address + size * count, 4);
target_addr_t adr = addrstart_al;
uint8_t *albuff;
+ bool bswap = xtensa->target->endianness == TARGET_BIG_ENDIAN;
if (target->state != TARGET_HALTED) {
LOG_TARGET_WARNING(target, "target not halted");
@@ -1613,19 +1740,48 @@ int xtensa_read_memory(struct target *target, target_addr_t address, uint32_t si
xtensa_mark_register_dirty(xtensa, XT_REG_IDX_A3);
/* Write start address to A3 */
xtensa_queue_dbg_reg_write(xtensa, NARADR_DDR, addrstart_al);
- xtensa_queue_exec_ins(xtensa, XT_INS_RSR(XT_SR_DDR, XT_REG_A3));
+ xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3));
/* Now we can safely read data from addrstart_al up to addrend_al into albuff */
- for (unsigned int i = 0; adr != addrend_al; i += sizeof(uint32_t), adr += sizeof(uint32_t)) {
- xtensa_queue_exec_ins(xtensa, XT_INS_LDDR32P(XT_REG_A3));
- xtensa_queue_dbg_reg_read(xtensa, NARADR_DDR, &albuff[i]);
+ if (xtensa->probe_lsddr32p != 0) {
+ xtensa_queue_exec_ins(xtensa, XT_INS_LDDR32P(xtensa, XT_REG_A3));
+ for (unsigned int i = 0; adr != addrend_al; i += sizeof(uint32_t), adr += sizeof(uint32_t))
+ xtensa_queue_dbg_reg_read(xtensa,
+ (adr + sizeof(uint32_t) == addrend_al) ? NARADR_DDR : NARADR_DDREXEC,
+ &albuff[i]);
+ } else {
+ xtensa_mark_register_dirty(xtensa, XT_REG_IDX_A4);
+ for (unsigned int i = 0; adr != addrend_al; i += sizeof(uint32_t), adr += sizeof(uint32_t)) {
+ xtensa_queue_exec_ins(xtensa, XT_INS_L32I(xtensa, XT_REG_A3, XT_REG_A4, 0));
+ xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, XT_SR_DDR, XT_REG_A4));
+ xtensa_queue_dbg_reg_read(xtensa, NARADR_DDR, &albuff[i]);
+ xtensa_queue_dbg_reg_write(xtensa, NARADR_DDR, adr + sizeof(uint32_t));
+ xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3));
+ }
}
int res = jtag_execute_queue();
- if (res == ERROR_OK)
+ if (res == ERROR_OK) {
+ bool prev_suppress = xtensa->suppress_dsr_errors;
+ xtensa->suppress_dsr_errors = true;
res = xtensa_core_status_check(target);
- if (res != ERROR_OK)
- LOG_TARGET_WARNING(target, "Failed reading %d bytes at address " TARGET_ADDR_FMT,
- count * size, address);
+ if (xtensa->probe_lsddr32p == -1)
+ xtensa->probe_lsddr32p = 1;
+ xtensa->suppress_dsr_errors = prev_suppress;
+ }
+ if (res != ERROR_OK) {
+ if (xtensa->probe_lsddr32p != 0) {
+ /* Disable fast memory access instructions and retry before reporting an error */
+ LOG_TARGET_INFO(target, "Disabling LDDR32.P/SDDR32.P");
+ xtensa->probe_lsddr32p = 0;
+ res = xtensa_read_memory(target, address, size, count, buffer);
+ bswap = false;
+ } else {
+ LOG_TARGET_WARNING(target, "Failed reading %d bytes at address "TARGET_ADDR_FMT,
+ count * size, address);
+ }
+ }
+ if (bswap)
+ buf_bswap32(albuff, albuff, addrend_al - addrstart_al);
if (albuff != buffer) {
memcpy(buffer, albuff + (address & 3), (size * count));
free(albuff);
@@ -1656,6 +1812,7 @@ int xtensa_write_memory(struct target *target,
target_addr_t adr = addrstart_al;
int res;
uint8_t *albuff;
+ bool fill_head_tail = false;
if (target->state != TARGET_HALTED) {
LOG_TARGET_WARNING(target, "target not halted");
@@ -1674,33 +1831,48 @@ int xtensa_write_memory(struct target *target,
/* Allocate a temporary buffer to put the aligned bytes in, if needed. */
if (addrstart_al == address && addrend_al == address + (size * count)) {
- /* We discard the const here because albuff can also be non-const */
- albuff = (uint8_t *)buffer;
+ if (xtensa->target->endianness == TARGET_BIG_ENDIAN)
+ /* Need a buffer for byte-swapping */
+ albuff = malloc(addrend_al - addrstart_al);
+ else
+ /* We discard the const here because albuff can also be non-const */
+ albuff = (uint8_t *)buffer;
} else {
+ fill_head_tail = true;
albuff = malloc(addrend_al - addrstart_al);
- if (!albuff) {
- LOG_TARGET_ERROR(target, "Out of memory allocating %" TARGET_PRIdADDR " bytes!",
- addrend_al - addrstart_al);
- return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
- }
+ }
+ if (!albuff) {
+ LOG_TARGET_ERROR(target, "Out of memory allocating %" TARGET_PRIdADDR " bytes!",
+ addrend_al - addrstart_al);
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
}
/* We're going to use A3 here */
xtensa_mark_register_dirty(xtensa, XT_REG_IDX_A3);
/* If we're using a temp aligned buffer, we need to fill the head and/or tail bit of it. */
- if (albuff != buffer) {
+ if (fill_head_tail) {
/* See if we need to read the first and/or last word. */
if (address & 3) {
xtensa_queue_dbg_reg_write(xtensa, NARADR_DDR, addrstart_al);
- xtensa_queue_exec_ins(xtensa, XT_INS_RSR(XT_SR_DDR, XT_REG_A3));
- xtensa_queue_exec_ins(xtensa, XT_INS_LDDR32P(XT_REG_A3));
+ xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3));
+ if (xtensa->probe_lsddr32p == 1) {
+ xtensa_queue_exec_ins(xtensa, XT_INS_LDDR32P(xtensa, XT_REG_A3));
+ } else {
+ xtensa_queue_exec_ins(xtensa, XT_INS_L32I(xtensa, XT_REG_A3, XT_REG_A3, 0));
+ xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, XT_SR_DDR, XT_REG_A3));
+ }
xtensa_queue_dbg_reg_read(xtensa, NARADR_DDR, &albuff[0]);
}
if ((address + (size * count)) & 3) {
xtensa_queue_dbg_reg_write(xtensa, NARADR_DDR, addrend_al - 4);
- xtensa_queue_exec_ins(xtensa, XT_INS_RSR(XT_SR_DDR, XT_REG_A3));
- xtensa_queue_exec_ins(xtensa, XT_INS_LDDR32P(XT_REG_A3));
+ xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3));
+ if (xtensa->probe_lsddr32p == 1) {
+ xtensa_queue_exec_ins(xtensa, XT_INS_LDDR32P(xtensa, XT_REG_A3));
+ } else {
+ xtensa_queue_exec_ins(xtensa, XT_INS_L32I(xtensa, XT_REG_A3, XT_REG_A3, 0));
+ xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, XT_SR_DDR, XT_REG_A3));
+ }
xtensa_queue_dbg_reg_read(xtensa, NARADR_DDR,
&albuff[addrend_al - addrstart_al - 4]);
}
@@ -1713,24 +1885,110 @@ int xtensa_write_memory(struct target *target,
return res;
}
xtensa_core_status_check(target);
- /* Copy data to be written into the aligned buffer */
+ if (xtensa->target->endianness == TARGET_BIG_ENDIAN) {
+ bool swapped_w0 = false;
+ if (address & 3) {
+ buf_bswap32(&albuff[0], &albuff[0], 4);
+ swapped_w0 = true;
+ }
+ if ((address + (size * count)) & 3) {
+ if ((addrend_al - addrstart_al - 4 == 0) && swapped_w0) {
+ /* Don't double-swap if buffer start/end are within the same word */
+ } else {
+ buf_bswap32(&albuff[addrend_al - addrstart_al - 4],
+ &albuff[addrend_al - addrstart_al - 4], 4);
+ }
+ }
+ }
+ /* Copy data to be written into the aligned buffer (in host-endianness) */
memcpy(&albuff[address & 3], buffer, size * count);
/* Now we can write albuff in aligned uint32s. */
}
+ if (xtensa->target->endianness == TARGET_BIG_ENDIAN)
+ buf_bswap32(albuff, fill_head_tail ? albuff : buffer, addrend_al - addrstart_al);
+
/* Write start address to A3 */
xtensa_queue_dbg_reg_write(xtensa, NARADR_DDR, addrstart_al);
- xtensa_queue_exec_ins(xtensa, XT_INS_RSR(XT_SR_DDR, XT_REG_A3));
+ xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3));
/* Write the aligned buffer */
- for (unsigned int i = 0; adr != addrend_al; i += sizeof(uint32_t), adr += sizeof(uint32_t)) {
- xtensa_queue_dbg_reg_write(xtensa, NARADR_DDR, buf_get_u32(&albuff[i], 0, 32));
- xtensa_queue_exec_ins(xtensa, XT_INS_SDDR32P(XT_REG_A3));
+ if (xtensa->probe_lsddr32p != 0) {
+ for (unsigned int i = 0; adr != addrend_al; i += sizeof(uint32_t), adr += sizeof(uint32_t)) {
+ if (i == 0) {
+ xtensa_queue_dbg_reg_write(xtensa, NARADR_DDR, buf_get_u32(&albuff[i], 0, 32));
+ xtensa_queue_exec_ins(xtensa, XT_INS_SDDR32P(xtensa, XT_REG_A3));
+ } else {
+ xtensa_queue_dbg_reg_write(xtensa, NARADR_DDREXEC, buf_get_u32(&albuff[i], 0, 32));
+ }
+ }
+ } else {
+ xtensa_mark_register_dirty(xtensa, XT_REG_IDX_A4);
+ for (unsigned int i = 0; adr != addrend_al; i += sizeof(uint32_t), adr += sizeof(uint32_t)) {
+ xtensa_queue_dbg_reg_write(xtensa, NARADR_DDR, buf_get_u32(&albuff[i], 0, 32));
+ xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A4));
+ xtensa_queue_exec_ins(xtensa, XT_INS_S32I(xtensa, XT_REG_A3, XT_REG_A4, 0));
+ xtensa_queue_dbg_reg_write(xtensa, NARADR_DDR, adr + sizeof(uint32_t));
+ xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3));
+ }
}
+
res = jtag_execute_queue();
- if (res == ERROR_OK)
+ if (res == ERROR_OK) {
+ bool prev_suppress = xtensa->suppress_dsr_errors;
+ xtensa->suppress_dsr_errors = true;
res = xtensa_core_status_check(target);
- if (res != ERROR_OK)
- LOG_TARGET_WARNING(target, "Failed writing %d bytes at address " TARGET_ADDR_FMT, count * size, address);
+ if (xtensa->probe_lsddr32p == -1)
+ xtensa->probe_lsddr32p = 1;
+ xtensa->suppress_dsr_errors = prev_suppress;
+ }
+ if (res != ERROR_OK) {
+ if (xtensa->probe_lsddr32p != 0) {
+ /* Disable fast memory access instructions and retry before reporting an error */
+ LOG_TARGET_INFO(target, "Disabling LDDR32.P/SDDR32.P");
+ xtensa->probe_lsddr32p = 0;
+ res = xtensa_write_memory(target, address, size, count, buffer);
+ } else {
+ LOG_TARGET_WARNING(target, "Failed writing %d bytes at address "TARGET_ADDR_FMT,
+ count * size, address);
+ }
+ } else {
+ /* Invalidate ICACHE, writeback DCACHE if present */
+ uint32_t issue_ihi = xtensa_is_icacheable(xtensa, address);
+ uint32_t issue_dhwb = xtensa_is_dcacheable(xtensa, address);
+ if (issue_ihi || issue_dhwb) {
+ uint32_t ilinesize = issue_ihi ? xtensa->core_config->icache.line_size : UINT32_MAX;
+ uint32_t dlinesize = issue_dhwb ? xtensa->core_config->dcache.line_size : UINT32_MAX;
+ uint32_t linesize = MIN(ilinesize, dlinesize);
+ uint32_t off = 0;
+ adr = addrstart_al;
+
+ while ((adr + off) < addrend_al) {
+ if (off == 0) {
+ /* Write start address to A3 */
+ xtensa_queue_dbg_reg_write(xtensa, NARADR_DDR, adr);
+ xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3));
+ }
+ if (issue_ihi)
+ xtensa_queue_exec_ins(xtensa, XT_INS_IHI(xtensa, XT_REG_A3, off));
+ if (issue_dhwb)
+ xtensa_queue_exec_ins(xtensa, XT_INS_DHWBI(xtensa, XT_REG_A3, off));
+ off += linesize;
+ if (off > 1020) {
+ /* IHI, DHWB have 8-bit immediate operands (0..1020) */
+ adr += off;
+ off = 0;
+ }
+ }
+
+ /* Execute cache WB/INV instructions */
+ res = jtag_execute_queue();
+ xtensa_core_status_check(target);
+ if (res != ERROR_OK)
+ LOG_TARGET_ERROR(target,
+ "Error issuing cache writeback/invaldate instruction(s): %d",
+ res);
+ }
+ }
if (albuff != buffer)
free(albuff);
@@ -1754,6 +2012,11 @@ int xtensa_poll(struct target *target)
struct xtensa *xtensa = target_to_xtensa(target);
int res = xtensa_dm_power_status_read(&xtensa->dbg_mod, PWRSTAT_DEBUGWASRESET | PWRSTAT_COREWASRESET);
+ if (xtensa->dbg_mod.power_status.stat != xtensa->dbg_mod.power_status.stath)
+ LOG_TARGET_DEBUG(target, "PWRSTAT: read 0x%08" PRIx32 ", clear 0x%08lx, reread 0x%08" PRIx32,
+ xtensa->dbg_mod.power_status.stat,
+ PWRSTAT_DEBUGWASRESET | PWRSTAT_COREWASRESET,
+ xtensa->dbg_mod.power_status.stath);
if (res != ERROR_OK)
return res;
@@ -1771,9 +2034,15 @@ int xtensa_poll(struct target *target)
if (res != ERROR_OK)
return res;
+ uint32_t prev_dsr = xtensa->dbg_mod.core_status.dsr;
res = xtensa_dm_core_status_read(&xtensa->dbg_mod);
if (res != ERROR_OK)
return res;
+ if (prev_dsr != xtensa->dbg_mod.core_status.dsr)
+ LOG_TARGET_DEBUG(target,
+ "DSR has changed: was 0x%08" PRIx32 " now 0x%08" PRIx32,
+ prev_dsr,
+ xtensa->dbg_mod.core_status.dsr);
if (xtensa->dbg_mod.power_status.stath & PWRSTAT_COREWASRESET) {
/* if RESET state is persitent */
target->state = TARGET_RESET;
@@ -1797,7 +2066,7 @@ int xtensa_poll(struct target *target)
* priorities: watchpoint == breakpoint > single step > debug interrupt. */
/* Watchpoint and breakpoint events at the same time results in special
* debug reason: DBG_REASON_WPTANDBKPT. */
- xtensa_reg_val_t halt_cause = xtensa_reg_get(target, XT_REG_IDX_DEBUGCAUSE);
+ uint32_t halt_cause = xtensa_cause_get(target);
/* TODO: Add handling of DBG_REASON_EXC_CATCH */
if (halt_cause & DEBUGCAUSE_IC)
target->debug_reason = DBG_REASON_SINGLESTEP;
@@ -1809,7 +2078,8 @@ int xtensa_poll(struct target *target)
} else if (halt_cause & DEBUGCAUSE_DB) {
target->debug_reason = DBG_REASON_WATCHPOINT;
}
- LOG_TARGET_DEBUG(target, "Target halted, pc=0x%08" PRIX32 ", debug_reason=%08x, oldstate=%08x",
+ LOG_TARGET_DEBUG(target, "Target halted, pc=0x%08" PRIx32
+ ", debug_reason=%08" PRIx32 ", oldstate=%08" PRIx32,
xtensa_reg_get(target, XT_REG_IDX_PC),
target->debug_reason,
oldstate);
@@ -1817,8 +2087,6 @@ int xtensa_poll(struct target *target)
halt_cause,
xtensa_reg_get(target, XT_REG_IDX_EXCCAUSE),
xtensa->dbg_mod.core_status.dsr);
- LOG_TARGET_INFO(target, "Target halted, PC=0x%08" PRIX32 ", debug_reason=%08x",
- xtensa_reg_get(target, XT_REG_IDX_PC), target->debug_reason);
xtensa_dm_core_status_clear(
&xtensa->dbg_mod,
OCDDSR_DEBUGPENDBREAK | OCDDSR_DEBUGINTBREAK | OCDDSR_DEBUGPENDTRAX |
@@ -1852,25 +2120,101 @@ int xtensa_poll(struct target *target)
return ERROR_OK;
}
+static int xtensa_update_instruction(struct target *target, target_addr_t address, uint32_t size, const uint8_t *buffer)
+{
+ struct xtensa *xtensa = target_to_xtensa(target);
+ unsigned int issue_ihi = xtensa_is_icacheable(xtensa, address);
+ unsigned int issue_dhwbi = xtensa_is_dcacheable(xtensa, address);
+ uint32_t icache_line_size = issue_ihi ? xtensa->core_config->icache.line_size : UINT32_MAX;
+ uint32_t dcache_line_size = issue_dhwbi ? xtensa->core_config->dcache.line_size : UINT32_MAX;
+ unsigned int same_ic_line = ((address & (icache_line_size - 1)) + size) <= icache_line_size;
+ unsigned int same_dc_line = ((address & (dcache_line_size - 1)) + size) <= dcache_line_size;
+ int ret;
+
+ if (size > icache_line_size)
+ return ERROR_FAIL;
+
+ if (issue_ihi || issue_dhwbi) {
+ /* We're going to use A3 here */
+ xtensa_mark_register_dirty(xtensa, XT_REG_IDX_A3);
+
+ /* Write start address to A3 and invalidate */
+ xtensa_queue_dbg_reg_write(xtensa, NARADR_DDR, address);
+ xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3));
+ LOG_TARGET_DEBUG(target, "DHWBI, IHI for address "TARGET_ADDR_FMT, address);
+ if (issue_dhwbi) {
+ xtensa_queue_exec_ins(xtensa, XT_INS_DHWBI(xtensa, XT_REG_A3, 0));
+ if (!same_dc_line) {
+ LOG_TARGET_DEBUG(target,
+ "DHWBI second dcache line for address "TARGET_ADDR_FMT,
+ address + 4);
+ xtensa_queue_exec_ins(xtensa, XT_INS_DHWBI(xtensa, XT_REG_A3, 4));
+ }
+ }
+ if (issue_ihi) {
+ xtensa_queue_exec_ins(xtensa, XT_INS_IHI(xtensa, XT_REG_A3, 0));
+ if (!same_ic_line) {
+ LOG_TARGET_DEBUG(target,
+ "IHI second icache line for address "TARGET_ADDR_FMT,
+ address + 4);
+ xtensa_queue_exec_ins(xtensa, XT_INS_IHI(xtensa, XT_REG_A3, 4));
+ }
+ }
+
+ /* Execute invalidate instructions */
+ ret = jtag_execute_queue();
+ xtensa_core_status_check(target);
+ if (ret != ERROR_OK) {
+ LOG_ERROR("Error issuing cache invaldate instruction(s): %d", ret);
+ return ret;
+ }
+ }
+
+ /* Write new instructions to memory */
+ ret = target_write_buffer(target, address, size, buffer);
+ if (ret != ERROR_OK) {
+ LOG_TARGET_ERROR(target, "Error writing instruction to memory: %d", ret);
+ return ret;
+ }
+
+ if (issue_dhwbi) {
+ /* Flush dcache so instruction propagates. A3 may be corrupted during memory write */
+ xtensa_queue_dbg_reg_write(xtensa, NARADR_DDR, address);
+ xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3));
+ xtensa_queue_exec_ins(xtensa, XT_INS_DHWB(xtensa, XT_REG_A3, 0));
+ LOG_DEBUG("DHWB dcache line for address "TARGET_ADDR_FMT, address);
+ if (!same_dc_line) {
+ LOG_TARGET_DEBUG(target, "DHWB second dcache line for address "TARGET_ADDR_FMT, address + 4);
+ xtensa_queue_exec_ins(xtensa, XT_INS_DHWB(xtensa, XT_REG_A3, 4));
+ }
+
+ /* Execute invalidate instructions */
+ ret = jtag_execute_queue();
+ xtensa_core_status_check(target);
+ }
+
+ /* TODO: Handle L2 cache if present */
+ return ret;
+}
+
static int xtensa_sw_breakpoint_add(struct target *target,
struct breakpoint *breakpoint,
struct xtensa_sw_breakpoint *sw_bp)
{
+ struct xtensa *xtensa = target_to_xtensa(target);
int ret = target_read_buffer(target, breakpoint->address, XT_ISNS_SZ_MAX, sw_bp->insn);
if (ret != ERROR_OK) {
LOG_TARGET_ERROR(target, "Failed to read original instruction (%d)!", ret);
return ret;
}
- sw_bp->insn_sz = xtensa_insn_size_get(buf_get_u32(sw_bp->insn, 0, 24));
+ sw_bp->insn_sz = MIN(XT_ISNS_SZ_MAX, breakpoint->length);
sw_bp->oocd_bp = breakpoint;
- uint32_t break_insn = sw_bp->insn_sz == XT_ISNS_SZ_MAX ? XT_INS_BREAK(0, 0) : XT_INS_BREAKN(0);
- /* convert to target endianness */
- uint8_t break_insn_buff[4];
- target_buffer_set_u32(target, break_insn_buff, break_insn);
+ uint32_t break_insn = sw_bp->insn_sz == XT_ISNS_SZ_MAX ? XT_INS_BREAK(xtensa, 0, 0) : XT_INS_BREAKN(xtensa, 0);
- ret = target_write_buffer(target, breakpoint->address, sw_bp->insn_sz, break_insn_buff);
+ /* Underlying memory write will convert instruction endianness, don't do that here */
+ ret = xtensa_update_instruction(target, breakpoint->address, sw_bp->insn_sz, (uint8_t *)&break_insn);
if (ret != ERROR_OK) {
LOG_TARGET_ERROR(target, "Failed to write breakpoint instruction (%d)!", ret);
return ret;
@@ -1881,9 +2225,9 @@ static int xtensa_sw_breakpoint_add(struct target *target,
static int xtensa_sw_breakpoint_remove(struct target *target, struct xtensa_sw_breakpoint *sw_bp)
{
- int ret = target_write_buffer(target, sw_bp->oocd_bp->address, sw_bp->insn_sz, sw_bp->insn);
+ int ret = xtensa_update_instruction(target, sw_bp->oocd_bp->address, sw_bp->insn_sz, sw_bp->insn);
if (ret != ERROR_OK) {
- LOG_TARGET_ERROR(target, "Failed to read insn (%d)!", ret);
+ LOG_TARGET_ERROR(target, "Failed to write insn (%d)!", ret);
return ret;
}
sw_bp->oocd_bp = NULL;
@@ -1927,7 +2271,8 @@ int xtensa_breakpoint_add(struct target *target, struct breakpoint *breakpoint)
xtensa->hw_brps[slot] = breakpoint;
/* We will actually write the breakpoints when we resume the target. */
- LOG_TARGET_DEBUG(target, "placed HW breakpoint @ " TARGET_ADDR_FMT,
+ LOG_TARGET_DEBUG(target, "placed HW breakpoint %u @ " TARGET_ADDR_FMT,
+ slot,
breakpoint->address);
return ERROR_OK;
@@ -2049,6 +2394,12 @@ static int xtensa_build_reg_cache(struct target *target)
{
struct xtensa *xtensa = target_to_xtensa(target);
struct reg_cache **cache_p = register_get_last_cache_p(&target->reg_cache);
+ unsigned int last_dbreg_num = 0;
+
+ if (xtensa->core_regs_num + xtensa->num_optregs != xtensa->total_regs_num)
+ LOG_TARGET_WARNING(target, "Register count MISMATCH: %d core regs, %d extended regs; %d expected",
+ xtensa->core_regs_num, xtensa->num_optregs, xtensa->total_regs_num);
+
struct reg_cache *reg_cache = calloc(1, sizeof(struct reg_cache));
if (!reg_cache) {
@@ -2057,86 +2408,101 @@ static int xtensa_build_reg_cache(struct target *target)
}
reg_cache->name = "Xtensa registers";
reg_cache->next = NULL;
- reg_cache->num_regs = XT_NUM_REGS + xtensa->core_config->user_regs_num;
/* Init reglist */
- struct reg *reg_list = calloc(reg_cache->num_regs, sizeof(struct reg));
+ unsigned int reg_list_size = XT_NUM_REGS + xtensa->num_optregs;
+ struct reg *reg_list = calloc(reg_list_size, sizeof(struct reg));
if (!reg_list) {
LOG_ERROR("Failed to alloc reg list!");
goto fail;
}
- xtensa->regs_num = 0;
-
- for (unsigned int i = 0; i < XT_NUM_REGS; i++) {
- reg_list[i].exist = false;
- if (xtensa_regs[i].type == XT_REG_USER) {
- if (xtensa_user_reg_exists(xtensa, i))
- reg_list[i].exist = true;
- else
- LOG_DEBUG("User reg '%s' (%d) does not exist", xtensa_regs[i].name, i);
- } else if (xtensa_regs[i].type == XT_REG_FR) {
- if (xtensa_fp_reg_exists(xtensa, i))
- reg_list[i].exist = true;
- else
- LOG_DEBUG("FP reg '%s' (%d) does not exist", xtensa_regs[i].name, i);
- } else if (xtensa_regs[i].type == XT_REG_SPECIAL) {
- if (xtensa_special_reg_exists(xtensa, i))
- reg_list[i].exist = true;
- else
- LOG_DEBUG("Special reg '%s' (%d) does not exist", xtensa_regs[i].name, i);
- } else {
- if (xtensa_regular_reg_exists(xtensa, i))
- reg_list[i].exist = true;
- else
- LOG_DEBUG("Regular reg '%s' (%d) does not exist", xtensa_regs[i].name, i);
- }
- reg_list[i].name = xtensa_regs[i].name;
- reg_list[i].size = 32;
- reg_list[i].value = calloc(1, 4 /*XT_REG_LEN*/);/* make Clang Static Analyzer happy */
- if (!reg_list[i].value) {
- LOG_ERROR("Failed to alloc reg list value!");
+ xtensa->dbregs_num = 0;
+ unsigned int didx = 0;
+ for (unsigned int whichlist = 0; whichlist < 2; whichlist++) {
+ struct xtensa_reg_desc *rlist = (whichlist == 0) ? xtensa_regs : xtensa->optregs;
+ unsigned int listsize = (whichlist == 0) ? XT_NUM_REGS : xtensa->num_optregs;
+ for (unsigned int i = 0; i < listsize; i++, didx++) {
+ reg_list[didx].exist = rlist[i].exist;
+ reg_list[didx].name = rlist[i].name;
+ reg_list[didx].size = 32;
+ reg_list[didx].value = calloc(1, 4 /*XT_REG_LEN*/); /* make Clang Static Analyzer happy */
+ if (!reg_list[didx].value) {
+ LOG_ERROR("Failed to alloc reg list value!");
+ goto fail;
+ }
+ reg_list[didx].dirty = false;
+ reg_list[didx].valid = false;
+ reg_list[didx].type = &xtensa_reg_type;
+ reg_list[didx].arch_info = xtensa;
+ if (rlist[i].exist && (rlist[i].dbreg_num > last_dbreg_num))
+ last_dbreg_num = rlist[i].dbreg_num;
+
+ if (xtensa_extra_debug_log) {
+ LOG_TARGET_DEBUG(target,
+ "POPULATE %-16s list %d exist %d, idx %d, type %d, dbreg_num 0x%04x",
+ reg_list[didx].name,
+ whichlist,
+ reg_list[didx].exist,
+ didx,
+ rlist[i].type,
+ rlist[i].dbreg_num);
+ }
+ }
+ }
+
+ xtensa->dbregs_num = last_dbreg_num + 1;
+ reg_cache->reg_list = reg_list;
+ reg_cache->num_regs = reg_list_size;
+
+ LOG_TARGET_DEBUG(target, "xtensa->total_regs_num %d reg_list_size %d xtensa->dbregs_num %d",
+ xtensa->total_regs_num, reg_list_size, xtensa->dbregs_num);
+
+ /* Construct empty-register list for handling unknown register requests */
+ xtensa->empty_regs = calloc(xtensa->dbregs_num, sizeof(struct reg));
+ if (!xtensa->empty_regs) {
+ LOG_TARGET_ERROR(target, "ERROR: Out of memory");
+ goto fail;
+ }
+ for (unsigned int i = 0; i < xtensa->dbregs_num; i++) {
+ xtensa->empty_regs[i].name = calloc(8, sizeof(char));
+ if (!xtensa->empty_regs[i].name) {
+ LOG_TARGET_ERROR(target, "ERROR: Out of memory");
goto fail;
}
- reg_list[i].dirty = false;
- reg_list[i].valid = false;
- reg_list[i].type = &xtensa_reg_type;
- reg_list[i].arch_info = xtensa;
- if (reg_list[i].exist)
- xtensa->regs_num++;
- }
- for (unsigned int i = 0; i < xtensa->core_config->user_regs_num; i++) {
- reg_list[XT_USR_REG_START + i].exist = true;
- reg_list[XT_USR_REG_START + i].name = xtensa->core_config->user_regs[i].name;
- reg_list[XT_USR_REG_START + i].size = xtensa->core_config->user_regs[i].size;
- reg_list[XT_USR_REG_START + i].value = calloc(1, reg_list[XT_USR_REG_START + i].size / 8);
- if (!reg_list[XT_USR_REG_START + i].value) {
- LOG_ERROR("Failed to alloc user reg list value!");
+ sprintf((char *)xtensa->empty_regs[i].name, "?0x%04x", i);
+ xtensa->empty_regs[i].size = 32;
+ xtensa->empty_regs[i].type = &xtensa_reg_type;
+ xtensa->empty_regs[i].value = calloc(1, 4 /*XT_REG_LEN*/); /* make Clang Static Analyzer happy */
+ if (!xtensa->empty_regs[i].value) {
+ LOG_ERROR("Failed to alloc empty reg list value!");
goto fail;
}
- reg_list[XT_USR_REG_START + i].dirty = false;
- reg_list[XT_USR_REG_START + i].valid = false;
- reg_list[XT_USR_REG_START + i].type = xtensa->core_config->user_regs[i].type;
- reg_list[XT_USR_REG_START + i].arch_info = xtensa;
- xtensa->regs_num++;
- }
- if (xtensa->core_config->gdb_general_regs_num >= xtensa->regs_num) {
- LOG_ERROR("Regs number less then GDB general regs number!");
- goto fail;
+ xtensa->empty_regs[i].arch_info = xtensa;
}
- /* assign GDB reg numbers to registers */
- for (unsigned int gdb_reg_id = 0; gdb_reg_id < xtensa->regs_num; gdb_reg_id++) {
- unsigned int reg_id = xtensa->core_config->gdb_regs_mapping[gdb_reg_id];
- if (reg_id >= reg_cache->num_regs) {
- LOG_ERROR("Invalid GDB map!");
+ /* Construct contiguous register list from contiguous descriptor list */
+ if (xtensa->regmap_contiguous && xtensa->contiguous_regs_desc) {
+ xtensa->contiguous_regs_list = calloc(xtensa->total_regs_num, sizeof(struct reg *));
+ if (!xtensa->contiguous_regs_list) {
+ LOG_TARGET_ERROR(target, "ERROR: Out of memory");
goto fail;
}
- if (!reg_list[reg_id].exist) {
- LOG_ERROR("Non-existing reg in GDB map!");
- goto fail;
+ for (unsigned int i = 0; i < xtensa->total_regs_num; i++) {
+ unsigned int j;
+ for (j = 0; j < reg_cache->num_regs; j++) {
+ if (!strcmp(reg_cache->reg_list[j].name, xtensa->contiguous_regs_desc[i]->name)) {
+ xtensa->contiguous_regs_list[i] = &(reg_cache->reg_list[j]);
+ LOG_TARGET_DEBUG(target,
+ "POPULATE contiguous regs list: %-16s, dbreg_num 0x%04x",
+ xtensa->contiguous_regs_list[i]->name,
+ xtensa->contiguous_regs_desc[i]->dbreg_num);
+ break;
+ }
+ }
+ if (j == reg_cache->num_regs)
+ LOG_TARGET_WARNING(target, "contiguous register %s not found",
+ xtensa->contiguous_regs_desc[i]->name);
}
- reg_list[reg_id].number = gdb_reg_id;
}
- reg_cache->reg_list = reg_list;
xtensa->algo_context_backup = calloc(reg_cache->num_regs, sizeof(void *));
if (!xtensa->algo_context_backup) {
@@ -2151,7 +2517,6 @@ static int xtensa_build_reg_cache(struct target *target)
goto fail;
}
}
-
xtensa->core_cache = reg_cache;
if (cache_p)
*cache_p = reg_cache;
@@ -2159,9 +2524,15 @@ static int xtensa_build_reg_cache(struct target *target)
fail:
if (reg_list) {
- for (unsigned int i = 0; i < reg_cache->num_regs; i++)
+ for (unsigned int i = 0; i < reg_list_size; i++)
free(reg_list[i].value);
- free(reg_list);
+ }
+ if (xtensa->empty_regs) {
+ for (unsigned int i = 0; i < xtensa->dbregs_num; i++) {
+ free((void *)xtensa->empty_regs[i].name);
+ free(xtensa->empty_regs[i].value);
+ }
+ free(xtensa->empty_regs);
}
if (xtensa->algo_context_backup) {
for (unsigned int i = 0; i < reg_cache->num_regs; i++)
@@ -2173,21 +2544,321 @@ fail:
return ERROR_FAIL;
}
+static int32_t xtensa_gdbqc_parse_exec_tie_ops(struct target *target, char *opstr)
+{
+ struct xtensa *xtensa = target_to_xtensa(target);
+ int32_t status = ERROR_COMMAND_ARGUMENT_INVALID;
+ /* Process op[] list */
+ while (opstr && (*opstr == ':')) {
+ uint8_t ops[32];
+ unsigned int oplen = strtoul(opstr + 1, &opstr, 16);
+ if (oplen > 32) {
+ LOG_TARGET_ERROR(target, "TIE access instruction too long (%d)\n", oplen);
+ break;
+ }
+ unsigned int i = 0;
+ while ((i < oplen) && opstr && (*opstr == ':'))
+ ops[i++] = strtoul(opstr + 1, &opstr, 16);
+ if (i != oplen) {
+ LOG_TARGET_ERROR(target, "TIE access instruction malformed (%d)\n", i);
+ break;
+ }
+
+ char insn_buf[128];
+ sprintf(insn_buf, "Exec %d-byte TIE sequence: ", oplen);
+ for (i = 0; i < oplen; i++)
+ sprintf(insn_buf + strlen(insn_buf), "%02x:", ops[i]);
+ LOG_TARGET_DEBUG(target, "%s", insn_buf);
+ xtensa_queue_exec_ins_wide(xtensa, ops, oplen); /* Handles endian-swap */
+ status = ERROR_OK;
+ }
+ return status;
+}
+
+static int xtensa_gdbqc_qxtreg(struct target *target, const char *packet, char **response_p)
+{
+ struct xtensa *xtensa = target_to_xtensa(target);
+ bool iswrite = (packet[0] == 'Q');
+ enum xtensa_qerr_e error;
+
+ /* Read/write TIE register. Requires spill location.
+ * qxtreg<num>:<len>:<oplen>:<op[0]>:<...>[:<oplen>:<op[0]>:<...>]
+ * Qxtreg<num>:<len>:<oplen>:<op[0]>:<...>[:<oplen>:<op[0]>:<...>]=<value>
+ */
+ if (!(xtensa->spill_buf)) {
+ LOG_ERROR("Spill location not specified. Try 'target remote <host>:3333 &spill_location0'");
+ error = XT_QERR_FAIL;
+ goto xtensa_gdbqc_qxtreg_fail;
+ }
+
+ char *delim;
+ uint32_t regnum = strtoul(packet + 6, &delim, 16);
+ if (*delim != ':') {
+ LOG_ERROR("Malformed qxtreg packet");
+ error = XT_QERR_INVAL;
+ goto xtensa_gdbqc_qxtreg_fail;
+ }
+ uint32_t reglen = strtoul(delim + 1, &delim, 16);
+ if (*delim != ':') {
+ LOG_ERROR("Malformed qxtreg packet");
+ error = XT_QERR_INVAL;
+ goto xtensa_gdbqc_qxtreg_fail;
+ }
+ uint8_t regbuf[XT_QUERYPKT_RESP_MAX];
+ LOG_DEBUG("TIE reg 0x%08" PRIx32 " %s (%d bytes)", regnum, iswrite ? "write" : "read", reglen);
+ if (reglen * 2 + 1 > XT_QUERYPKT_RESP_MAX) {
+ LOG_ERROR("TIE register too large");
+ error = XT_QERR_MEM;
+ goto xtensa_gdbqc_qxtreg_fail;
+ }
+
+ /* (1) Save spill memory, (1.5) [if write then store value to spill location],
+ * (2) read old a4, (3) write spill address to a4.
+ * NOTE: ensure a4 is restored properly by all error handling logic
+ */
+ unsigned int memop_size = (xtensa->spill_loc & 3) ? 1 : 4;
+ int status = xtensa_read_memory(target, xtensa->spill_loc, memop_size,
+ xtensa->spill_bytes / memop_size, xtensa->spill_buf);
+ if (status != ERROR_OK) {
+ LOG_ERROR("Spill memory save");
+ error = XT_QERR_MEM;
+ goto xtensa_gdbqc_qxtreg_fail;
+ }
+ if (iswrite) {
+ /* Extract value and store in spill memory */
+ unsigned int b = 0;
+ char *valbuf = strchr(delim, '=');
+ if (!(valbuf && (*valbuf == '='))) {
+ LOG_ERROR("Malformed Qxtreg packet");
+ error = XT_QERR_INVAL;
+ goto xtensa_gdbqc_qxtreg_fail;
+ }
+ valbuf++;
+ while (*valbuf && *(valbuf + 1)) {
+ char bytestr[3] = { 0, 0, 0 };
+ strncpy(bytestr, valbuf, 2);
+ regbuf[b++] = strtoul(bytestr, NULL, 16);
+ valbuf += 2;
+ }
+ if (b != reglen) {
+ LOG_ERROR("Malformed Qxtreg packet");
+ error = XT_QERR_INVAL;
+ goto xtensa_gdbqc_qxtreg_fail;
+ }
+ status = xtensa_write_memory(target, xtensa->spill_loc, memop_size,
+ reglen / memop_size, regbuf);
+ if (status != ERROR_OK) {
+ LOG_ERROR("TIE value store");
+ error = XT_QERR_MEM;
+ goto xtensa_gdbqc_qxtreg_fail;
+ }
+ }
+ xtensa_reg_val_t orig_a4 = xtensa_reg_get(target, XT_REG_IDX_A4);
+ xtensa_queue_dbg_reg_write(xtensa, NARADR_DDR, xtensa->spill_loc);
+ xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A4));
+
+ int32_t tieop_status = xtensa_gdbqc_parse_exec_tie_ops(target, delim);
+
+ /* Restore a4 but not yet spill memory. Execute it all... */
+ xtensa_queue_dbg_reg_write(xtensa, NARADR_DDR, orig_a4);
+ xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A4));
+ status = jtag_execute_queue();
+ if (status != ERROR_OK) {
+ LOG_TARGET_ERROR(target, "TIE queue execute: %d\n", status);
+ tieop_status = status;
+ }
+ status = xtensa_core_status_check(target);
+ if (status != ERROR_OK) {
+ LOG_TARGET_ERROR(target, "TIE instr execute: %d\n", status);
+ tieop_status = status;
+ }
+
+ if (tieop_status == ERROR_OK) {
+ if (iswrite) {
+ /* TIE write succeeded; send OK */
+ strcpy(*response_p, "OK");
+ } else {
+ /* TIE read succeeded; copy result from spill memory */
+ status = xtensa_read_memory(target, xtensa->spill_loc, memop_size, reglen, regbuf);
+ if (status != ERROR_OK) {
+ LOG_TARGET_ERROR(target, "TIE result read");
+ tieop_status = status;
+ }
+ unsigned int i;
+ for (i = 0; i < reglen; i++)
+ sprintf(*response_p + 2 * i, "%02x", regbuf[i]);
+ *(*response_p + 2 * i) = '\0';
+ LOG_TARGET_DEBUG(target, "TIE response: %s", *response_p);
+ }
+ }
+
+ /* Restore spill memory first, then report any previous errors */
+ status = xtensa_write_memory(target, xtensa->spill_loc, memop_size,
+ xtensa->spill_bytes / memop_size, xtensa->spill_buf);
+ if (status != ERROR_OK) {
+ LOG_ERROR("Spill memory restore");
+ error = XT_QERR_MEM;
+ goto xtensa_gdbqc_qxtreg_fail;
+ }
+ if (tieop_status != ERROR_OK) {
+ LOG_ERROR("TIE execution");
+ error = XT_QERR_FAIL;
+ goto xtensa_gdbqc_qxtreg_fail;
+ }
+ return ERROR_OK;
+
+xtensa_gdbqc_qxtreg_fail:
+ strcpy(*response_p, xt_qerr[error].chrval);
+ return xt_qerr[error].intval;
+}
+
+int xtensa_gdb_query_custom(struct target *target, const char *packet, char **response_p)
+{
+ struct xtensa *xtensa = target_to_xtensa(target);
+ enum xtensa_qerr_e error;
+ if (!packet || !response_p) {
+ LOG_TARGET_ERROR(target, "invalid parameter: packet %p response_p %p", packet, response_p);
+ return ERROR_FAIL;
+ }
+
+ *response_p = xtensa->qpkt_resp;
+ if (strncmp(packet, "qxtn", 4) == 0) {
+ strcpy(*response_p, "OpenOCD");
+ return ERROR_OK;
+ } else if (strncasecmp(packet, "qxtgdbversion=", 14) == 0) {
+ return ERROR_OK;
+ } else if ((strncmp(packet, "Qxtsis=", 7) == 0) || (strncmp(packet, "Qxtsds=", 7) == 0)) {
+ /* Confirm host cache params match core .cfg file */
+ struct xtensa_cache_config *cachep = (packet[4] == 'i') ?
+ &xtensa->core_config->icache : &xtensa->core_config->dcache;
+ unsigned int line_size = 0, size = 0, way_count = 0;
+ sscanf(&packet[7], "%x,%x,%x", &line_size, &size, &way_count);
+ if ((cachep->line_size != line_size) ||
+ (cachep->size != size) ||
+ (cachep->way_count != way_count)) {
+ LOG_TARGET_WARNING(target, "%cCache mismatch; check xtensa-core-XXX.cfg file",
+ cachep == &xtensa->core_config->icache ? 'I' : 'D');
+ }
+ strcpy(*response_p, "OK");
+ return ERROR_OK;
+ } else if ((strncmp(packet, "Qxtiram=", 8) == 0) || (strncmp(packet, "Qxtirom=", 8) == 0)) {
+ /* Confirm host IRAM/IROM params match core .cfg file */
+ struct xtensa_local_mem_config *memp = (packet[5] == 'a') ?
+ &xtensa->core_config->iram : &xtensa->core_config->irom;
+ unsigned int base = 0, size = 0, i;
+ char *pkt = (char *)&packet[7];
+ do {
+ pkt++;
+ size = strtoul(pkt, &pkt, 16);
+ pkt++;
+ base = strtoul(pkt, &pkt, 16);
+ LOG_TARGET_DEBUG(target, "memcheck: %dB @ 0x%08x", size, base);
+ for (i = 0; i < memp->count; i++) {
+ if ((memp->regions[i].base == base) && (memp->regions[i].size == size))
+ break;
+ }
+ if (i == memp->count) {
+ LOG_TARGET_WARNING(target, "%s mismatch; check xtensa-core-XXX.cfg file",
+ memp == &xtensa->core_config->iram ? "IRAM" : "IROM");
+ break;
+ }
+ for (i = 0; i < 11; i++) {
+ pkt++;
+ strtoul(pkt, &pkt, 16);
+ }
+ } while (pkt && (pkt[0] == ','));
+ strcpy(*response_p, "OK");
+ return ERROR_OK;
+ } else if (strncmp(packet, "Qxtexcmlvl=", 11) == 0) {
+ /* Confirm host EXCM_LEVEL matches core .cfg file */
+ unsigned int excm_level = strtoul(&packet[11], NULL, 0);
+ if (!xtensa->core_config->high_irq.enabled ||
+ (excm_level != xtensa->core_config->high_irq.excm_level))
+ LOG_TARGET_WARNING(target, "EXCM_LEVEL mismatch; check xtensa-core-XXX.cfg file");
+ strcpy(*response_p, "OK");
+ return ERROR_OK;
+ } else if ((strncmp(packet, "Qxtl2cs=", 8) == 0) ||
+ (strncmp(packet, "Qxtl2ca=", 8) == 0) ||
+ (strncmp(packet, "Qxtdensity=", 11) == 0)) {
+ strcpy(*response_p, "OK");
+ return ERROR_OK;
+ } else if (strncmp(packet, "Qxtspill=", 9) == 0) {
+ char *delim;
+ uint32_t spill_loc = strtoul(packet + 9, &delim, 16);
+ if (*delim != ':') {
+ LOG_ERROR("Malformed Qxtspill packet");
+ error = XT_QERR_INVAL;
+ goto xtensa_gdb_query_custom_fail;
+ }
+ xtensa->spill_loc = spill_loc;
+ xtensa->spill_bytes = strtoul(delim + 1, NULL, 16);
+ if (xtensa->spill_buf)
+ free(xtensa->spill_buf);
+ xtensa->spill_buf = calloc(1, xtensa->spill_bytes);
+ if (!xtensa->spill_buf) {
+ LOG_ERROR("Spill buf alloc");
+ error = XT_QERR_MEM;
+ goto xtensa_gdb_query_custom_fail;
+ }
+ LOG_TARGET_DEBUG(target, "Set spill 0x%08" PRIx32 " (%d)", xtensa->spill_loc, xtensa->spill_bytes);
+ strcpy(*response_p, "OK");
+ return ERROR_OK;
+ } else if (strncasecmp(packet, "qxtreg", 6) == 0) {
+ return xtensa_gdbqc_qxtreg(target, packet, response_p);
+ } else if ((strncmp(packet, "qTStatus", 8) == 0) ||
+ (strncmp(packet, "qxtftie", 7) == 0) ||
+ (strncmp(packet, "qxtstie", 7) == 0)) {
+ /* Return empty string to indicate trace, TIE wire debug are unsupported */
+ strcpy(*response_p, "");
+ return ERROR_OK;
+ }
+
+ /* Warn for all other queries, but do not return errors */
+ LOG_TARGET_WARNING(target, "Unknown target-specific query packet: %s", packet);
+ strcpy(*response_p, "");
+ return ERROR_OK;
+
+xtensa_gdb_query_custom_fail:
+ strcpy(*response_p, xt_qerr[error].chrval);
+ return xt_qerr[error].intval;
+}
+
int xtensa_init_arch_info(struct target *target, struct xtensa *xtensa,
- const struct xtensa_config *xtensa_config,
const struct xtensa_debug_module_config *dm_cfg)
{
target->arch_info = xtensa;
xtensa->common_magic = XTENSA_COMMON_MAGIC;
xtensa->target = target;
- xtensa->core_config = xtensa_config;
xtensa->stepping_isr_mode = XT_STEPPING_ISR_ON;
- if (!xtensa->core_config->exc.enabled || !xtensa->core_config->irq.enabled ||
- !xtensa->core_config->high_irq.enabled || !xtensa->core_config->debug.enabled) {
- LOG_ERROR("Xtensa configuration does not support debugging!");
+ xtensa->core_config = calloc(1, sizeof(struct xtensa_config));
+ if (!xtensa->core_config) {
+ LOG_ERROR("Xtensa configuration alloc failed\n");
return ERROR_FAIL;
}
+
+ /* Default cache settings are disabled with 1 way */
+ xtensa->core_config->icache.way_count = 1;
+ xtensa->core_config->dcache.way_count = 1;
+
+ /* chrval: AR3/AR4 register names will change with window mapping.
+ * intval: tracks whether scratch register was set through gdb P packet.
+ */
+ for (enum xtensa_ar_scratch_set_e s = 0; s < XT_AR_SCRATCH_NUM; s++) {
+ xtensa->scratch_ars[s].chrval = calloc(8, sizeof(char));
+ if (!xtensa->scratch_ars[s].chrval) {
+ for (enum xtensa_ar_scratch_set_e f = s - 1; s >= 0; s--)
+ free(xtensa->scratch_ars[f].chrval);
+ free(xtensa->core_config);
+ LOG_ERROR("Xtensa scratch AR alloc failed\n");
+ return ERROR_FAIL;
+ }
+ xtensa->scratch_ars[s].intval = false;
+ sprintf(xtensa->scratch_ars[s].chrval, "%s%d",
+ ((s == XT_AR_SCRATCH_A3) || (s == XT_AR_SCRATCH_A4)) ? "a" : "ar",
+ ((s == XT_AR_SCRATCH_A3) || (s == XT_AR_SCRATCH_AR3)) ? 3 : 4);
+ }
+
return xtensa_dm_init(&xtensa->dbg_mod, dm_cfg);
}
@@ -2201,12 +2872,12 @@ int xtensa_target_init(struct command_context *cmd_ctx, struct target *target)
struct xtensa *xtensa = target_to_xtensa(target);
xtensa->come_online_probes_num = 3;
- xtensa->hw_brps = calloc(xtensa->core_config->debug.ibreaks_num, sizeof(struct breakpoint *));
+ xtensa->hw_brps = calloc(XT_HW_IBREAK_MAX_NUM, sizeof(struct breakpoint *));
if (!xtensa->hw_brps) {
LOG_ERROR("Failed to alloc memory for HW breakpoints!");
return ERROR_FAIL;
}
- xtensa->hw_wps = calloc(xtensa->core_config->debug.dbreaks_num, sizeof(struct watchpoint *));
+ xtensa->hw_wps = calloc(XT_HW_DBREAK_MAX_NUM, sizeof(struct watchpoint *));
if (!xtensa->hw_wps) {
free(xtensa->hw_brps);
LOG_ERROR("Failed to alloc memory for HW watchpoints!");
@@ -2220,6 +2891,11 @@ int xtensa_target_init(struct command_context *cmd_ctx, struct target *target)
return ERROR_FAIL;
}
+ xtensa->spill_loc = 0xffffffff;
+ xtensa->spill_bytes = 0;
+ xtensa->spill_buf = NULL;
+ xtensa->probe_lsddr32p = -1; /* Probe for fast load/store operations */
+
return xtensa_build_reg_cache(target);
}
@@ -2240,6 +2916,21 @@ static void xtensa_free_reg_cache(struct target *target)
}
xtensa->core_cache = NULL;
xtensa->algo_context_backup = NULL;
+
+ if (xtensa->empty_regs) {
+ for (unsigned int i = 0; i < xtensa->dbregs_num; i++) {
+ free((void *)xtensa->empty_regs[i].name);
+ free(xtensa->empty_regs[i].value);
+ }
+ free(xtensa->empty_regs);
+ }
+ xtensa->empty_regs = NULL;
+ if (xtensa->optregs) {
+ for (unsigned int i = 0; i < xtensa->num_optregs; i++)
+ free((void *)xtensa->optregs[i].name);
+ free(xtensa->optregs);
+ }
+ xtensa->optregs = NULL;
}
void xtensa_target_deinit(struct target *target)
@@ -2265,6 +2956,13 @@ void xtensa_target_deinit(struct target *target)
free(xtensa->hw_brps);
free(xtensa->hw_wps);
free(xtensa->sw_brps);
+ if (xtensa->spill_buf) {
+ free(xtensa->spill_buf);
+ xtensa->spill_buf = NULL;
+ }
+ for (enum xtensa_ar_scratch_set_e s = 0; s < XT_AR_SCRATCH_NUM; s++)
+ free(xtensa->scratch_ars[s].chrval);
+ free(xtensa->core_config);
}
const char *xtensa_get_gdb_arch(struct target *target)
@@ -2272,6 +2970,521 @@ const char *xtensa_get_gdb_arch(struct target *target)
return "xtensa";
}
+/* exe <ascii-encoded hexadecimal instruction bytes> */
+COMMAND_HELPER(xtensa_cmd_exe_do, struct target *target)
+{
+ struct xtensa *xtensa = target_to_xtensa(target);
+
+ if (CMD_ARGC != 1)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ /* Process ascii-encoded hex byte string */
+ const char *parm = CMD_ARGV[0];
+ unsigned int parm_len = strlen(parm);
+ if ((parm_len >= 64) || (parm_len & 1)) {
+ LOG_ERROR("Invalid parameter length (%d): must be even, < 64 characters", parm_len);
+ return ERROR_FAIL;
+ }
+
+ uint8_t ops[32];
+ unsigned int oplen = parm_len / 2;
+ char encoded_byte[3] = { 0, 0, 0 };
+ for (unsigned int i = 0; i < oplen; i++) {
+ encoded_byte[0] = *parm++;
+ encoded_byte[1] = *parm++;
+ ops[i] = strtoul(encoded_byte, NULL, 16);
+ }
+
+ /* GDB must handle state save/restore.
+ * Flush reg cache in case spill location is in an AR
+ * Update CPENABLE only for this execution; later restore cached copy
+ * Keep a copy of exccause in case executed code triggers an exception
+ */
+ int status = xtensa_write_dirty_registers(target);
+ if (status != ERROR_OK) {
+ LOG_ERROR("%s: Failed to write back register cache.", target_name(target));
+ return ERROR_FAIL;
+ }
+ xtensa_reg_val_t exccause = xtensa_reg_get(target, XT_REG_IDX_EXCCAUSE);
+ xtensa_reg_val_t cpenable = xtensa_reg_get(target, XT_REG_IDX_CPENABLE);
+ xtensa_reg_val_t a3 = xtensa_reg_get(target, XT_REG_IDX_A3);
+ xtensa_queue_dbg_reg_write(xtensa, NARADR_DDR, 0xffffffff);
+ xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3));
+ xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa,
+ xtensa_regs[XT_REG_IDX_CPENABLE].reg_num, XT_REG_A3));
+ xtensa_queue_dbg_reg_write(xtensa, NARADR_DDR, a3);
+ xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3));
+
+ /* Queue instruction list and execute everything */
+ LOG_TARGET_DEBUG(target, "execute stub: %s", CMD_ARGV[0]);
+ xtensa_queue_exec_ins_wide(xtensa, ops, oplen); /* Handles endian-swap */
+ status = jtag_execute_queue();
+ if (status != ERROR_OK)
+ LOG_TARGET_ERROR(target, "TIE queue execute: %d\n", status);
+ status = xtensa_core_status_check(target);
+ if (status != ERROR_OK)
+ LOG_TARGET_ERROR(target, "TIE instr execute: %d\n", status);
+
+ /* Reread register cache and restore saved regs after instruction execution */
+ if (xtensa_fetch_all_regs(target) != ERROR_OK)
+ LOG_TARGET_ERROR(target, "%s: Failed to fetch register cache (post-exec).", target_name(target));
+ xtensa_reg_set(target, XT_REG_IDX_EXCCAUSE, exccause);
+ xtensa_reg_set(target, XT_REG_IDX_CPENABLE, cpenable);
+ return status;
+}
+
+COMMAND_HANDLER(xtensa_cmd_exe)
+{
+ return CALL_COMMAND_HANDLER(xtensa_cmd_exe_do, get_current_target(CMD_CTX));
+}
+
+/* xtdef <name> */
+COMMAND_HELPER(xtensa_cmd_xtdef_do, struct xtensa *xtensa)
+{
+ if (CMD_ARGC != 1)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ const char *core_name = CMD_ARGV[0];
+ if (strcasecmp(core_name, "LX") == 0) {
+ xtensa->core_config->core_type = XT_LX;
+ } else {
+ LOG_ERROR("xtdef [LX]\n");
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+ return ERROR_OK;
+}
+
+COMMAND_HANDLER(xtensa_cmd_xtdef)
+{
+ return CALL_COMMAND_HANDLER(xtensa_cmd_xtdef_do,
+ target_to_xtensa(get_current_target(CMD_CTX)));
+}
+
+static inline bool xtensa_cmd_xtopt_legal_val(char *opt, int val, int min, int max)
+{
+ if ((val < min) || (val > max)) {
+ LOG_ERROR("xtopt %s (%d) out of range [%d..%d]\n", opt, val, min, max);
+ return false;
+ }
+ return true;
+}
+
+/* xtopt <name> <value> */
+COMMAND_HELPER(xtensa_cmd_xtopt_do, struct xtensa *xtensa)
+{
+ if (CMD_ARGC != 2)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ const char *opt_name = CMD_ARGV[0];
+ int opt_val = strtol(CMD_ARGV[1], NULL, 0);
+ if (strcasecmp(opt_name, "arnum") == 0) {
+ if (!xtensa_cmd_xtopt_legal_val("arnum", opt_val, 0, 64))
+ return ERROR_COMMAND_ARGUMENT_INVALID;
+ xtensa->core_config->aregs_num = opt_val;
+ } else if (strcasecmp(opt_name, "windowed") == 0) {
+ if (!xtensa_cmd_xtopt_legal_val("windowed", opt_val, 0, 1))
+ return ERROR_COMMAND_ARGUMENT_INVALID;
+ xtensa->core_config->windowed = opt_val;
+ } else if (strcasecmp(opt_name, "cpenable") == 0) {
+ if (!xtensa_cmd_xtopt_legal_val("cpenable", opt_val, 0, 1))
+ return ERROR_COMMAND_ARGUMENT_INVALID;
+ xtensa->core_config->coproc = opt_val;
+ } else if (strcasecmp(opt_name, "exceptions") == 0) {
+ if (!xtensa_cmd_xtopt_legal_val("exceptions", opt_val, 0, 1))
+ return ERROR_COMMAND_ARGUMENT_INVALID;
+ xtensa->core_config->exceptions = opt_val;
+ } else if (strcasecmp(opt_name, "intnum") == 0) {
+ if (!xtensa_cmd_xtopt_legal_val("intnum", opt_val, 0, 32))
+ return ERROR_COMMAND_ARGUMENT_INVALID;
+ xtensa->core_config->irq.enabled = (opt_val > 0);
+ xtensa->core_config->irq.irq_num = opt_val;
+ } else if (strcasecmp(opt_name, "hipriints") == 0) {
+ if (!xtensa_cmd_xtopt_legal_val("hipriints", opt_val, 0, 1))
+ return ERROR_COMMAND_ARGUMENT_INVALID;
+ xtensa->core_config->high_irq.enabled = opt_val;
+ } else if (strcasecmp(opt_name, "excmlevel") == 0) {
+ if (!xtensa_cmd_xtopt_legal_val("excmlevel", opt_val, 1, 6))
+ return ERROR_COMMAND_ARGUMENT_INVALID;
+ if (!xtensa->core_config->high_irq.enabled) {
+ LOG_ERROR("xtopt excmlevel requires hipriints\n");
+ return ERROR_COMMAND_ARGUMENT_INVALID;
+ }
+ xtensa->core_config->high_irq.excm_level = opt_val;
+ } else if (strcasecmp(opt_name, "intlevels") == 0) {
+ if (xtensa->core_config->core_type == XT_LX) {
+ if (!xtensa_cmd_xtopt_legal_val("intlevels", opt_val, 2, 6))
+ return ERROR_COMMAND_ARGUMENT_INVALID;
+ } else {
+ if (!xtensa_cmd_xtopt_legal_val("intlevels", opt_val, 1, 255))
+ return ERROR_COMMAND_ARGUMENT_INVALID;
+ }
+ if (!xtensa->core_config->high_irq.enabled) {
+ LOG_ERROR("xtopt intlevels requires hipriints\n");
+ return ERROR_COMMAND_ARGUMENT_INVALID;
+ }
+ xtensa->core_config->high_irq.level_num = opt_val;
+ } else if (strcasecmp(opt_name, "debuglevel") == 0) {
+ if (xtensa->core_config->core_type == XT_LX) {
+ if (!xtensa_cmd_xtopt_legal_val("debuglevel", opt_val, 2, 6))
+ return ERROR_COMMAND_ARGUMENT_INVALID;
+ } else {
+ if (!xtensa_cmd_xtopt_legal_val("debuglevel", opt_val, 0, 0))
+ return ERROR_COMMAND_ARGUMENT_INVALID;
+ }
+ xtensa->core_config->debug.enabled = 1;
+ xtensa->core_config->debug.irq_level = opt_val;
+ } else if (strcasecmp(opt_name, "ibreaknum") == 0) {
+ if (!xtensa_cmd_xtopt_legal_val("ibreaknum", opt_val, 0, 2))
+ return ERROR_COMMAND_ARGUMENT_INVALID;
+ xtensa->core_config->debug.ibreaks_num = opt_val;
+ } else if (strcasecmp(opt_name, "dbreaknum") == 0) {
+ if (!xtensa_cmd_xtopt_legal_val("dbreaknum", opt_val, 0, 2))
+ return ERROR_COMMAND_ARGUMENT_INVALID;
+ xtensa->core_config->debug.dbreaks_num = opt_val;
+ } else if (strcasecmp(opt_name, "tracemem") == 0) {
+ if (!xtensa_cmd_xtopt_legal_val("tracemem", opt_val, 0, 256 * 1024))
+ return ERROR_COMMAND_ARGUMENT_INVALID;
+ xtensa->core_config->trace.mem_sz = opt_val;
+ xtensa->core_config->trace.enabled = (opt_val > 0);
+ } else if (strcasecmp(opt_name, "tracememrev") == 0) {
+ if (!xtensa_cmd_xtopt_legal_val("tracememrev", opt_val, 0, 1))
+ return ERROR_COMMAND_ARGUMENT_INVALID;
+ xtensa->core_config->trace.reversed_mem_access = opt_val;
+ } else if (strcasecmp(opt_name, "perfcount") == 0) {
+ if (!xtensa_cmd_xtopt_legal_val("perfcount", opt_val, 0, 8))
+ return ERROR_COMMAND_ARGUMENT_INVALID;
+ xtensa->core_config->debug.perfcount_num = opt_val;
+ } else {
+ LOG_WARNING("Unknown xtensa command ignored: \"xtopt %s %s\"", CMD_ARGV[0], CMD_ARGV[1]);
+ return ERROR_OK;
+ }
+
+ return ERROR_OK;
+}
+
+COMMAND_HANDLER(xtensa_cmd_xtopt)
+{
+ return CALL_COMMAND_HANDLER(xtensa_cmd_xtopt_do,
+ target_to_xtensa(get_current_target(CMD_CTX)));
+}
+
+/* xtmem <type> [parameters] */
+COMMAND_HELPER(xtensa_cmd_xtmem_do, struct xtensa *xtensa)
+{
+ struct xtensa_cache_config *cachep = NULL;
+ struct xtensa_local_mem_config *memp = NULL;
+ int mem_access = 0;
+ bool is_dcache = false;
+
+ if (CMD_ARGC == 0) {
+ LOG_ERROR("xtmem <type> [parameters]\n");
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+
+ const char *mem_name = CMD_ARGV[0];
+ if (strcasecmp(mem_name, "icache") == 0) {
+ cachep = &xtensa->core_config->icache;
+ } else if (strcasecmp(mem_name, "dcache") == 0) {
+ cachep = &xtensa->core_config->dcache;
+ is_dcache = true;
+ } else if (strcasecmp(mem_name, "l2cache") == 0) {
+ /* TODO: support L2 cache */
+ } else if (strcasecmp(mem_name, "l2addr") == 0) {
+ /* TODO: support L2 cache */
+ } else if (strcasecmp(mem_name, "iram") == 0) {
+ memp = &xtensa->core_config->iram;
+ mem_access = XT_MEM_ACCESS_READ | XT_MEM_ACCESS_WRITE;
+ } else if (strcasecmp(mem_name, "dram") == 0) {
+ memp = &xtensa->core_config->dram;
+ mem_access = XT_MEM_ACCESS_READ | XT_MEM_ACCESS_WRITE;
+ } else if (strcasecmp(mem_name, "sram") == 0) {
+ memp = &xtensa->core_config->sram;
+ mem_access = XT_MEM_ACCESS_READ | XT_MEM_ACCESS_WRITE;
+ } else if (strcasecmp(mem_name, "irom") == 0) {
+ memp = &xtensa->core_config->irom;
+ mem_access = XT_MEM_ACCESS_READ;
+ } else if (strcasecmp(mem_name, "drom") == 0) {
+ memp = &xtensa->core_config->drom;
+ mem_access = XT_MEM_ACCESS_READ;
+ } else if (strcasecmp(mem_name, "srom") == 0) {
+ memp = &xtensa->core_config->srom;
+ mem_access = XT_MEM_ACCESS_READ;
+ } else {
+ LOG_ERROR("xtmem types: <icache|dcache|l2cache|l2addr|iram|irom|dram|drom|sram|srom>\n");
+ return ERROR_COMMAND_ARGUMENT_INVALID;
+ }
+
+ if (cachep) {
+ if ((CMD_ARGC != 4) && (CMD_ARGC != 5)) {
+ LOG_ERROR("xtmem <cachetype> <linebytes> <cachebytes> <ways> [writeback]\n");
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+ cachep->line_size = strtoul(CMD_ARGV[1], NULL, 0);
+ cachep->size = strtoul(CMD_ARGV[2], NULL, 0);
+ cachep->way_count = strtoul(CMD_ARGV[3], NULL, 0);
+ cachep->writeback = ((CMD_ARGC == 5) && is_dcache) ?
+ strtoul(CMD_ARGV[4], NULL, 0) : 0;
+ } else if (memp) {
+ if (CMD_ARGC != 3) {
+ LOG_ERROR("xtmem <memtype> <baseaddr> <bytes>\n");
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+ struct xtensa_local_mem_region_config *memcfgp = &memp->regions[memp->count];
+ memcfgp->base = strtoul(CMD_ARGV[1], NULL, 0);
+ memcfgp->size = strtoul(CMD_ARGV[2], NULL, 0);
+ memcfgp->access = mem_access;
+ memp->count++;
+ }
+
+ return ERROR_OK;
+}
+
+COMMAND_HANDLER(xtensa_cmd_xtmem)
+{
+ return CALL_COMMAND_HANDLER(xtensa_cmd_xtmem_do,
+ target_to_xtensa(get_current_target(CMD_CTX)));
+}
+
+/* xtmpu <num FG seg> <min seg size> <lockable> <executeonly> */
+COMMAND_HELPER(xtensa_cmd_xtmpu_do, struct xtensa *xtensa)
+{
+ if (CMD_ARGC != 4) {
+ LOG_ERROR("xtmpu <num FG seg> <min seg size> <lockable> <executeonly>\n");
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+
+ unsigned int nfgseg = strtoul(CMD_ARGV[0], NULL, 0);
+ unsigned int minsegsize = strtoul(CMD_ARGV[1], NULL, 0);
+ unsigned int lockable = strtoul(CMD_ARGV[2], NULL, 0);
+ unsigned int execonly = strtoul(CMD_ARGV[3], NULL, 0);
+
+ if ((nfgseg > 32)) {
+ LOG_ERROR("<nfgseg> must be within [0..32]\n");
+ return ERROR_COMMAND_ARGUMENT_INVALID;
+ } else if (minsegsize & (minsegsize - 1)) {
+ LOG_ERROR("<minsegsize> must be a power of 2 >= 32\n");
+ return ERROR_COMMAND_ARGUMENT_INVALID;
+ } else if (lockable > 1) {
+ LOG_ERROR("<lockable> must be 0 or 1\n");
+ return ERROR_COMMAND_ARGUMENT_INVALID;
+ } else if (execonly > 1) {
+ LOG_ERROR("<execonly> must be 0 or 1\n");
+ return ERROR_COMMAND_ARGUMENT_INVALID;
+ }
+
+ xtensa->core_config->mpu.enabled = true;
+ xtensa->core_config->mpu.nfgseg = nfgseg;
+ xtensa->core_config->mpu.minsegsize = minsegsize;
+ xtensa->core_config->mpu.lockable = lockable;
+ xtensa->core_config->mpu.execonly = execonly;
+ return ERROR_OK;
+}
+
+COMMAND_HANDLER(xtensa_cmd_xtmpu)
+{
+ return CALL_COMMAND_HANDLER(xtensa_cmd_xtmpu_do,
+ target_to_xtensa(get_current_target(CMD_CTX)));
+}
+
+/* xtmmu <NIREFILLENTRIES> <NDREFILLENTRIES> <IVARWAY56> <DVARWAY56> */
+COMMAND_HELPER(xtensa_cmd_xtmmu_do, struct xtensa *xtensa)
+{
+ if (CMD_ARGC != 2) {
+ LOG_ERROR("xtmmu <NIREFILLENTRIES> <NDREFILLENTRIES>\n");
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+
+ unsigned int nirefillentries = strtoul(CMD_ARGV[0], NULL, 0);
+ unsigned int ndrefillentries = strtoul(CMD_ARGV[1], NULL, 0);
+ if ((nirefillentries != 16) && (nirefillentries != 32)) {
+ LOG_ERROR("<nirefillentries> must be 16 or 32\n");
+ return ERROR_COMMAND_ARGUMENT_INVALID;
+ } else if ((ndrefillentries != 16) && (ndrefillentries != 32)) {
+ LOG_ERROR("<ndrefillentries> must be 16 or 32\n");
+ return ERROR_COMMAND_ARGUMENT_INVALID;
+ }
+
+ xtensa->core_config->mmu.enabled = true;
+ xtensa->core_config->mmu.itlb_entries_count = nirefillentries;
+ xtensa->core_config->mmu.dtlb_entries_count = ndrefillentries;
+ return ERROR_OK;
+}
+
+COMMAND_HANDLER(xtensa_cmd_xtmmu)
+{
+ return CALL_COMMAND_HANDLER(xtensa_cmd_xtmmu_do,
+ target_to_xtensa(get_current_target(CMD_CTX)));
+}
+
+/* xtregs <numregs>
+ * xtreg <regname> <regnum> */
+COMMAND_HELPER(xtensa_cmd_xtreg_do, struct xtensa *xtensa)
+{
+ if (CMD_ARGC == 1) {
+ int32_t numregs = strtoul(CMD_ARGV[0], NULL, 0);
+ if ((numregs <= 0) || (numregs > UINT16_MAX)) {
+ LOG_ERROR("xtreg <numregs>: Invalid 'numregs' (%d)", numregs);
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+ if ((xtensa->genpkt_regs_num > 0) && (numregs < (int32_t)xtensa->genpkt_regs_num)) {
+ LOG_ERROR("xtregs (%d) must be larger than numgenregs (%d) (if xtregfmt specified)",
+ numregs, xtensa->genpkt_regs_num);
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+ xtensa->total_regs_num = numregs;
+ xtensa->core_regs_num = 0;
+ xtensa->num_optregs = 0;
+ /* A little more memory than required, but saves a second initialization pass */
+ xtensa->optregs = calloc(xtensa->total_regs_num, sizeof(struct xtensa_reg_desc));
+ if (!xtensa->optregs) {
+ LOG_ERROR("Failed to allocate xtensa->optregs!");
+ return ERROR_FAIL;
+ }
+ return ERROR_OK;
+ } else if (CMD_ARGC != 2)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ /* "xtregfmt contiguous" must be specified prior to the first "xtreg" definition
+ * if general register (g-packet) requests or contiguous register maps are supported */
+ if (xtensa->regmap_contiguous && !xtensa->contiguous_regs_desc) {
+ xtensa->contiguous_regs_desc = calloc(xtensa->total_regs_num, sizeof(struct xtensa_reg_desc *));
+ if (!xtensa->contiguous_regs_desc) {
+ LOG_ERROR("Failed to allocate xtensa->contiguous_regs_desc!");
+ return ERROR_FAIL;
+ }
+ }
+
+ const char *regname = CMD_ARGV[0];
+ unsigned int regnum = strtoul(CMD_ARGV[1], NULL, 0);
+ if (regnum > UINT16_MAX) {
+ LOG_ERROR("<regnum> must be a 16-bit number");
+ return ERROR_COMMAND_ARGUMENT_INVALID;
+ }
+
+ if ((xtensa->num_optregs + xtensa->core_regs_num) >= xtensa->total_regs_num) {
+ if (xtensa->total_regs_num)
+ LOG_ERROR("'xtreg %s 0x%04x': Too many registers (%d expected, %d core %d extended)",
+ regname, regnum,
+ xtensa->total_regs_num, xtensa->core_regs_num, xtensa->num_optregs);
+ else
+ LOG_ERROR("'xtreg %s 0x%04x': Number of registers unspecified",
+ regname, regnum);
+ return ERROR_FAIL;
+ }
+
+ /* Determine whether register belongs in xtensa_regs[] or xtensa->xtensa_spec_regs[] */
+ struct xtensa_reg_desc *rptr = &xtensa->optregs[xtensa->num_optregs];
+ bool is_extended_reg = true;
+ unsigned int ridx;
+ for (ridx = 0; ridx < XT_NUM_REGS; ridx++) {
+ if (strcmp(CMD_ARGV[0], xtensa_regs[ridx].name) == 0) {
+ /* Flag core register as defined */
+ rptr = &xtensa_regs[ridx];
+ xtensa->core_regs_num++;
+ is_extended_reg = false;
+ break;
+ }
+ }
+
+ rptr->exist = true;
+ if (is_extended_reg) {
+ /* Register ID, debugger-visible register ID */
+ rptr->name = strdup(CMD_ARGV[0]);
+ rptr->dbreg_num = regnum;
+ rptr->reg_num = (regnum & XT_REG_INDEX_MASK);
+ xtensa->num_optregs++;
+
+ /* Register type */
+ if ((regnum & XT_REG_GENERAL_MASK) == XT_REG_GENERAL_VAL) {
+ rptr->type = XT_REG_GENERAL;
+ } else if ((regnum & XT_REG_USER_MASK) == XT_REG_USER_VAL) {
+ rptr->type = XT_REG_USER;
+ } else if ((regnum & XT_REG_FR_MASK) == XT_REG_FR_VAL) {
+ rptr->type = XT_REG_FR;
+ } else if ((regnum & XT_REG_SPECIAL_MASK) == XT_REG_SPECIAL_VAL) {
+ rptr->type = XT_REG_SPECIAL;
+ } else if ((regnum & XT_REG_RELGEN_MASK) == XT_REG_RELGEN_VAL) {
+ /* WARNING: For these registers, regnum points to the
+ * index of the corresponding ARx registers, NOT to
+ * the processor register number! */
+ rptr->type = XT_REG_RELGEN;
+ rptr->reg_num += XT_REG_IDX_ARFIRST;
+ rptr->dbreg_num += XT_REG_IDX_ARFIRST;
+ } else if ((regnum & XT_REG_TIE_MASK) != 0) {
+ rptr->type = XT_REG_TIE;
+ } else {
+ rptr->type = XT_REG_OTHER;
+ }
+
+ /* Register flags */
+ if ((strcmp(rptr->name, "mmid") == 0) || (strcmp(rptr->name, "eraccess") == 0) ||
+ (strcmp(rptr->name, "ddr") == 0) || (strcmp(rptr->name, "intset") == 0) ||
+ (strcmp(rptr->name, "intclear") == 0))
+ rptr->flags = XT_REGF_NOREAD;
+ else
+ rptr->flags = 0;
+
+ if ((rptr->reg_num == (XT_PS_REG_NUM_BASE + xtensa->core_config->debug.irq_level)) &&
+ (xtensa->core_config->core_type == XT_LX) && (rptr->type == XT_REG_SPECIAL)) {
+ xtensa->eps_dbglevel_idx = XT_NUM_REGS + xtensa->num_optregs - 1;
+ LOG_DEBUG("Setting PS (%s) index to %d", rptr->name, xtensa->eps_dbglevel_idx);
+ }
+ } else if (strcmp(rptr->name, "cpenable") == 0) {
+ xtensa->core_config->coproc = true;
+ }
+
+ /* Build out list of contiguous registers in specified order */
+ unsigned int running_reg_count = xtensa->num_optregs + xtensa->core_regs_num;
+ if (xtensa->contiguous_regs_desc) {
+ assert((running_reg_count <= xtensa->total_regs_num) && "contiguous register address internal error!");
+ xtensa->contiguous_regs_desc[running_reg_count - 1] = rptr;
+ }
+ if (xtensa_extra_debug_log)
+ LOG_DEBUG("Added %s register %-16s: 0x%04x/0x%02x t%d (%d of %d)",
+ is_extended_reg ? "config-specific" : "core",
+ rptr->name, rptr->dbreg_num, rptr->reg_num, rptr->type,
+ is_extended_reg ? xtensa->num_optregs : ridx,
+ is_extended_reg ? xtensa->total_regs_num : XT_NUM_REGS);
+ return ERROR_OK;
+}
+
+COMMAND_HANDLER(xtensa_cmd_xtreg)
+{
+ return CALL_COMMAND_HANDLER(xtensa_cmd_xtreg_do,
+ target_to_xtensa(get_current_target(CMD_CTX)));
+}
+
+/* xtregfmt <contiguous|sparse> [numgregs] */
+COMMAND_HELPER(xtensa_cmd_xtregfmt_do, struct xtensa *xtensa)
+{
+ if ((CMD_ARGC == 1) || (CMD_ARGC == 2)) {
+ if (!strcasecmp(CMD_ARGV[0], "sparse")) {
+ return ERROR_OK;
+ } else if (!strcasecmp(CMD_ARGV[0], "contiguous")) {
+ xtensa->regmap_contiguous = true;
+ if (CMD_ARGC == 2) {
+ unsigned int numgregs = strtoul(CMD_ARGV[1], NULL, 0);
+ if ((numgregs <= 0) ||
+ ((numgregs > xtensa->total_regs_num) &&
+ (xtensa->total_regs_num > 0))) {
+ LOG_ERROR("xtregfmt: if specified, numgregs (%d) must be <= numregs (%d)",
+ numgregs, xtensa->total_regs_num);
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+ xtensa->genpkt_regs_num = numgregs;
+ }
+ return ERROR_OK;
+ }
+ }
+ return ERROR_COMMAND_SYNTAX_ERROR;
+}
+
+COMMAND_HANDLER(xtensa_cmd_xtregfmt)
+{
+ return CALL_COMMAND_HANDLER(xtensa_cmd_xtregfmt_do,
+ target_to_xtensa(get_current_target(CMD_CTX)));
+}
+
COMMAND_HELPER(xtensa_cmd_permissive_mode_do, struct xtensa *xtensa)
{
return CALL_COMMAND_HANDLER(handle_command_parse_bool,
@@ -2422,7 +3635,7 @@ COMMAND_HANDLER(xtensa_cmd_mask_interrupts)
COMMAND_HELPER(xtensa_cmd_smpbreak_do, struct target *target)
{
- int res = ERROR_OK;
+ int res;
uint32_t val = 0;
if (CMD_ARGC >= 1) {
@@ -2455,16 +3668,15 @@ COMMAND_HELPER(xtensa_cmd_smpbreak_do, struct target *target)
} else {
struct xtensa *xtensa = target_to_xtensa(target);
res = xtensa_smpbreak_read(xtensa, &val);
- if (res == ERROR_OK) {
+ if (res == ERROR_OK)
command_print(CMD, "Current bits set:%s%s%s%s",
(val & OCDDCR_BREAKINEN) ? " BreakIn" : "",
(val & OCDDCR_BREAKOUTEN) ? " BreakOut" : "",
(val & OCDDCR_RUNSTALLINEN) ? " RunStallIn" : "",
(val & OCDDCR_DEBUGMODEOUTEN) ? " DebugModeOut" : ""
);
- } else {
+ else
command_print(CMD, "Failed to get smpbreak config %d", res);
- }
}
return res;
}
@@ -2653,12 +3865,68 @@ COMMAND_HANDLER(xtensa_cmd_tracedump)
target_to_xtensa(get_current_target(CMD_CTX)), CMD_ARGV[0]);
}
-const struct command_registration xtensa_command_handlers[] = {
+static const struct command_registration xtensa_any_command_handlers[] = {
+ {
+ .name = "xtdef",
+ .handler = xtensa_cmd_xtdef,
+ .mode = COMMAND_CONFIG,
+ .help = "Configure Xtensa core type",
+ .usage = "<type>",
+ },
+ {
+ .name = "xtopt",
+ .handler = xtensa_cmd_xtopt,
+ .mode = COMMAND_CONFIG,
+ .help = "Configure Xtensa core option",
+ .usage = "<name> <value>",
+ },
+ {
+ .name = "xtmem",
+ .handler = xtensa_cmd_xtmem,
+ .mode = COMMAND_CONFIG,
+ .help = "Configure Xtensa memory/cache option",
+ .usage = "<type> [parameters]",
+ },
+ {
+ .name = "xtmmu",
+ .handler = xtensa_cmd_xtmmu,
+ .mode = COMMAND_CONFIG,
+ .help = "Configure Xtensa MMU option",
+ .usage = "<NIREFILLENTRIES> <NDREFILLENTRIES> <IVARWAY56> <DVARWAY56>",
+ },
+ {
+ .name = "xtmpu",
+ .handler = xtensa_cmd_xtmpu,
+ .mode = COMMAND_CONFIG,
+ .help = "Configure Xtensa MPU option",
+ .usage = "<num FG seg> <min seg size> <lockable> <executeonly>",
+ },
+ {
+ .name = "xtreg",
+ .handler = xtensa_cmd_xtreg,
+ .mode = COMMAND_CONFIG,
+ .help = "Configure Xtensa register",
+ .usage = "<regname> <regnum>",
+ },
+ {
+ .name = "xtregs",
+ .handler = xtensa_cmd_xtreg,
+ .mode = COMMAND_CONFIG,
+ .help = "Configure number of Xtensa registers",
+ .usage = "<numregs>",
+ },
+ {
+ .name = "xtregfmt",
+ .handler = xtensa_cmd_xtregfmt,
+ .mode = COMMAND_CONFIG,
+ .help = "Configure format of Xtensa register map",
+ .usage = "<contiguous|sparse> [numgregs]",
+ },
{
.name = "set_permissive",
.handler = xtensa_cmd_permissive_mode,
.mode = COMMAND_ANY,
- .help = "When set to 1, enable Xtensa permissive mode (less client-side checks)",
+ .help = "When set to 1, enable Xtensa permissive mode (fewer client-side checks)",
.usage = "[0|1]",
},
{
@@ -2673,8 +3941,7 @@ const struct command_registration xtensa_command_handlers[] = {
.handler = xtensa_cmd_smpbreak,
.mode = COMMAND_ANY,
.help = "Set the way the CPU chains OCD breaks",
- .usage =
- "[none|breakinout|runstall] | [BreakIn] [BreakOut] [RunStallIn] [DebugModeOut]",
+ .usage = "[none|breakinout|runstall] | [BreakIn] [BreakOut] [RunStallIn] [DebugModeOut]",
},
{
.name = "perfmon_enable",
@@ -2687,8 +3954,7 @@ const struct command_registration xtensa_command_handlers[] = {
.name = "perfmon_dump",
.handler = xtensa_cmd_perfmon_dump,
.mode = COMMAND_EXEC,
- .help =
- "Dump performance counter value. If no argument specified, dumps all counters.",
+ .help = "Dump performance counter value. If no argument specified, dumps all counters.",
.usage = "[counter_id]",
},
{
@@ -2713,5 +3979,23 @@ const struct command_registration xtensa_command_handlers[] = {
.help = "Tracing: Dump trace memory to a files. One file per core.",
.usage = "<outfile>",
},
+ {
+ .name = "exe",
+ .handler = xtensa_cmd_exe,
+ .mode = COMMAND_ANY,
+ .help = "Xtensa stub execution",
+ .usage = "<ascii-encoded hexadecimal instruction bytes>",
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
+const struct command_registration xtensa_command_handlers[] = {
+ {
+ .name = "xtensa",
+ .mode = COMMAND_ANY,
+ .help = "Xtensa command group",
+ .usage = "",
+ .chain = xtensa_any_command_handlers,
+ },
COMMAND_REGISTRATION_DONE
};
diff --git a/src/target/xtensa/xtensa.h b/src/target/xtensa/xtensa.h
index d6000d8..fd03f07 100644
--- a/src/target/xtensa/xtensa.h
+++ b/src/target/xtensa/xtensa.h
@@ -2,6 +2,7 @@
/***************************************************************************
* Generic Xtensa target *
+ * Copyright (C) 2020-2022 Cadence Design Systems, Inc. *
* Copyright (C) 2019 Espressif Systems Ltd. *
***************************************************************************/
@@ -19,41 +20,77 @@
* Holds the interface to Xtensa cores.
*/
-#define XT_ISNS_SZ_MAX 3
+/* Big-endian vs. little-endian detection */
+#define XT_ISBE(X) ((X)->target->endianness == TARGET_BIG_ENDIAN)
-#define XT_PS_RING(_v_) ((uint32_t)((_v_) & 0x3) << 6)
-#define XT_PS_RING_MSK (0x3 << 6)
-#define XT_PS_RING_GET(_v_) (((_v_) >> 6) & 0x3)
-#define XT_PS_CALLINC_MSK (0x3 << 16)
-#define XT_PS_OWB_MSK (0xF << 8)
+/* 24-bit break; BE version field-swapped then byte-swapped for use in memory R/W fns */
+#define XT_INS_BREAK_LE(S, T) (0x004000 | (((S) & 0xF) << 8) | (((T) & 0xF) << 4))
+#define XT_INS_BREAK_BE(S, T) (0x000400 | (((S) & 0xF) << 12) | ((T) & 0xF))
+#define XT_INS_BREAK(X, S, T) (XT_ISBE(X) ? XT_INS_BREAK_BE(S, T) : XT_INS_BREAK_LE(S, T))
-#define XT_LOCAL_MEM_REGIONS_NUM_MAX 8
+/* 16-bit break; BE version field-swapped then byte-swapped for use in memory R/W fns */
+#define XT_INS_BREAKN_LE(IMM4) (0xF02D | (((IMM4) & 0xF) << 8))
+#define XT_INS_BREAKN_BE(IMM4) (0x0FD2 | (((IMM4) & 0xF) << 12))
+#define XT_INS_BREAKN(X, IMM4) (XT_ISBE(X) ? XT_INS_BREAKN_BE(IMM4) : XT_INS_BREAKN_LE(IMM4))
-#define XT_AREGS_NUM_MAX 64
-#define XT_USER_REGS_NUM_MAX 256
+#define XT_ISNS_SZ_MAX 3
-#define XT_MEM_ACCESS_NONE 0x0
-#define XT_MEM_ACCESS_READ 0x1
-#define XT_MEM_ACCESS_WRITE 0x2
+#define XT_PS_RING(_v_) ((uint32_t)((_v_) & 0x3) << 6)
+#define XT_PS_RING_MSK (0x3 << 6)
+#define XT_PS_RING_GET(_v_) (((_v_) >> 6) & 0x3)
+#define XT_PS_CALLINC_MSK (0x3 << 16)
+#define XT_PS_OWB_MSK (0xF << 8)
+#define XT_PS_WOE_MSK BIT(18)
-enum xtensa_mem_err_detect {
- XT_MEM_ERR_DETECT_NONE,
- XT_MEM_ERR_DETECT_PARITY,
- XT_MEM_ERR_DETECT_ECC,
+#define XT_LOCAL_MEM_REGIONS_NUM_MAX 8
+
+#define XT_AREGS_NUM_MAX 64
+#define XT_USER_REGS_NUM_MAX 256
+
+#define XT_MEM_ACCESS_NONE 0x0
+#define XT_MEM_ACCESS_READ 0x1
+#define XT_MEM_ACCESS_WRITE 0x2
+
+#define XT_MAX_TIE_REG_WIDTH (512) /* TIE register file max 4096 bits */
+#define XT_QUERYPKT_RESP_MAX (XT_MAX_TIE_REG_WIDTH * 2 + 1)
+
+enum xtensa_qerr_e {
+ XT_QERR_INTERNAL = 0,
+ XT_QERR_FAIL,
+ XT_QERR_INVAL,
+ XT_QERR_MEM,
+ XT_QERR_NUM,
+};
+
+/* An and ARn registers potentially used as scratch regs */
+enum xtensa_ar_scratch_set_e {
+ XT_AR_SCRATCH_A3 = 0,
+ XT_AR_SCRATCH_AR3,
+ XT_AR_SCRATCH_A4,
+ XT_AR_SCRATCH_AR4,
+ XT_AR_SCRATCH_NUM
+};
+
+struct xtensa_keyval_info_s {
+ char *chrval;
+ int intval;
+};
+
+enum xtensa_type {
+ XT_UNDEF = 0,
+ XT_LX,
};
struct xtensa_cache_config {
uint8_t way_count;
- uint8_t line_size;
- uint16_t size;
- bool writeback;
- enum xtensa_mem_err_detect mem_err_check;
+ uint32_t line_size;
+ uint32_t size;
+ int writeback;
};
struct xtensa_local_mem_region_config {
target_addr_t base;
uint32_t size;
- enum xtensa_mem_err_detect mem_err_check;
int access;
};
@@ -66,13 +103,14 @@ struct xtensa_mmu_config {
bool enabled;
uint8_t itlb_entries_count;
uint8_t dtlb_entries_count;
- bool ivarway56;
- bool dvarway56;
};
-struct xtensa_exception_config {
+struct xtensa_mpu_config {
bool enabled;
- uint8_t depc_num;
+ uint8_t nfgseg;
+ uint32_t minsegsize;
+ bool lockable;
+ bool execonly;
};
struct xtensa_irq_config {
@@ -82,8 +120,8 @@ struct xtensa_irq_config {
struct xtensa_high_prio_irq_config {
bool enabled;
+ uint8_t level_num;
uint8_t excm_level;
- uint8_t nmi_num;
};
struct xtensa_debug_config {
@@ -91,7 +129,7 @@ struct xtensa_debug_config {
uint8_t irq_level;
uint8_t ibreaks_num;
uint8_t dbreaks_num;
- uint8_t icount_sz;
+ uint8_t perfcount_num;
};
struct xtensa_tracing_config {
@@ -100,48 +138,26 @@ struct xtensa_tracing_config {
bool reversed_mem_access;
};
-struct xtensa_timer_irq_config {
- bool enabled;
- uint8_t comp_num;
-};
-
struct xtensa_config {
- bool density;
+ enum xtensa_type core_type;
uint8_t aregs_num;
bool windowed;
bool coproc;
- bool fp_coproc;
- bool loop;
- uint8_t miscregs_num;
- bool threadptr;
- bool boolean;
- bool cond_store;
- bool ext_l32r;
- bool mac16;
- bool reloc_vec;
- bool proc_id;
- bool mem_err_check;
- uint16_t user_regs_num;
- const struct xtensa_user_reg_desc *user_regs;
- int (*fetch_user_regs)(struct target *target);
- int (*queue_write_dirty_user_regs)(struct target *target);
+ bool exceptions;
+ struct xtensa_irq_config irq;
+ struct xtensa_high_prio_irq_config high_irq;
+ struct xtensa_mmu_config mmu;
+ struct xtensa_mpu_config mpu;
+ struct xtensa_debug_config debug;
+ struct xtensa_tracing_config trace;
struct xtensa_cache_config icache;
struct xtensa_cache_config dcache;
struct xtensa_local_mem_config irom;
struct xtensa_local_mem_config iram;
struct xtensa_local_mem_config drom;
struct xtensa_local_mem_config dram;
- struct xtensa_local_mem_config uram;
- struct xtensa_local_mem_config xlmi;
- struct xtensa_mmu_config mmu;
- struct xtensa_exception_config exc;
- struct xtensa_irq_config irq;
- struct xtensa_high_prio_irq_config high_irq;
- struct xtensa_timer_irq_config tim_irq;
- struct xtensa_debug_config debug;
- struct xtensa_tracing_config trace;
- unsigned int gdb_general_regs_num;
- const unsigned int *gdb_regs_mapping;
+ struct xtensa_local_mem_config sram;
+ struct xtensa_local_mem_config srom;
};
typedef uint32_t xtensa_insn_t;
@@ -175,13 +191,26 @@ struct xtensa_sw_breakpoint {
*/
struct xtensa {
unsigned int common_magic;
- const struct xtensa_config *core_config;
+ struct xtensa_chip_common *xtensa_chip;
+ struct xtensa_config *core_config;
struct xtensa_debug_module dbg_mod;
struct reg_cache *core_cache;
- unsigned int regs_num;
+ unsigned int total_regs_num;
+ unsigned int core_regs_num;
+ bool regmap_contiguous;
+ unsigned int genpkt_regs_num;
+ struct xtensa_reg_desc **contiguous_regs_desc;
+ struct reg **contiguous_regs_list;
+ /* Per-config Xtensa registers as specified via "xtreg" in xtensa-core*.cfg */
+ struct xtensa_reg_desc *optregs;
+ unsigned int num_optregs;
+ struct reg *empty_regs;
+ char qpkt_resp[XT_QUERYPKT_RESP_MAX];
/* An array of pointers to buffers to backup registers' values while algo is run on target.
* Size is 'regs_num'. */
void **algo_context_backup;
+ unsigned int eps_dbglevel_idx;
+ unsigned int dbregs_num;
struct target *target;
bool reset_asserted;
enum xtensa_stepping_isr_mode stepping_isr_mode;
@@ -192,11 +221,18 @@ struct xtensa {
bool permissive_mode; /* bypass memory checks */
bool suppress_dsr_errors;
uint32_t smp_break;
+ uint32_t spill_loc;
+ unsigned int spill_bytes;
+ uint8_t *spill_buf;
+ int8_t probe_lsddr32p;
/* Sometimes debug module's 'powered' bit is cleared after reset, but get set after some
* time.This is the number of polling periods after which core is considered to be powered
* off (marked as unexamined) if the bit retains to be cleared (e.g. if core is disabled by
* SW running on target).*/
uint8_t come_online_probes_num;
+ bool proc_syscall;
+ bool halt_request;
+ struct xtensa_keyval_info_s scratch_ars[XT_AR_SCRATCH_NUM];
bool regs_fetched; /* true after first register fetch completed successfully */
};
@@ -210,7 +246,6 @@ static inline struct xtensa *target_to_xtensa(struct target *target)
int xtensa_init_arch_info(struct target *target,
struct xtensa *xtensa,
- const struct xtensa_config *cfg,
const struct xtensa_debug_module_config *dm_cfg);
int xtensa_target_init(struct command_context *cmd_ctx, struct target *target);
void xtensa_target_deinit(struct target *target);
@@ -233,11 +268,41 @@ static inline bool xtensa_data_addr_valid(struct target *target, uint32_t addr)
return true;
if (xtensa_addr_in_mem(&xtensa->core_config->dram, addr))
return true;
- if (xtensa_addr_in_mem(&xtensa->core_config->uram, addr))
+ if (xtensa_addr_in_mem(&xtensa->core_config->sram, addr))
return true;
return false;
}
+static inline int xtensa_queue_dbg_reg_read(struct xtensa *xtensa, unsigned int reg, uint8_t *data)
+{
+ struct xtensa_debug_module *dm = &xtensa->dbg_mod;
+
+ if (!xtensa->core_config->trace.enabled &&
+ (reg <= NARADR_MEMADDREND || (reg >= NARADR_PMG && reg <= NARADR_PMSTAT7))) {
+ LOG_ERROR("Can not access %u reg when Trace Port option disabled!", reg);
+ return ERROR_FAIL;
+ }
+ return dm->dbg_ops->queue_reg_read(dm, reg, data);
+}
+
+static inline int xtensa_queue_dbg_reg_write(struct xtensa *xtensa, unsigned int reg, uint32_t data)
+{
+ struct xtensa_debug_module *dm = &xtensa->dbg_mod;
+
+ if (!xtensa->core_config->trace.enabled &&
+ (reg <= NARADR_MEMADDREND || (reg >= NARADR_PMG && reg <= NARADR_PMSTAT7))) {
+ LOG_ERROR("Can not access %u reg when Trace Port option disabled!", reg);
+ return ERROR_FAIL;
+ }
+ return dm->dbg_ops->queue_reg_write(dm, reg, data);
+}
+
+static inline int xtensa_core_status_clear(struct target *target, uint32_t bits)
+{
+ struct xtensa *xtensa = target_to_xtensa(target);
+ return xtensa_dm_core_status_clear(&xtensa->dbg_mod, bits);
+}
+
int xtensa_core_status_check(struct target *target);
int xtensa_examine(struct target *target);
@@ -248,11 +313,15 @@ int xtensa_smpbreak_write(struct xtensa *xtensa, uint32_t set);
int xtensa_smpbreak_read(struct xtensa *xtensa, uint32_t *val);
xtensa_reg_val_t xtensa_reg_get(struct target *target, enum xtensa_reg_id reg_id);
void xtensa_reg_set(struct target *target, enum xtensa_reg_id reg_id, xtensa_reg_val_t value);
+void xtensa_reg_set_deep_relgen(struct target *target, enum xtensa_reg_id a_idx, xtensa_reg_val_t value);
int xtensa_fetch_all_regs(struct target *target);
int xtensa_get_gdb_reg_list(struct target *target,
struct reg **reg_list[],
int *reg_list_size,
enum target_register_class reg_class);
+uint32_t xtensa_cause_get(struct target *target);
+void xtensa_cause_clear(struct target *target);
+void xtensa_cause_reset(struct target *target);
int xtensa_poll(struct target *target);
void xtensa_on_poll(struct target *target);
int xtensa_halt(struct target *target);
@@ -281,16 +350,22 @@ int xtensa_write_buffer(struct target *target, target_addr_t address, uint32_t c
int xtensa_checksum_memory(struct target *target, target_addr_t address, uint32_t count, uint32_t *checksum);
int xtensa_assert_reset(struct target *target);
int xtensa_deassert_reset(struct target *target);
+int xtensa_soft_reset_halt(struct target *target);
int xtensa_breakpoint_add(struct target *target, struct breakpoint *breakpoint);
int xtensa_breakpoint_remove(struct target *target, struct breakpoint *breakpoint);
int xtensa_watchpoint_add(struct target *target, struct watchpoint *watchpoint);
int xtensa_watchpoint_remove(struct target *target, struct watchpoint *watchpoint);
void xtensa_set_permissive_mode(struct target *target, bool state);
-int xtensa_fetch_user_regs_u32(struct target *target);
-int xtensa_queue_write_dirty_user_regs_u32(struct target *target);
const char *xtensa_get_gdb_arch(struct target *target);
-
-
+int xtensa_gdb_query_custom(struct target *target, const char *packet, char **response_p);
+
+COMMAND_HELPER(xtensa_cmd_xtdef_do, struct xtensa *xtensa);
+COMMAND_HELPER(xtensa_cmd_xtopt_do, struct xtensa *xtensa);
+COMMAND_HELPER(xtensa_cmd_xtmem_do, struct xtensa *xtensa);
+COMMAND_HELPER(xtensa_cmd_xtmpu_do, struct xtensa *xtensa);
+COMMAND_HELPER(xtensa_cmd_xtmmu_do, struct xtensa *xtensa);
+COMMAND_HELPER(xtensa_cmd_xtreg_do, struct xtensa *xtensa);
+COMMAND_HELPER(xtensa_cmd_xtregfmt_do, struct xtensa *xtensa);
COMMAND_HELPER(xtensa_cmd_permissive_mode_do, struct xtensa *xtensa);
COMMAND_HELPER(xtensa_cmd_mask_interrupts_do, struct xtensa *xtensa);
COMMAND_HELPER(xtensa_cmd_smpbreak_do, struct target *target);
@@ -300,8 +375,6 @@ COMMAND_HELPER(xtensa_cmd_tracestart_do, struct xtensa *xtensa);
COMMAND_HELPER(xtensa_cmd_tracestop_do, struct xtensa *xtensa);
COMMAND_HELPER(xtensa_cmd_tracedump_do, struct xtensa *xtensa, const char *fname);
-extern const struct reg_arch_type xtensa_user_reg_u32_type;
-extern const struct reg_arch_type xtensa_user_reg_u128_type;
extern const struct command_registration xtensa_command_handlers[];
#endif /* OPENOCD_TARGET_XTENSA_H */
diff --git a/src/target/xtensa/xtensa_chip.c b/src/target/xtensa/xtensa_chip.c
new file mode 100644
index 0000000..79aa3e4
--- /dev/null
+++ b/src/target/xtensa/xtensa_chip.c
@@ -0,0 +1,170 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/***************************************************************************
+ * Xtensa Chip-level Target Support for OpenOCD *
+ * Copyright (C) 2020-2022 Cadence Design Systems, Inc. *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "assert.h"
+#include <target/target.h>
+#include <target/target_type.h>
+#include <target/arm_adi_v5.h>
+#include <rtos/rtos.h>
+#include "xtensa_chip.h"
+
+int xtensa_chip_init_arch_info(struct target *target, void *arch_info,
+ struct xtensa_debug_module_config *dm_cfg)
+{
+ struct xtensa_chip_common *xtensa_chip = (struct xtensa_chip_common *)arch_info;
+ int ret = xtensa_init_arch_info(target, &xtensa_chip->xtensa, dm_cfg);
+ if (ret != ERROR_OK)
+ return ret;
+ /* All xtensa target structures point back to original xtensa_chip */
+ xtensa_chip->xtensa.xtensa_chip = arch_info;
+ return ERROR_OK;
+}
+
+int xtensa_chip_target_init(struct command_context *cmd_ctx, struct target *target)
+{
+ return xtensa_target_init(cmd_ctx, target);
+}
+
+int xtensa_chip_arch_state(struct target *target)
+{
+ return ERROR_OK;
+}
+
+static int xtensa_chip_poll(struct target *target)
+{
+ enum target_state old_state = target->state;
+ int ret = xtensa_poll(target);
+
+ if (old_state != TARGET_HALTED && target->state == TARGET_HALTED) {
+ /*Call any event callbacks that are applicable */
+ if (old_state == TARGET_DEBUG_RUNNING)
+ target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED);
+ else
+ target_call_event_callbacks(target, TARGET_EVENT_HALTED);
+ }
+
+ return ret;
+}
+
+static int xtensa_chip_virt2phys(struct target *target,
+ target_addr_t virtual, target_addr_t *physical)
+{
+ if (physical) {
+ *physical = virtual;
+ return ERROR_OK;
+ }
+ return ERROR_FAIL;
+}
+
+static const struct xtensa_debug_ops xtensa_chip_dm_dbg_ops = {
+ .queue_enable = xtensa_dm_queue_enable,
+ .queue_reg_read = xtensa_dm_queue_reg_read,
+ .queue_reg_write = xtensa_dm_queue_reg_write
+};
+
+static const struct xtensa_power_ops xtensa_chip_dm_pwr_ops = {
+ .queue_reg_read = xtensa_dm_queue_pwr_reg_read,
+ .queue_reg_write = xtensa_dm_queue_pwr_reg_write
+};
+
+static int xtensa_chip_target_create(struct target *target, Jim_Interp *interp)
+{
+ struct xtensa_debug_module_config xtensa_chip_dm_cfg = {
+ .dbg_ops = &xtensa_chip_dm_dbg_ops,
+ .pwr_ops = &xtensa_chip_dm_pwr_ops,
+ .tap = NULL,
+ .queue_tdi_idle = NULL,
+ .queue_tdi_idle_arg = NULL,
+ };
+
+ xtensa_chip_dm_cfg.tap = target->tap;
+ LOG_DEBUG("JTAG: %s:%s pos %d", target->tap->chip, target->tap->tapname, target->tap->abs_chain_position);
+
+ struct xtensa_chip_common *xtensa_chip = calloc(1, sizeof(struct xtensa_chip_common));
+ if (!xtensa_chip) {
+ LOG_ERROR("Failed to alloc chip-level memory!");
+ return ERROR_FAIL;
+ }
+
+ int ret = xtensa_chip_init_arch_info(target, xtensa_chip, &xtensa_chip_dm_cfg);
+ if (ret != ERROR_OK) {
+ LOG_ERROR("Failed to init arch info!");
+ free(xtensa_chip);
+ return ret;
+ }
+
+ /*Assume running target. If different, the first poll will fix this. */
+ target->state = TARGET_RUNNING;
+ target->debug_reason = DBG_REASON_NOTHALTED;
+ return ERROR_OK;
+}
+
+void xtensa_chip_target_deinit(struct target *target)
+{
+ struct xtensa *xtensa = target_to_xtensa(target);
+ xtensa_target_deinit(target);
+ free(xtensa->xtensa_chip);
+}
+
+static int xtensa_chip_examine(struct target *target)
+{
+ return xtensa_examine(target);
+}
+
+int xtensa_chip_jim_configure(struct target *target, struct jim_getopt_info *goi)
+{
+ target->has_dap = false;
+ return JIM_CONTINUE;
+}
+
+/** Methods for generic example of Xtensa-based chip-level targets. */
+struct target_type xtensa_chip_target = {
+ .name = "xtensa",
+
+ .poll = xtensa_chip_poll,
+ .arch_state = xtensa_chip_arch_state,
+
+ .halt = xtensa_halt,
+ .resume = xtensa_resume,
+ .step = xtensa_step,
+
+ .assert_reset = xtensa_assert_reset,
+ .deassert_reset = xtensa_deassert_reset,
+ .soft_reset_halt = xtensa_soft_reset_halt,
+
+ .virt2phys = xtensa_chip_virt2phys,
+ .mmu = xtensa_mmu_is_enabled,
+ .read_memory = xtensa_read_memory,
+ .write_memory = xtensa_write_memory,
+
+ .read_buffer = xtensa_read_buffer,
+ .write_buffer = xtensa_write_buffer,
+
+ .checksum_memory = xtensa_checksum_memory,
+
+ .get_gdb_reg_list = xtensa_get_gdb_reg_list,
+
+ .add_breakpoint = xtensa_breakpoint_add,
+ .remove_breakpoint = xtensa_breakpoint_remove,
+
+ .add_watchpoint = xtensa_watchpoint_add,
+ .remove_watchpoint = xtensa_watchpoint_remove,
+
+ .target_create = xtensa_chip_target_create,
+ .target_jim_configure = xtensa_chip_jim_configure,
+ .init_target = xtensa_chip_target_init,
+ .examine = xtensa_chip_examine,
+ .deinit_target = xtensa_chip_target_deinit,
+
+ .gdb_query_custom = xtensa_gdb_query_custom,
+
+ .commands = xtensa_command_handlers,
+};
diff --git a/src/target/xtensa/xtensa_chip.h b/src/target/xtensa/xtensa_chip.h
new file mode 100644
index 0000000..5200deb
--- /dev/null
+++ b/src/target/xtensa/xtensa_chip.h
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/***************************************************************************
+ * Xtensa Chip-level Target Support for OpenOCD *
+ * Copyright (C) 2020-2022 Cadence Design Systems, Inc. *
+ ***************************************************************************/
+
+#ifndef OPENOCD_TARGET_XTENSA_CHIP_H
+#define OPENOCD_TARGET_XTENSA_CHIP_H
+
+#include <target/target.h>
+#include "xtensa.h"
+#include "xtensa_debug_module.h"
+
+struct xtensa_chip_common {
+ struct xtensa xtensa;
+ /* Chip-specific extensions can be added here */
+};
+
+static inline struct xtensa_chip_common *target_to_xtensa_chip(struct target *target)
+{
+ return container_of(target->arch_info, struct xtensa_chip_common, xtensa);
+}
+
+int xtensa_chip_init_arch_info(struct target *target, void *arch_info,
+ struct xtensa_debug_module_config *dm_cfg);
+int xtensa_chip_target_init(struct command_context *cmd_ctx, struct target *target);
+int xtensa_chip_arch_state(struct target *target);
+void xtensa_chip_queue_tdi_idle(struct target *target);
+void xtensa_chip_on_reset(struct target *target);
+bool xtensa_chip_on_halt(struct target *target);
+void xtensa_chip_on_poll(struct target *target);
+
+#endif /* OPENOCD_TARGET_XTENSA_CHIP_H */
diff --git a/src/target/xtensa/xtensa_regs.h b/src/target/xtensa/xtensa_regs.h
index 7009a2a..1d9d365 100644
--- a/src/target/xtensa/xtensa_regs.h
+++ b/src/target/xtensa/xtensa_regs.h
@@ -2,6 +2,7 @@
/***************************************************************************
* Generic Xtensa target API for OpenOCD *
+ * Copyright (C) 2020-2022 Cadence Design Systems, Inc. *
* Copyright (C) 2016-2019 Espressif Systems Ltd. *
* Author: Angus Gratton gus@projectgus.com *
***************************************************************************/
@@ -14,6 +15,7 @@ struct reg_arch_type;
enum xtensa_reg_id {
XT_REG_IDX_PC = 0,
XT_REG_IDX_AR0,
+ XT_REG_IDX_ARFIRST = XT_REG_IDX_AR0,
XT_REG_IDX_AR1,
XT_REG_IDX_AR2,
XT_REG_IDX_AR3,
@@ -29,152 +31,23 @@ enum xtensa_reg_id {
XT_REG_IDX_AR13,
XT_REG_IDX_AR14,
XT_REG_IDX_AR15,
- XT_REG_IDX_AR16,
- XT_REG_IDX_AR17,
- XT_REG_IDX_AR18,
- XT_REG_IDX_AR19,
- XT_REG_IDX_AR20,
- XT_REG_IDX_AR21,
- XT_REG_IDX_AR22,
- XT_REG_IDX_AR23,
- XT_REG_IDX_AR24,
- XT_REG_IDX_AR25,
- XT_REG_IDX_AR26,
- XT_REG_IDX_AR27,
- XT_REG_IDX_AR28,
- XT_REG_IDX_AR29,
- XT_REG_IDX_AR30,
- XT_REG_IDX_AR31,
- XT_REG_IDX_AR32,
- XT_REG_IDX_AR33,
- XT_REG_IDX_AR34,
- XT_REG_IDX_AR35,
- XT_REG_IDX_AR36,
- XT_REG_IDX_AR37,
- XT_REG_IDX_AR38,
- XT_REG_IDX_AR39,
- XT_REG_IDX_AR40,
- XT_REG_IDX_AR41,
- XT_REG_IDX_AR42,
- XT_REG_IDX_AR43,
- XT_REG_IDX_AR44,
- XT_REG_IDX_AR45,
- XT_REG_IDX_AR46,
- XT_REG_IDX_AR47,
- XT_REG_IDX_AR48,
- XT_REG_IDX_AR49,
- XT_REG_IDX_AR50,
- XT_REG_IDX_AR51,
- XT_REG_IDX_AR52,
- XT_REG_IDX_AR53,
- XT_REG_IDX_AR54,
- XT_REG_IDX_AR55,
- XT_REG_IDX_AR56,
- XT_REG_IDX_AR57,
- XT_REG_IDX_AR58,
- XT_REG_IDX_AR59,
- XT_REG_IDX_AR60,
- XT_REG_IDX_AR61,
- XT_REG_IDX_AR62,
- XT_REG_IDX_AR63,
- XT_REG_IDX_LBEG,
- XT_REG_IDX_LEND,
- XT_REG_IDX_LCOUNT,
- XT_REG_IDX_SAR,
+ XT_REG_IDX_ARLAST = 64, /* Max 64 ARs */
XT_REG_IDX_WINDOWBASE,
XT_REG_IDX_WINDOWSTART,
- XT_REG_IDX_CONFIGID0,
- XT_REG_IDX_CONFIGID1,
XT_REG_IDX_PS,
- XT_REG_IDX_THREADPTR,
- XT_REG_IDX_BR,
- XT_REG_IDX_SCOMPARE1,
- XT_REG_IDX_ACCLO,
- XT_REG_IDX_ACCHI,
- XT_REG_IDX_M0,
- XT_REG_IDX_M1,
- XT_REG_IDX_M2,
- XT_REG_IDX_M3,
- XT_REG_IDX_F0,
- XT_REG_IDX_F1,
- XT_REG_IDX_F2,
- XT_REG_IDX_F3,
- XT_REG_IDX_F4,
- XT_REG_IDX_F5,
- XT_REG_IDX_F6,
- XT_REG_IDX_F7,
- XT_REG_IDX_F8,
- XT_REG_IDX_F9,
- XT_REG_IDX_F10,
- XT_REG_IDX_F11,
- XT_REG_IDX_F12,
- XT_REG_IDX_F13,
- XT_REG_IDX_F14,
- XT_REG_IDX_F15,
- XT_REG_IDX_FCR,
- XT_REG_IDX_FSR,
- XT_REG_IDX_MMID,
XT_REG_IDX_IBREAKENABLE,
- XT_REG_IDX_MEMCTL,
- XT_REG_IDX_ATOMCTL,
+ XT_REG_IDX_DDR,
XT_REG_IDX_IBREAKA0,
XT_REG_IDX_IBREAKA1,
XT_REG_IDX_DBREAKA0,
XT_REG_IDX_DBREAKA1,
XT_REG_IDX_DBREAKC0,
XT_REG_IDX_DBREAKC1,
- XT_REG_IDX_EPC1,
- XT_REG_IDX_EPC2,
- XT_REG_IDX_EPC3,
- XT_REG_IDX_EPC4,
- XT_REG_IDX_EPC5,
- XT_REG_IDX_EPC6,
- XT_REG_IDX_EPC7,
- XT_REG_IDX_DEPC,
- XT_REG_IDX_EPS2,
- XT_REG_IDX_EPS3,
- XT_REG_IDX_EPS4,
- XT_REG_IDX_EPS5,
- XT_REG_IDX_EPS6,
- XT_REG_IDX_EPS7,
- XT_REG_IDX_EXCSAVE1,
- XT_REG_IDX_EXCSAVE2,
- XT_REG_IDX_EXCSAVE3,
- XT_REG_IDX_EXCSAVE4,
- XT_REG_IDX_EXCSAVE5,
- XT_REG_IDX_EXCSAVE6,
- XT_REG_IDX_EXCSAVE7,
XT_REG_IDX_CPENABLE,
- XT_REG_IDX_INTERRUPT,
- XT_REG_IDX_INTSET,
- XT_REG_IDX_INTCLEAR,
- XT_REG_IDX_INTENABLE,
- XT_REG_IDX_VECBASE,
XT_REG_IDX_EXCCAUSE,
XT_REG_IDX_DEBUGCAUSE,
- XT_REG_IDX_CCOUNT,
- XT_REG_IDX_PRID,
XT_REG_IDX_ICOUNT,
XT_REG_IDX_ICOUNTLEVEL,
- XT_REG_IDX_EXCVADDR,
- XT_REG_IDX_CCOMPARE0,
- XT_REG_IDX_CCOMPARE1,
- XT_REG_IDX_CCOMPARE2,
- XT_REG_IDX_MISC0,
- XT_REG_IDX_MISC1,
- XT_REG_IDX_MISC2,
- XT_REG_IDX_MISC3,
- XT_REG_IDX_LITBASE,
- XT_REG_IDX_PTEVADDR,
- XT_REG_IDX_RASID,
- XT_REG_IDX_ITLBCFG,
- XT_REG_IDX_DTLBCFG,
- XT_REG_IDX_MEPC,
- XT_REG_IDX_MEPS,
- XT_REG_IDX_MESAVE,
- XT_REG_IDX_MESR,
- XT_REG_IDX_MECR,
- XT_REG_IDX_MEVADDR,
XT_REG_IDX_A0,
XT_REG_IDX_A1,
XT_REG_IDX_A2,
@@ -191,77 +64,72 @@ enum xtensa_reg_id {
XT_REG_IDX_A13,
XT_REG_IDX_A14,
XT_REG_IDX_A15,
- XT_REG_IDX_PWRCTL,
- XT_REG_IDX_PWRSTAT,
- XT_REG_IDX_ERISTAT,
- XT_REG_IDX_CS_ITCTRL,
- XT_REG_IDX_CS_CLAIMSET,
- XT_REG_IDX_CS_CLAIMCLR,
- XT_REG_IDX_CS_LOCKACCESS,
- XT_REG_IDX_CS_LOCKSTATUS,
- XT_REG_IDX_CS_AUTHSTATUS,
- XT_REG_IDX_FAULT_INFO,
- XT_REG_IDX_TRAX_ID,
- XT_REG_IDX_TRAX_CTRL,
- XT_REG_IDX_TRAX_STAT,
- XT_REG_IDX_TRAX_DATA,
- XT_REG_IDX_TRAX_ADDR,
- XT_REG_IDX_TRAX_PCTRIGGER,
- XT_REG_IDX_TRAX_PCMATCH,
- XT_REG_IDX_TRAX_DELAY,
- XT_REG_IDX_TRAX_MEMSTART,
- XT_REG_IDX_TRAX_MEMEND,
- XT_REG_IDX_PMG,
- XT_REG_IDX_PMPC,
- XT_REG_IDX_PM0,
- XT_REG_IDX_PM1,
- XT_REG_IDX_PMCTRL0,
- XT_REG_IDX_PMCTRL1,
- XT_REG_IDX_PMSTAT0,
- XT_REG_IDX_PMSTAT1,
- XT_REG_IDX_OCD_ID,
- XT_REG_IDX_OCD_DCRCLR,
- XT_REG_IDX_OCD_DCRSET,
- XT_REG_IDX_OCD_DSR,
- XT_REG_IDX_OCD_DDR,
- XT_NUM_REGS,
- /* chip-specific user registers go after ISA-defined ones */
- XT_USR_REG_START = XT_NUM_REGS
+ XT_NUM_REGS
};
typedef uint32_t xtensa_reg_val_t;
+#define XT_NUM_A_REGS 16
+
enum xtensa_reg_type {
XT_REG_GENERAL = 0, /* General-purpose register; part of the windowed register set */
XT_REG_USER = 1, /* User register, needs RUR to read */
XT_REG_SPECIAL = 2, /* Special register, needs RSR to read */
XT_REG_DEBUG = 3, /* Register used for the debug interface. Don't mess with this. */
XT_REG_RELGEN = 4, /* Relative general address. Points to the absolute addresses plus the window
- *index */
+ * index */
XT_REG_FR = 5, /* Floating-point register */
+ XT_REG_TIE = 6, /* TIE (custom) register */
+ XT_REG_OTHER = 7, /* Other (typically legacy) register */
+ XT_REG_TYPE_NUM,
+
+ /* enum names must be one of the above types + _VAL or _MASK */
+ XT_REG_GENERAL_MASK = 0xFFC0,
+ XT_REG_GENERAL_VAL = 0x0100,
+ XT_REG_USER_MASK = 0xFF00,
+ XT_REG_USER_VAL = 0x0300,
+ XT_REG_SPECIAL_MASK = 0xFF00,
+ XT_REG_SPECIAL_VAL = 0x0200,
+ XT_REG_DEBUG_MASK = 0xFF00,
+ XT_REG_DEBUG_VAL = 0x0200,
+ XT_REG_RELGEN_MASK = 0xFFE0,
+ XT_REG_RELGEN_VAL = 0x0000,
+ XT_REG_FR_MASK = 0xFFF0,
+ XT_REG_FR_VAL = 0x0030,
+ XT_REG_TIE_MASK = 0xF000,
+ XT_REG_TIE_VAL = 0xF000, /* unused */
+ XT_REG_OTHER_MASK = 0xFFFF,
+ XT_REG_OTHER_VAL = 0xF000, /* unused */
+
+ XT_REG_INDEX_MASK = 0x00FF
};
enum xtensa_reg_flags {
XT_REGF_NOREAD = 0x01, /* Register is write-only */
- XT_REGF_COPROC0 = 0x02 /* Can't be read if coproc0 isn't enabled */
+ XT_REGF_COPROC0 = 0x02, /* Can't be read if coproc0 isn't enabled */
+ XT_REGF_MASK = 0x03
};
struct xtensa_reg_desc {
const char *name;
+ bool exist;
unsigned int reg_num; /* ISA register num (meaning depends on register type) */
+ unsigned int dbreg_num; /* Debugger-visible register num (reg type encoded) */
enum xtensa_reg_type type;
enum xtensa_reg_flags flags;
};
-struct xtensa_user_reg_desc {
- const char *name;
- /* ISA register num (meaning depends on register type) */
- unsigned int reg_num;
- enum xtensa_reg_flags flags;
- uint32_t size;
- const struct reg_arch_type *type;
-};
+#define _XT_MK_DBREGN(reg_num, reg_type) \
+ ((reg_type ## _VAL) | (reg_num))
+
+#define _XT_MK_DBREGN_MASK(reg_num, reg_mask) \
+ ((reg_mask) | (reg_num))
+
+#define XT_MK_REG_DESC(n, r, t, f) \
+ { .name = (n), .exist = false, .reg_num = (r), \
+ .dbreg_num = _XT_MK_DBREGN(r, t), .type = (t), \
+ .flags = (f) }
-extern const struct xtensa_reg_desc xtensa_regs[XT_NUM_REGS];
+extern struct xtensa_reg_desc xtensa_regs[XT_NUM_REGS];
#endif /* OPENOCD_TARGET_XTENSA_REGS_H */
diff --git a/tcl/target/esp32.cfg b/tcl/target/esp32.cfg
index f5ca78a..4206080 100644
--- a/tcl/target/esp32.cfg
+++ b/tcl/target/esp32.cfg
@@ -68,3 +68,5 @@ if { $_ONLYCPU != 1 } {
}
gdb_breakpoint_override hard
+
+source [find target/xtensa-core-esp32.cfg]
diff --git a/tcl/target/esp32s2.cfg b/tcl/target/esp32s2.cfg
index 8c5835d..23ada5e 100644
--- a/tcl/target/esp32s2.cfg
+++ b/tcl/target/esp32s2.cfg
@@ -63,3 +63,5 @@ xtensa maskisr on
$_TARGETNAME configure -event reset-assert-post { soft_reset_halt }
gdb_breakpoint_override hard
+
+source [find target/xtensa-core-esp32s2.cfg]
diff --git a/tcl/target/esp32s3.cfg b/tcl/target/esp32s3.cfg
index 967c3a2..a25dc14 100644
--- a/tcl/target/esp32s3.cfg
+++ b/tcl/target/esp32s3.cfg
@@ -124,3 +124,5 @@ if { $_ONLYCPU != 1 } {
}
gdb_breakpoint_override hard
+
+source [find target/xtensa-core-esp32s3.cfg]
diff --git a/tcl/target/xtensa-core-esp32.cfg b/tcl/target/xtensa-core-esp32.cfg
new file mode 100644
index 0000000..e7b5a20
--- /dev/null
+++ b/tcl/target/xtensa-core-esp32.cfg
@@ -0,0 +1,260 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+# OpenOCD configuration file for Xtensa ESP32 target
+
+# Core definition and ABI
+xtensa xtdef LX
+xtensa xtopt arnum 64
+xtensa xtopt windowed 1
+
+# Exception/Interrupt Options
+xtensa xtopt exceptions 1
+xtensa xtopt hipriints 1
+xtensa xtopt intlevels 6
+xtensa xtopt excmlevel 3
+
+# Cache Options
+xtensa xtmem icache 4 0 1
+xtensa xtmem dcache 4 0 1 0
+
+# Memory Options
+xtensa xtmem irom 0x400D0000 0x330000
+xtensa xtmem irom 0x40000000 0x64F00
+xtensa xtmem iram 0x40070000 0x30000
+xtensa xtmem iram 0x400C0000 0x2000
+xtensa xtmem drom 0x3F400000 0x800000
+xtensa xtmem dram 0x3FFAE000 0x52000
+xtensa xtmem dram 0x3FF80000 0x2000
+xtensa xtmem dram 0x3F800000 0x400000
+xtensa xtmem dram 0x50000000 0x2000
+xtensa xtmem dram 0x3FF00000 0x71000
+xtensa xtmem dram 0x60000000 0x20000000
+
+# Memory Protection/Translation Options
+
+# Debug Options
+xtensa xtopt debuglevel 6
+xtensa xtopt ibreaknum 2
+xtensa xtopt dbreaknum 2
+xtensa xtopt tracemem 8192
+xtensa xtopt tracememrev 1
+xtensa xtopt perfcount 2
+
+# Core Registers
+# xtregfmt: Optionally specify "contiguous" vs. "sparse" GDB register map.
+# Default setting is "sparse" and is used with xt-gdb.
+# If contiguous, optional parameter specifies number of registers
+# in "Read General Registers" (g-packet) requests.
+# NOTE: For contiguous format, registers listed in GDB order.
+# xtregs: Total number of Xtensa registers in the system
+xtensa xtregs 205
+xtensa xtregfmt contiguous 105
+xtensa xtreg pc 0x0020
+xtensa xtreg ar0 0x0100
+xtensa xtreg ar1 0x0101
+xtensa xtreg ar2 0x0102
+xtensa xtreg ar3 0x0103
+xtensa xtreg ar4 0x0104
+xtensa xtreg ar5 0x0105
+xtensa xtreg ar6 0x0106
+xtensa xtreg ar7 0x0107
+xtensa xtreg ar8 0x0108
+xtensa xtreg ar9 0x0109
+xtensa xtreg ar10 0x010a
+xtensa xtreg ar11 0x010b
+xtensa xtreg ar12 0x010c
+xtensa xtreg ar13 0x010d
+xtensa xtreg ar14 0x010e
+xtensa xtreg ar15 0x010f
+xtensa xtreg ar16 0x0110
+xtensa xtreg ar17 0x0111
+xtensa xtreg ar18 0x0112
+xtensa xtreg ar19 0x0113
+xtensa xtreg ar20 0x0114
+xtensa xtreg ar21 0x0115
+xtensa xtreg ar22 0x0116
+xtensa xtreg ar23 0x0117
+xtensa xtreg ar24 0x0118
+xtensa xtreg ar25 0x0119
+xtensa xtreg ar26 0x011a
+xtensa xtreg ar27 0x011b
+xtensa xtreg ar28 0x011c
+xtensa xtreg ar29 0x011d
+xtensa xtreg ar30 0x011e
+xtensa xtreg ar31 0x011f
+xtensa xtreg ar32 0x0120
+xtensa xtreg ar33 0x0121
+xtensa xtreg ar34 0x0122
+xtensa xtreg ar35 0x0123
+xtensa xtreg ar36 0x0124
+xtensa xtreg ar37 0x0125
+xtensa xtreg ar38 0x0126
+xtensa xtreg ar39 0x0127
+xtensa xtreg ar40 0x0128
+xtensa xtreg ar41 0x0129
+xtensa xtreg ar42 0x012a
+xtensa xtreg ar43 0x012b
+xtensa xtreg ar44 0x012c
+xtensa xtreg ar45 0x012d
+xtensa xtreg ar46 0x012e
+xtensa xtreg ar47 0x012f
+xtensa xtreg ar48 0x0130
+xtensa xtreg ar49 0x0131
+xtensa xtreg ar50 0x0132
+xtensa xtreg ar51 0x0133
+xtensa xtreg ar52 0x0134
+xtensa xtreg ar53 0x0135
+xtensa xtreg ar54 0x0136
+xtensa xtreg ar55 0x0137
+xtensa xtreg ar56 0x0138
+xtensa xtreg ar57 0x0139
+xtensa xtreg ar58 0x013a
+xtensa xtreg ar59 0x013b
+xtensa xtreg ar60 0x013c
+xtensa xtreg ar61 0x013d
+xtensa xtreg ar62 0x013e
+xtensa xtreg ar63 0x013f
+xtensa xtreg lbeg 0x0200
+xtensa xtreg lend 0x0201
+xtensa xtreg lcount 0x0202
+xtensa xtreg sar 0x0203
+xtensa xtreg windowbase 0x0248
+xtensa xtreg windowstart 0x0249
+xtensa xtreg configid0 0x02b0
+xtensa xtreg configid1 0x02d0
+xtensa xtreg ps 0x02e6
+xtensa xtreg threadptr 0x03e7
+
+# added by hand for esp32
+xtensa xtreg br 0x0204
+xtensa xtreg scompare1 0x020c
+xtensa xtreg acclo 0x0210
+xtensa xtreg acchi 0x0211
+xtensa xtreg m0 0x0220
+xtensa xtreg m1 0x0221
+xtensa xtreg m2 0x0222
+xtensa xtreg m3 0x0223
+xtensa xtreg expstate 0x03e6
+xtensa xtreg f64r_lo 0x03ea
+xtensa xtreg f64r_hi 0x03eb
+xtensa xtreg f64s 0x03ec
+xtensa xtreg f0 0x0030
+xtensa xtreg f1 0x0031
+xtensa xtreg f2 0x0032
+xtensa xtreg f3 0x0033
+xtensa xtreg f4 0x0034
+xtensa xtreg f5 0x0035
+xtensa xtreg f6 0x0036
+xtensa xtreg f7 0x0037
+xtensa xtreg f8 0x0038
+xtensa xtreg f9 0x0039
+xtensa xtreg f10 0x003a
+xtensa xtreg f11 0x003b
+xtensa xtreg f12 0x003c
+xtensa xtreg f13 0x003d
+xtensa xtreg f14 0x003e
+xtensa xtreg f15 0x003f
+xtensa xtreg fcr 0x03e8
+xtensa xtreg fsr 0x03e9
+
+xtensa xtreg mmid 0x0259
+xtensa xtreg ibreakenable 0x0260
+
+xtensa xtreg memctl 0x0261
+xtensa xtreg atomctl 0x0263
+
+xtensa xtreg ddr 0x0268
+xtensa xtreg ibreaka0 0x0280
+xtensa xtreg ibreaka1 0x0281
+xtensa xtreg dbreaka0 0x0290
+xtensa xtreg dbreaka1 0x0291
+xtensa xtreg dbreakc0 0x02a0
+xtensa xtreg dbreakc1 0x02a1
+xtensa xtreg epc1 0x02b1
+xtensa xtreg epc2 0x02b2
+xtensa xtreg epc3 0x02b3
+xtensa xtreg epc4 0x02b4
+xtensa xtreg epc5 0x02b5
+xtensa xtreg epc6 0x02b6
+xtensa xtreg epc7 0x02b7
+xtensa xtreg depc 0x02c0
+xtensa xtreg eps2 0x02c2
+xtensa xtreg eps3 0x02c3
+xtensa xtreg eps4 0x02c4
+xtensa xtreg eps5 0x02c5
+xtensa xtreg eps6 0x02c6
+xtensa xtreg eps7 0x02c7
+xtensa xtreg excsave1 0x02d1
+xtensa xtreg excsave2 0x02d2
+xtensa xtreg excsave3 0x02d3
+xtensa xtreg excsave4 0x02d4
+xtensa xtreg excsave5 0x02d5
+xtensa xtreg excsave6 0x02d6
+xtensa xtreg excsave7 0x02d7
+xtensa xtreg cpenable 0x02e0
+xtensa xtreg interrupt 0x02e2
+xtensa xtreg intset 0x02e2
+xtensa xtreg intclear 0x02e3
+xtensa xtreg intenable 0x02e4
+xtensa xtreg vecbase 0x02e7
+xtensa xtreg exccause 0x02e8
+xtensa xtreg debugcause 0x02e9
+xtensa xtreg ccount 0x02ea
+xtensa xtreg prid 0x02eb
+xtensa xtreg icount 0x02ec
+xtensa xtreg icountlevel 0x02ed
+xtensa xtreg excvaddr 0x02ee
+xtensa xtreg ccompare0 0x02f0
+xtensa xtreg ccompare1 0x02f1
+xtensa xtreg ccompare2 0x02f2
+xtensa xtreg misc0 0x02f4
+xtensa xtreg misc1 0x02f5
+xtensa xtreg misc2 0x02f6
+xtensa xtreg misc3 0x02f7
+xtensa xtreg a0 0x0000
+xtensa xtreg a1 0x0001
+xtensa xtreg a2 0x0002
+xtensa xtreg a3 0x0003
+xtensa xtreg a4 0x0004
+xtensa xtreg a5 0x0005
+xtensa xtreg a6 0x0006
+xtensa xtreg a7 0x0007
+xtensa xtreg a8 0x0008
+xtensa xtreg a9 0x0009
+xtensa xtreg a10 0x000a
+xtensa xtreg a11 0x000b
+xtensa xtreg a12 0x000c
+xtensa xtreg a13 0x000d
+xtensa xtreg a14 0x000e
+xtensa xtreg a15 0x000f
+xtensa xtreg pwrctl 0x2028
+xtensa xtreg pwrstat 0x2029
+xtensa xtreg eristat 0x202a
+xtensa xtreg cs_itctrl 0x202b
+xtensa xtreg cs_claimset 0x202c
+xtensa xtreg cs_claimclr 0x202d
+xtensa xtreg cs_lockaccess 0x202e
+xtensa xtreg cs_lockstatus 0x202f
+xtensa xtreg cs_authstatus 0x2030
+xtensa xtreg fault_info 0x203f
+xtensa xtreg trax_id 0x2040
+xtensa xtreg trax_control 0x2041
+xtensa xtreg trax_status 0x2042
+xtensa xtreg trax_data 0x2043
+xtensa xtreg trax_address 0x2044
+xtensa xtreg trax_pctrigger 0x2045
+xtensa xtreg trax_pcmatch 0x2046
+xtensa xtreg trax_delay 0x2047
+xtensa xtreg trax_memstart 0x2048
+xtensa xtreg trax_memend 0x2049
+xtensa xtreg pmg 0x2057
+xtensa xtreg pmpc 0x2058
+xtensa xtreg pm0 0x2059
+xtensa xtreg pm1 0x205a
+xtensa xtreg pmctrl0 0x2061
+xtensa xtreg pmctrl1 0x2062
+xtensa xtreg pmstat0 0x2069
+xtensa xtreg pmstat1 0x206a
+xtensa xtreg ocdid 0x2071
+xtensa xtreg ocd_dcrclr 0x2072
+xtensa xtreg ocd_dcrset 0x2073
+xtensa xtreg ocd_dsr 0x2074
diff --git a/tcl/target/xtensa-core-esp32s2.cfg b/tcl/target/xtensa-core-esp32s2.cfg
new file mode 100644
index 0000000..e590e51
--- /dev/null
+++ b/tcl/target/xtensa-core-esp32s2.cfg
@@ -0,0 +1,223 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+# OpenOCD configuration file for Xtensa ESP32S2 target
+
+# Core definition and ABI
+xtensa xtdef LX
+xtensa xtopt arnum 64
+xtensa xtopt windowed 1
+
+# Exception/Interrupt Options
+xtensa xtopt exceptions 1
+xtensa xtopt hipriints 1
+xtensa xtopt intlevels 6
+xtensa xtopt excmlevel 3
+
+# Cache Options
+xtensa xtmem icache 4 0 1
+xtensa xtmem dcache 4 0 1 0
+
+# Memory Options
+xtensa xtmem irom 0x40080000 0x780000
+xtensa xtmem irom 0x40000000 0x20000
+xtensa xtmem iram 0x40020000 0x50000
+xtensa xtmem iram 0x40070000 0x2000
+xtensa xtmem drom 0x3F000000 0x400000
+xtensa xtmem drom 0x3F4D3FFC 0xAAC004
+xtensa xtmem dram 0x3FFB0000 0x50000
+xtensa xtmem dram 0x3FF9E000 0x2000
+xtensa xtmem dram 0x50000000 0x2000
+xtensa xtmem dram 0x3F500000 0xA80000
+xtensa xtmem dram 0x3F400000 0xD3FFC
+xtensa xtmem dram 0x60000000 0x20000000
+
+# Memory Protection/Translation Options
+
+# Debug Options
+xtensa xtopt debuglevel 6
+xtensa xtopt ibreaknum 2
+xtensa xtopt dbreaknum 2
+xtensa xtopt tracemem 8192
+xtensa xtopt tracememrev 1
+xtensa xtopt perfcount 2
+
+# Core Registers
+# xtregfmt: Optionally specify "contiguous" vs. "sparse" GDB register map.
+# Default setting is "sparse" and is used with xt-gdb.
+# If contiguous, optional parameter specifies number of registers
+# in "Read General Registers" (g-packet) requests.
+# NOTE: For contiguous format, registers listed in GDB order.
+# xtregs: Total number of Xtensa registers in the system
+xtensa xtregs 171
+xtensa xtregfmt contiguous 72
+xtensa xtreg pc 0x0020
+xtensa xtreg ar0 0x0100
+xtensa xtreg ar1 0x0101
+xtensa xtreg ar2 0x0102
+xtensa xtreg ar3 0x0103
+xtensa xtreg ar4 0x0104
+xtensa xtreg ar5 0x0105
+xtensa xtreg ar6 0x0106
+xtensa xtreg ar7 0x0107
+xtensa xtreg ar8 0x0108
+xtensa xtreg ar9 0x0109
+xtensa xtreg ar10 0x010a
+xtensa xtreg ar11 0x010b
+xtensa xtreg ar12 0x010c
+xtensa xtreg ar13 0x010d
+xtensa xtreg ar14 0x010e
+xtensa xtreg ar15 0x010f
+xtensa xtreg ar16 0x0110
+xtensa xtreg ar17 0x0111
+xtensa xtreg ar18 0x0112
+xtensa xtreg ar19 0x0113
+xtensa xtreg ar20 0x0114
+xtensa xtreg ar21 0x0115
+xtensa xtreg ar22 0x0116
+xtensa xtreg ar23 0x0117
+xtensa xtreg ar24 0x0118
+xtensa xtreg ar25 0x0119
+xtensa xtreg ar26 0x011a
+xtensa xtreg ar27 0x011b
+xtensa xtreg ar28 0x011c
+xtensa xtreg ar29 0x011d
+xtensa xtreg ar30 0x011e
+xtensa xtreg ar31 0x011f
+xtensa xtreg ar32 0x0120
+xtensa xtreg ar33 0x0121
+xtensa xtreg ar34 0x0122
+xtensa xtreg ar35 0x0123
+xtensa xtreg ar36 0x0124
+xtensa xtreg ar37 0x0125
+xtensa xtreg ar38 0x0126
+xtensa xtreg ar39 0x0127
+xtensa xtreg ar40 0x0128
+xtensa xtreg ar41 0x0129
+xtensa xtreg ar42 0x012a
+xtensa xtreg ar43 0x012b
+xtensa xtreg ar44 0x012c
+xtensa xtreg ar45 0x012d
+xtensa xtreg ar46 0x012e
+xtensa xtreg ar47 0x012f
+xtensa xtreg ar48 0x0130
+xtensa xtreg ar49 0x0131
+xtensa xtreg ar50 0x0132
+xtensa xtreg ar51 0x0133
+xtensa xtreg ar52 0x0134
+xtensa xtreg ar53 0x0135
+xtensa xtreg ar54 0x0136
+xtensa xtreg ar55 0x0137
+xtensa xtreg ar56 0x0138
+xtensa xtreg ar57 0x0139
+xtensa xtreg ar58 0x013a
+xtensa xtreg ar59 0x013b
+xtensa xtreg ar60 0x013c
+xtensa xtreg ar61 0x013d
+xtensa xtreg ar62 0x013e
+xtensa xtreg ar63 0x013f
+xtensa xtreg sar 0x0203
+xtensa xtreg windowbase 0x0248
+xtensa xtreg windowstart 0x0249
+xtensa xtreg configid0 0x02b0
+xtensa xtreg configid1 0x02d0
+xtensa xtreg ps 0x02e6
+xtensa xtreg threadptr 0x03e7
+# gpio_out should be 0x0300? Hits an exception on wrover
+xtensa xtreg gpio_out 0x0268
+xtensa xtreg mmid 0x0259
+xtensa xtreg ibreakenable 0x0260
+xtensa xtreg ddr 0x0268
+xtensa xtreg ibreaka0 0x0280
+xtensa xtreg ibreaka1 0x0281
+xtensa xtreg dbreaka0 0x0290
+xtensa xtreg dbreaka1 0x0291
+xtensa xtreg dbreakc0 0x02a0
+xtensa xtreg dbreakc1 0x02a1
+xtensa xtreg epc1 0x02b1
+xtensa xtreg epc2 0x02b2
+xtensa xtreg epc3 0x02b3
+xtensa xtreg epc4 0x02b4
+xtensa xtreg epc5 0x02b5
+xtensa xtreg epc6 0x02b6
+xtensa xtreg epc7 0x02b7
+xtensa xtreg depc 0x02c0
+xtensa xtreg eps2 0x02c2
+xtensa xtreg eps3 0x02c3
+xtensa xtreg eps4 0x02c4
+xtensa xtreg eps5 0x02c5
+xtensa xtreg eps6 0x02c6
+xtensa xtreg eps7 0x02c7
+xtensa xtreg excsave1 0x02d1
+xtensa xtreg excsave2 0x02d2
+xtensa xtreg excsave3 0x02d3
+xtensa xtreg excsave4 0x02d4
+xtensa xtreg excsave5 0x02d5
+xtensa xtreg excsave6 0x02d6
+xtensa xtreg excsave7 0x02d7
+xtensa xtreg cpenable 0x02e0
+xtensa xtreg interrupt 0x02e2
+xtensa xtreg intset 0x02e2
+xtensa xtreg intclear 0x02e3
+xtensa xtreg intenable 0x02e4
+xtensa xtreg vecbase 0x02e7
+xtensa xtreg exccause 0x02e8
+xtensa xtreg debugcause 0x02e9
+xtensa xtreg ccount 0x02ea
+xtensa xtreg prid 0x02eb
+xtensa xtreg icount 0x02ec
+xtensa xtreg icountlevel 0x02ed
+xtensa xtreg excvaddr 0x02ee
+xtensa xtreg ccompare0 0x02f0
+xtensa xtreg ccompare1 0x02f1
+xtensa xtreg ccompare2 0x02f2
+xtensa xtreg misc0 0x02f4
+xtensa xtreg misc1 0x02f5
+xtensa xtreg misc2 0x02f6
+xtensa xtreg misc3 0x02f7
+xtensa xtreg a0 0x0000
+xtensa xtreg a1 0x0001
+xtensa xtreg a2 0x0002
+xtensa xtreg a3 0x0003
+xtensa xtreg a4 0x0004
+xtensa xtreg a5 0x0005
+xtensa xtreg a6 0x0006
+xtensa xtreg a7 0x0007
+xtensa xtreg a8 0x0008
+xtensa xtreg a9 0x0009
+xtensa xtreg a10 0x000a
+xtensa xtreg a11 0x000b
+xtensa xtreg a12 0x000c
+xtensa xtreg a13 0x000d
+xtensa xtreg a14 0x000e
+xtensa xtreg a15 0x000f
+xtensa xtreg pwrctl 0x2028
+xtensa xtreg pwrstat 0x2029
+xtensa xtreg eristat 0x202a
+xtensa xtreg cs_itctrl 0x202b
+xtensa xtreg cs_claimset 0x202c
+xtensa xtreg cs_claimclr 0x202d
+xtensa xtreg cs_lockaccess 0x202e
+xtensa xtreg cs_lockstatus 0x202f
+xtensa xtreg cs_authstatus 0x2030
+xtensa xtreg fault_info 0x203f
+xtensa xtreg trax_id 0x2040
+xtensa xtreg trax_control 0x2041
+xtensa xtreg trax_status 0x2042
+xtensa xtreg trax_data 0x2043
+xtensa xtreg trax_address 0x2044
+xtensa xtreg trax_pctrigger 0x2045
+xtensa xtreg trax_pcmatch 0x2046
+xtensa xtreg trax_delay 0x2047
+xtensa xtreg trax_memstart 0x2048
+xtensa xtreg trax_memend 0x2049
+xtensa xtreg pmg 0x2057
+xtensa xtreg pmpc 0x2058
+xtensa xtreg pm0 0x2059
+xtensa xtreg pm1 0x205a
+xtensa xtreg pmctrl0 0x2061
+xtensa xtreg pmctrl1 0x2062
+xtensa xtreg pmstat0 0x2069
+xtensa xtreg pmstat1 0x206a
+xtensa xtreg ocdid 0x2071
+xtensa xtreg ocd_dcrclr 0x2072
+xtensa xtreg ocd_dcrset 0x2073
+xtensa xtreg ocd_dsr 0x2074
diff --git a/tcl/target/xtensa-core-esp32s3.cfg b/tcl/target/xtensa-core-esp32s3.cfg
new file mode 100644
index 0000000..f5c1cb3
--- /dev/null
+++ b/tcl/target/xtensa-core-esp32s3.cfg
@@ -0,0 +1,297 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+# OpenOCD configuration file for Xtensa ESP32S3 target
+
+# Core definition and ABI
+xtensa xtdef LX
+xtensa xtopt arnum 64
+xtensa xtopt windowed 1
+
+# Exception/Interrupt Options
+xtensa xtopt exceptions 1
+xtensa xtopt hipriints 1
+xtensa xtopt intlevels 6
+xtensa xtopt excmlevel 3
+
+# Cache Options
+
+# Memory Options
+xtensa xtmem irom 0x42000000 0x2000000
+xtensa xtmem irom 0x40000000 0x60000
+xtensa xtmem iram 0x40370000 0x70000
+xtensa xtmem iram 0x600FE000 0x2000
+xtensa xtmem drom 0x3C000000 0x1000000
+xtensa xtmem dram 0x3FC88000 0x78000
+xtensa xtmem dram 0x600FE000 0x2000
+xtensa xtmem dram 0x50000000 0x2000
+xtensa xtmem dram 0x60000000 0x10000000
+
+# Memory Protection/Translation Options
+
+# Debug Options
+xtensa xtopt debuglevel 6
+xtensa xtopt ibreaknum 2
+xtensa xtopt dbreaknum 2
+xtensa xtopt tracemem 16384
+xtensa xtopt tracememrev 1
+xtensa xtopt perfcount 2
+
+
+# Core Registers
+# xtregfmt: Optionally specify "contiguous" vs. "sparse" GDB register map.
+# Default setting is "sparse" and is used with xt-gdb.
+# If contiguous, optional parameter specifies number of registers
+# in "Read General Registers" (g-packet) requests.
+# NOTE: For contiguous format, registers listed in GDB order.
+# xtregs: Total number of Xtensa registers in the system
+xtensa xtregs 244
+xtensa xtregfmt contiguous 128
+xtensa xtreg pc 0x0020
+xtensa xtreg ar0 0x0100
+xtensa xtreg ar1 0x0101
+xtensa xtreg ar2 0x0102
+xtensa xtreg ar3 0x0103
+xtensa xtreg ar4 0x0104
+xtensa xtreg ar5 0x0105
+xtensa xtreg ar6 0x0106
+xtensa xtreg ar7 0x0107
+xtensa xtreg ar8 0x0108
+xtensa xtreg ar9 0x0109
+xtensa xtreg ar10 0x010a
+xtensa xtreg ar11 0x010b
+xtensa xtreg ar12 0x010c
+xtensa xtreg ar13 0x010d
+xtensa xtreg ar14 0x010e
+xtensa xtreg ar15 0x010f
+xtensa xtreg ar16 0x0110
+xtensa xtreg ar17 0x0111
+xtensa xtreg ar18 0x0112
+xtensa xtreg ar19 0x0113
+xtensa xtreg ar20 0x0114
+xtensa xtreg ar21 0x0115
+xtensa xtreg ar22 0x0116
+xtensa xtreg ar23 0x0117
+xtensa xtreg ar24 0x0118
+xtensa xtreg ar25 0x0119
+xtensa xtreg ar26 0x011a
+xtensa xtreg ar27 0x011b
+xtensa xtreg ar28 0x011c
+xtensa xtreg ar29 0x011d
+xtensa xtreg ar30 0x011e
+xtensa xtreg ar31 0x011f
+xtensa xtreg ar32 0x0120
+xtensa xtreg ar33 0x0121
+xtensa xtreg ar34 0x0122
+xtensa xtreg ar35 0x0123
+xtensa xtreg ar36 0x0124
+xtensa xtreg ar37 0x0125
+xtensa xtreg ar38 0x0126
+xtensa xtreg ar39 0x0127
+xtensa xtreg ar40 0x0128
+xtensa xtreg ar41 0x0129
+xtensa xtreg ar42 0x012a
+xtensa xtreg ar43 0x012b
+xtensa xtreg ar44 0x012c
+xtensa xtreg ar45 0x012d
+xtensa xtreg ar46 0x012e
+xtensa xtreg ar47 0x012f
+xtensa xtreg ar48 0x0130
+xtensa xtreg ar49 0x0131
+xtensa xtreg ar50 0x0132
+xtensa xtreg ar51 0x0133
+xtensa xtreg ar52 0x0134
+xtensa xtreg ar53 0x0135
+xtensa xtreg ar54 0x0136
+xtensa xtreg ar55 0x0137
+xtensa xtreg ar56 0x0138
+xtensa xtreg ar57 0x0139
+xtensa xtreg ar58 0x013a
+xtensa xtreg ar59 0x013b
+xtensa xtreg ar60 0x013c
+xtensa xtreg ar61 0x013d
+xtensa xtreg ar62 0x013e
+xtensa xtreg ar63 0x013f
+xtensa xtreg lbeg 0x0200
+xtensa xtreg lend 0x0201
+xtensa xtreg lcount 0x0202
+xtensa xtreg sar 0x0203
+xtensa xtreg windowbase 0x0248
+xtensa xtreg windowstart 0x0249
+xtensa xtreg configid0 0x02b0
+xtensa xtreg configid1 0x02d0
+xtensa xtreg ps 0x02e6
+xtensa xtreg threadptr 0x03e7
+xtensa xtreg br 0x0204
+xtensa xtreg scompare1 0x020c
+xtensa xtreg acclo 0x0210
+xtensa xtreg acchi 0x0211
+xtensa xtreg m0 0x0220
+xtensa xtreg m1 0x0221
+xtensa xtreg m2 0x0222
+xtensa xtreg m3 0x0223
+
+# TODO: update gpioout address while testing on S3 HW
+xtensa xtreg gpioout 0x02f4
+
+xtensa xtreg f0 0x0030
+xtensa xtreg f1 0x0031
+xtensa xtreg f2 0x0032
+xtensa xtreg f3 0x0033
+xtensa xtreg f4 0x0034
+xtensa xtreg f5 0x0035
+xtensa xtreg f6 0x0036
+xtensa xtreg f7 0x0037
+xtensa xtreg f8 0x0038
+xtensa xtreg f9 0x0039
+xtensa xtreg f10 0x003a
+xtensa xtreg f11 0x003b
+xtensa xtreg f12 0x003c
+xtensa xtreg f13 0x003d
+xtensa xtreg f14 0x003e
+xtensa xtreg f15 0x003f
+xtensa xtreg fcr 0x03e8
+xtensa xtreg fsr 0x03e9
+
+# TODO: update TIE state
+xtensa xtreg accx_0 0x02f4
+xtensa xtreg accx_1 0x02f4
+xtensa xtreg qacc_h_0 0x02f4
+xtensa xtreg qacc_h_1 0x02f4
+xtensa xtreg qacc_h_2 0x02f4
+xtensa xtreg qacc_h_3 0x02f4
+xtensa xtreg qacc_h_4 0x02f4
+xtensa xtreg qacc_l_0 0x02f4
+xtensa xtreg qacc_l_1 0x02f4
+xtensa xtreg qacc_l_2 0x02f4
+xtensa xtreg qacc_l_3 0x02f4
+xtensa xtreg qacc_l_4 0x02f4
+xtensa xtreg sar_byte 0x02f4
+xtensa xtreg fft_bit_width 0x02f4
+xtensa xtreg ua_state_0 0x02f4
+xtensa xtreg ua_state_1 0x02f4
+xtensa xtreg ua_state_2 0x02f4
+xtensa xtreg ua_state_3 0x02f4
+xtensa xtreg q0 0x02f4
+xtensa xtreg q1 0x02f4
+xtensa xtreg q2 0x02f4
+xtensa xtreg q3 0x02f4
+xtensa xtreg q4 0x02f4
+xtensa xtreg q5 0x02f4
+xtensa xtreg q6 0x02f4
+xtensa xtreg q7 0x02f4
+
+xtensa xtreg mmid 0x0259
+xtensa xtreg ibreakenable 0x0260
+xtensa xtreg memctl 0x0261
+xtensa xtreg atomctl 0x0263
+xtensa xtreg ddr 0x0268
+xtensa xtreg ibreaka0 0x0280
+xtensa xtreg ibreaka1 0x0281
+xtensa xtreg dbreaka0 0x0290
+xtensa xtreg dbreaka1 0x0291
+xtensa xtreg dbreakc0 0x02a0
+xtensa xtreg dbreakc1 0x02a1
+xtensa xtreg epc1 0x02b1
+xtensa xtreg epc2 0x02b2
+xtensa xtreg epc3 0x02b3
+xtensa xtreg epc4 0x02b4
+xtensa xtreg epc5 0x02b5
+xtensa xtreg epc6 0x02b6
+xtensa xtreg epc7 0x02b7
+xtensa xtreg depc 0x02c0
+xtensa xtreg eps2 0x02c2
+xtensa xtreg eps3 0x02c3
+xtensa xtreg eps4 0x02c4
+xtensa xtreg eps5 0x02c5
+xtensa xtreg eps6 0x02c6
+xtensa xtreg eps7 0x02c7
+xtensa xtreg excsave1 0x02d1
+xtensa xtreg excsave2 0x02d2
+xtensa xtreg excsave3 0x02d3
+xtensa xtreg excsave4 0x02d4
+xtensa xtreg excsave5 0x02d5
+xtensa xtreg excsave6 0x02d6
+xtensa xtreg excsave7 0x02d7
+xtensa xtreg cpenable 0x02e0
+xtensa xtreg interrupt 0x02e2
+xtensa xtreg intset 0x02e2
+xtensa xtreg intclear 0x02e3
+xtensa xtreg intenable 0x02e4
+xtensa xtreg vecbase 0x02e7
+xtensa xtreg exccause 0x02e8
+xtensa xtreg debugcause 0x02e9
+xtensa xtreg ccount 0x02ea
+xtensa xtreg prid 0x02eb
+xtensa xtreg icount 0x02ec
+xtensa xtreg icountlevel 0x02ed
+xtensa xtreg excvaddr 0x02ee
+xtensa xtreg ccompare0 0x02f0
+xtensa xtreg ccompare1 0x02f1
+xtensa xtreg ccompare2 0x02f2
+xtensa xtreg misc0 0x02f4
+xtensa xtreg misc1 0x02f5
+xtensa xtreg misc2 0x02f6
+xtensa xtreg misc3 0x02f7
+xtensa xtreg pwrctl 0x2025
+xtensa xtreg pwrstat 0x2026
+xtensa xtreg eristat 0x2027
+xtensa xtreg cs_itctrl 0x2028
+xtensa xtreg cs_claimset 0x2029
+xtensa xtreg cs_claimclr 0x202a
+xtensa xtreg cs_lockaccess 0x202b
+xtensa xtreg cs_lockstatus 0x202c
+xtensa xtreg cs_authstatus 0x202d
+xtensa xtreg fault_info 0x203c
+xtensa xtreg trax_id 0x203d
+xtensa xtreg trax_control 0x203e
+xtensa xtreg trax_status 0x203f
+xtensa xtreg trax_data 0x2040
+xtensa xtreg trax_address 0x2041
+xtensa xtreg trax_pctrigger 0x2042
+xtensa xtreg trax_pcmatch 0x2043
+xtensa xtreg trax_delay 0x2044
+xtensa xtreg trax_memstart 0x2045
+xtensa xtreg trax_memend 0x2046
+xtensa xtreg pmg 0x2054
+xtensa xtreg pmpc 0x2055
+xtensa xtreg pm0 0x2056
+xtensa xtreg pm1 0x2057
+xtensa xtreg pmctrl0 0x2058
+xtensa xtreg pmctrl1 0x2059
+xtensa xtreg pmstat0 0x205a
+xtensa xtreg pmstat1 0x205b
+xtensa xtreg ocdid 0x205c
+xtensa xtreg ocd_dcrclr 0x205d
+xtensa xtreg ocd_dcrset 0x205e
+xtensa xtreg ocd_dsr 0x205f
+xtensa xtreg a0 0x0000
+xtensa xtreg a1 0x0001
+xtensa xtreg a2 0x0002
+xtensa xtreg a3 0x0003
+xtensa xtreg a4 0x0004
+xtensa xtreg a5 0x0005
+xtensa xtreg a6 0x0006
+xtensa xtreg a7 0x0007
+xtensa xtreg a8 0x0008
+xtensa xtreg a9 0x0009
+xtensa xtreg a10 0x000a
+xtensa xtreg a11 0x000b
+xtensa xtreg a12 0x000c
+xtensa xtreg a13 0x000d
+xtensa xtreg a14 0x000e
+xtensa xtreg a15 0x000f
+xtensa xtreg b0 0x0010
+xtensa xtreg b1 0x0011
+xtensa xtreg b2 0x0012
+xtensa xtreg b3 0x0013
+xtensa xtreg b4 0x0014
+xtensa xtreg b5 0x0015
+xtensa xtreg b6 0x0016
+xtensa xtreg b7 0x0017
+xtensa xtreg b8 0x0018
+xtensa xtreg b9 0x0019
+xtensa xtreg b10 0x001a
+xtensa xtreg b11 0x001b
+xtensa xtreg b12 0x001c
+xtensa xtreg b13 0x001d
+xtensa xtreg b14 0x001e
+xtensa xtreg b15 0x001f