target: add generic Xtensa LX support 55/7055/18
authorIan Thompson <ianst@cadence.com>
Sat, 25 Jun 2022 05:27:32 +0000 (22:27 -0700)
committerAntonio Borneo <borneo.antonio@gmail.com>
Sat, 20 Aug 2022 15:38:41 +0000 (15:38 +0000)
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>
25 files changed:
doc/openocd.texi
src/target/espressif/Makefile.am
src/target/espressif/esp32.c
src/target/espressif/esp32.h [deleted file]
src/target/espressif/esp32s2.c
src/target/espressif/esp32s2.h [deleted file]
src/target/espressif/esp32s3.c
src/target/espressif/esp32s3.h [deleted file]
src/target/espressif/esp_xtensa.c
src/target/espressif/esp_xtensa.h
src/target/espressif/esp_xtensa_smp.c
src/target/espressif/esp_xtensa_smp.h
src/target/target.c
src/target/xtensa/Makefile.am
src/target/xtensa/xtensa.c
src/target/xtensa/xtensa.h
src/target/xtensa/xtensa_chip.c [new file with mode: 0644]
src/target/xtensa/xtensa_chip.h [new file with mode: 0644]
src/target/xtensa/xtensa_regs.h
tcl/target/esp32.cfg
tcl/target/esp32s2.cfg
tcl/target/esp32s3.cfg
tcl/target/xtensa-core-esp32.cfg [new file with mode: 0644]
tcl/target/xtensa-core-esp32s2.cfg [new file with mode: 0644]
tcl/target/xtensa-core-esp32s3.cfg [new file with mode: 0644]

index 9a5ab9a186180fc52ff01a42c6f8b534daa4cd52..0df25406ffb886768e1de8c0958a265cc6a7f26c 100644 (file)
@@ -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.
index df002b33bc2d994c32d6c3be0dec52f8f8a9c27c..1b4f8062e31a08bd7dacb16b24b028f58f02357a 100644 (file)
@@ -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
index de8f1aacf73cd1cc65e431a99e2662f401bbe68a..a083627fbcfa042263afe04b37fd7024977c6af5 100644 (file)
@@ -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 (file)
index f07c08d..0000000
+++ /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 */
index bbf7ff5afaecde75461af49b1cee27148e4be498..0bcd20f2d22ad3e92e4c616fc0978adc94702c7c 100644 (file)
@@ -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 */
 #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 (file)
index 26fc7a1..0000000
+++ /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 */
index b5487407f3e706ddd09231df43a8d62104ac8937..b870059017de01dbc16429a940debb972f9a89f5 100644 (file)
@@ -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 (file)
index a7d57ec..0000000
+++ /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 */
index ce1601289c24b9c34daf181ae576b44947d2bb1a..fcd42eac30b91b50808f6c0e5a13314e7cc1257d 100644 (file)
 
 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)
index 4bbbd756ca746f8c38f5b87666af0e59f0fa0e45..61e87c086d068d286859f47b3dd7097c029c320b 100644 (file)
@@ -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);
index 6060662475d64976b4e2f0d1d36936f610fa707a..b109f3c5e9bad54108d2f7ee8ebd49c748c7d29b 100644 (file)
@@ -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);
@@ -632,6 +764,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,
index 159125d37b248950f2cdfb75cb83a960322b71b1..bafd4206672b01fbc4c799251163b32e1ede74a2 100644 (file)
@@ -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);
 
index 10a25efde6193afeedb04b7310374807df8a7b13..9b07dbf6185fc98e2b90c6c9125cb0bc11d073dd 100644 (file)
@@ -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,
index a11e58530cfe029896403f2bf5192eca9fd1910c..94c7c4a85b7263aa01856312e6a0053bd62dc872 100644 (file)
@@ -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
index 6f9d77e6cc80993edd5172c27b70bf4a2b20183f..fe0f43882b09106299d6ad958717645d8bc5da4e 100644 (file)
@@ -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                              *
 #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)
-
-/* 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_WFR(X, FR, T) _XT_INS_FORMAT_RRR(X, 0xFA0000, ((T << 4) | 0x5), FR)
 
-#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_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_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;
-}
-
-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;
+               xtensa_window_state_restore(target, woe);
 
-       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,34 +1831,49 @@ 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_dbg_reg_read(xtensa, NARADR_DDR,
+                       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]);
                }
                /* Grab bytes */
@@ -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
 };
index d6000d80e7a00f5ae4c4e365fd0869941b3215ad..fd03f07f85375ff10dcf57eab806063e5d4158bb 100644 (file)
@@ -2,6 +2,7 @@
 
 /***************************************************************************
  *   Generic Xtensa target                                                 *
+ *   Copyright (C) 2020-2022 Cadence Design Systems, Inc.                  *
  *   Copyright (C) 2019 Espressif Systems Ltd.                             *
  ***************************************************************************/
 
  * 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 (file)
index 0000000..79aa3e4
--- /dev/null
@@ -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 (file)
index 0000000..5200deb
--- /dev/null
@@ -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 */
index 7009a2a5fce4c89d61f8e33ec8e98335d49dc855..1d9d3657ac86c14bfd3b8dfd3314a458a28cb6e0 100644 (file)
@@ -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 */
index f5ca78ac86094d08d7261acb9cf97878f80c16ea..4206080acb7f4fdc628f830709f75e03169be17c 100644 (file)
@@ -68,3 +68,5 @@ if { $_ONLYCPU != 1 } {
 }
 
 gdb_breakpoint_override hard
+
+source [find target/xtensa-core-esp32.cfg]
index 8c5835da60a6ae2076c2241bdcbcc2d19b40dc8d..23ada5e9b0cc180f7eb84d2cc4c123fbb1683007 100644 (file)
@@ -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]
index 967c3a2d1017154c131de5de0a83b4617044b6e2..a25dc145c5f37cdb1b1063bea9a9bdcb33649dbb 100644 (file)
@@ -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 (file)
index 0000000..e7b5a20
--- /dev/null
@@ -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 (file)
index 0000000..e590e51
--- /dev/null
@@ -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 (file)
index 0000000..f5c1cb3
--- /dev/null
@@ -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

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)