target: add Espressif ESP32-S2 basic support

ESP32-S2 is a single core Xtensa chip.
Not full featured yet. Some of the missing functionality:
-Semihosting
-Flash breakpoints
-Flash loader
-Apptrace
-FreeRTOS

Signed-off-by: Erhan Kurubas <erhan.kurubas@espressif.com>
Change-Id: I2fb32978e801af5aa21616c581691406ad7cd6bb
Reviewed-on: https://review.openocd.org/c/openocd/+/6940
Reviewed-by: Tomas Vanek <vanekt@fbl.cz>
Reviewed-by: Ian Thompson <ianst@cadence.com>
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
Tested-by: jenkins
This commit is contained in:
Erhan Kurubas 2022-04-21 07:53:54 +02:00 committed by Antonio Borneo
parent b470b664ca
commit 78c87f5e81
17 changed files with 5122 additions and 1 deletions

View File

@ -4895,6 +4895,7 @@ compact Thumb2 instruction set. Supports also ARMv6-M and ARMv8-M cores
@item @code{dsp5680xx} -- implements Freescale's 5680x DSP.
@item @code{esirisc} -- this is an EnSilica eSi-RISC core.
The current implementation supports eSi-32xx cores.
@item @code{esp32s2} -- this is an Espressif SoC with single Xtensa core.
@item @code{fa526} -- resembles arm920 (w/o Thumb).
@item @code{feroceon} -- resembles arm926.
@item @code{hla_target} -- a Cortex-M alternative to work with HL adapters like ST-Link.
@ -10956,6 +10957,94 @@ STMicroelectronics, based on a proprietary 8-bit core architecture.
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 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
@uref{https://www.espressif.com/en/products/socs, ESP32 family}.
@subsection General Xtensa Commands
@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
@item @code{none} - Core's "break/stall network" is disconnected. Core is not affected by any debug
signal from other cores.
@item @code{breakinout} - Core's "break network" is fully connected (break inputs and outputs are enabled).
Core will receive debug break signals from other cores and send such signals to them. For example when another core
is stopped due to breakpoint hit this core will be stopped too and vice versa.
@item @code{runstall} - Core's "stall network" is fully connected (stall inputs and outputs are enabled).
This feature is not well implemented and tested yet.
@item @code{BreakIn} - Core's "break-in" signal is enabled.
Core will receive debug break signals from other cores. For example when another core is
stopped due to breakpoint hit this core will be stopped too.
@item @code{BreakOut} - Core's "break-out" signal is enabled.
Core will send debug break signal to other cores. For example when this core is
stopped due to breakpoint hit other cores with enabled break-in signals will be stopped too.
@item @code{RunStallIn} - Core's "runstall-in" signal is enabled.
This feature is not well implemented and tested yet.
@item @code{DebugModeOut} - Core's "debugmode-out" signal is enabled.
This feature is not well implemented and tested yet.
@end itemize
@end deffn
@deffn {Command} {xtensa perfmon_enable} <counter_id> <select> [mask] [kernelcnt] [tracelevel]
Enable and start performance counter.
@itemize @bullet
@item @code{counter_id} - Counter ID (0-1).
@item @code{select} - Selects performance metric to be counted by the counter,
e.g. 0 - CPU cycles, 2 - retired instructions.
@item @code{mask} - Selects input subsets to be counted (counter will
increment only once even if more than one condition corresponding to a mask bit occurs).
@item @code{kernelcnt} - 0 - count events with "CINTLEVEL <= tracelevel",
1 - count events with "CINTLEVEL > tracelevel".
@item @code{tracelevel} - Compares this value to "CINTLEVEL" when deciding
whether to count.
@end itemize
@end deffn
@deffn {Command} {xtensa perfmon_dump} (counter_id)
Dump performance counter value. If no argument specified, dumps all counters.
@end deffn
@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.
@itemize @bullet
@item @code{pcval} - PC value which will trigger trace data collection stop.
@item @code{maskbitcount} - PC value mask.
@item @code{n} - Maximum number of instructions/words to capture after trace stop trigger.
@end itemize
@end deffn
@deffn {Command} {xtensa tracestop}
Stop current trace as started by the tracestart command.
@end deffn
@deffn {Command} {xtensa tracedump} <outfile>
Dump trace memory to a file.
@end deffn
@anchor{softwaredebugmessagesandtracing}
@section Software Debug Messages and Tracing
@cindex Linux-ARM DCC support

View File

@ -1,5 +1,7 @@
%C%_libtarget_la_LIBADD = %D%/openrisc/libopenrisc.la \
%D%/riscv/libriscv.la
%D%/riscv/libriscv.la \
%D%/xtensa/libxtensa.la \
%D%/espressif/libespressif.la
%C%_libtarget_la_CPPFLAGS = $(AM_CPPFLAGS)
@ -260,3 +262,5 @@ ARC_SRC = \
include %D%/openrisc/Makefile.am
include %D%/riscv/Makefile.am
include %D%/xtensa/Makefile.am
include %D%/espressif/Makefile.am

View File

@ -0,0 +1,6 @@
noinst_LTLIBRARIES += %D%/libespressif.la
%C%_libespressif_la_SOURCES = \
%D%/esp_xtensa.c \
%D%/esp_xtensa.h \
%D%/esp32s2.c \
%D%/esp32s2.h

View File

@ -0,0 +1,715 @@
/***************************************************************************
* ESP32-S2 target for OpenOCD *
* Copyright (C) 2019 Espressif Systems Ltd. *
* Author: Alexey Gerenkov <alexey@espressif.com> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "assert.h"
#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_IROM_MASK_LOW 0x40000000
#define ESP32_S2_IROM_MASK_HIGH 0x40020000
#define ESP32_S2_IRAM_LOW 0x40020000
#define ESP32_S2_IRAM_HIGH 0x40070000
#define ESP32_S2_DRAM_LOW 0x3ffb0000
#define ESP32_S2_DRAM_HIGH 0x40000000
#define ESP32_S2_RTC_IRAM_LOW 0x40070000
#define ESP32_S2_RTC_IRAM_HIGH 0x40072000
#define ESP32_S2_RTC_DRAM_LOW 0x3ff9e000
#define ESP32_S2_RTC_DRAM_HIGH 0x3ffa0000
#define ESP32_S2_RTC_DATA_LOW 0x50000000
#define ESP32_S2_RTC_DATA_HIGH 0x50002000
#define ESP32_S2_EXTRAM_DATA_LOW 0x3f500000
#define ESP32_S2_EXTRAM_DATA_HIGH 0x3ff80000
#define ESP32_S2_DR_REG_LOW 0x3f400000
#define ESP32_S2_DR_REG_HIGH 0x3f4d3FFC
#define ESP32_S2_SYS_RAM_LOW 0x60000000UL
#define ESP32_S2_SYS_RAM_HIGH (ESP32_S2_SYS_RAM_LOW + 0x20000000UL)
/* ESP32-S2 DROM mapping is not contiguous. */
/* IDF declares this as 0x3F000000..0x3FF80000, but there are peripheral registers mapped to
* 0x3f400000..0x3f4d3FFC. */
#define ESP32_S2_DROM0_LOW ESP32_S2_DROM_LOW
#define ESP32_S2_DROM0_HIGH ESP32_S2_DR_REG_LOW
#define ESP32_S2_DROM1_LOW ESP32_S2_DR_REG_HIGH
#define ESP32_S2_DROM1_HIGH ESP32_S2_DROM_HIGH
/* ESP32 WDT */
#define ESP32_S2_WDT_WKEY_VALUE 0x50d83aa1
#define ESP32_S2_TIMG0_BASE 0x3f41F000
#define ESP32_S2_TIMG1_BASE 0x3f420000
#define ESP32_S2_TIMGWDT_CFG0_OFF 0x48
#define ESP32_S2_TIMGWDT_PROTECT_OFF 0x64
#define ESP32_S2_TIMG0WDT_CFG0 (ESP32_S2_TIMG0_BASE + ESP32_S2_TIMGWDT_CFG0_OFF)
#define ESP32_S2_TIMG1WDT_CFG0 (ESP32_S2_TIMG1_BASE + ESP32_S2_TIMGWDT_CFG0_OFF)
#define ESP32_S2_TIMG0WDT_PROTECT (ESP32_S2_TIMG0_BASE + ESP32_S2_TIMGWDT_PROTECT_OFF)
#define ESP32_S2_TIMG1WDT_PROTECT (ESP32_S2_TIMG1_BASE + ESP32_S2_TIMGWDT_PROTECT_OFF)
#define ESP32_S2_RTCCNTL_BASE 0x3f408000
#define ESP32_S2_RTCWDT_CFG_OFF 0x94
#define ESP32_S2_RTCWDT_PROTECT_OFF 0xAC
#define ESP32_S2_SWD_CONF_OFF 0xB0
#define ESP32_S2_SWD_WPROTECT_OFF 0xB4
#define ESP32_S2_RTC_CNTL_DIG_PWC_REG_OFF 0x8C
#define ESP32_S2_RTC_CNTL_DIG_PWC_REG (ESP32_S2_RTCCNTL_BASE + ESP32_S2_RTC_CNTL_DIG_PWC_REG_OFF)
#define ESP32_S2_RTCWDT_CFG (ESP32_S2_RTCCNTL_BASE + ESP32_S2_RTCWDT_CFG_OFF)
#define ESP32_S2_RTCWDT_PROTECT (ESP32_S2_RTCCNTL_BASE + ESP32_S2_RTCWDT_PROTECT_OFF)
#define ESP32_S2_SWD_CONF_REG (ESP32_S2_RTCCNTL_BASE + ESP32_S2_SWD_CONF_OFF)
#define ESP32_S2_SWD_WPROTECT_REG (ESP32_S2_RTCCNTL_BASE + ESP32_S2_SWD_WPROTECT_OFF)
#define ESP32_S2_SWD_AUTO_FEED_EN_M BIT(31)
#define ESP32_S2_SWD_WKEY_VALUE 0x8F1D312AU
#define ESP32_S2_OPTIONS0 (ESP32_S2_RTCCNTL_BASE + 0x0000)
#define ESP32_S2_SW_SYS_RST_M 0x80000000
#define ESP32_S2_SW_SYS_RST_V 0x1
#define ESP32_S2_SW_SYS_RST_S 31
#define ESP32_S2_SW_STALL_PROCPU_C0_M ((ESP32_S2_SW_STALL_PROCPU_C0_V) << (ESP32_S2_SW_STALL_PROCPU_C0_S))
#define ESP32_S2_SW_STALL_PROCPU_C0_V 0x3
#define ESP32_S2_SW_STALL_PROCPU_C0_S 2
#define ESP32_S2_SW_CPU_STALL (ESP32_S2_RTCCNTL_BASE + 0x00B8)
#define ESP32_S2_SW_STALL_PROCPU_C1_M ((ESP32_S2_SW_STALL_PROCPU_C1_V) << (ESP32_S2_SW_STALL_PROCPU_C1_S))
#define ESP32_S2_SW_STALL_PROCPU_C1_V 0x3FU
#define ESP32_S2_SW_STALL_PROCPU_C1_S 26
#define ESP32_S2_CLK_CONF (ESP32_S2_RTCCNTL_BASE + 0x0074)
#define ESP32_S2_CLK_CONF_DEF 0x1583218
#define ESP32_S2_STORE4 (ESP32_S2_RTCCNTL_BASE + 0x00BC)
#define ESP32_S2_STORE5 (ESP32_S2_RTCCNTL_BASE + 0x00C0)
#define ESP32_S2_DPORT_PMS_OCCUPY_3 0x3F4C10E0
#define ESP32_S2_TRACEMEM_BLOCK_SZ 0x4000
#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;
};
static int esp32s2_soc_reset(struct target *target);
static int esp32s2_disable_wdts(struct target *target);
static int esp32s2_assert_reset(struct target *target)
{
return ERROR_OK;
}
static int esp32s2_deassert_reset(struct target *target)
{
struct xtensa *xtensa = target_to_xtensa(target);
LOG_TARGET_DEBUG(target, "begin");
int res = xtensa_deassert_reset(target);
if (res != ERROR_OK)
return res;
/* restore configured value
esp32s2_soc_reset() modified it, but can not restore just after SW reset for some reason (???) */
res = xtensa_smpbreak_write(xtensa, xtensa->smp_break);
if (res != ERROR_OK) {
LOG_ERROR("Failed to restore smpbreak (%d)!", res);
return res;
}
return ERROR_OK;
}
int esp32s2_soft_reset_halt(struct target *target)
{
LOG_TARGET_DEBUG(target, "begin");
/* Reset the SoC first */
int res = esp32s2_soc_reset(target);
if (res != ERROR_OK)
return res;
return xtensa_assert_reset(target);
}
static int esp32s2_set_peri_reg_mask(struct target *target,
target_addr_t addr,
uint32_t mask,
uint32_t val)
{
uint32_t reg_val;
int res = target_read_u32(target, addr, &reg_val);
if (res != ERROR_OK)
return res;
reg_val = (reg_val & (~mask)) | val;
res = target_write_u32(target, addr, reg_val);
if (res != ERROR_OK)
return res;
return ERROR_OK;
}
static int esp32s2_stall_set(struct target *target, bool stall)
{
LOG_TARGET_DEBUG(target, "begin");
int res = esp32s2_set_peri_reg_mask(target,
ESP32_S2_SW_CPU_STALL,
ESP32_S2_SW_STALL_PROCPU_C1_M,
stall ? 0x21U << ESP32_S2_SW_STALL_PROCPU_C1_S : 0);
if (res != ERROR_OK) {
LOG_ERROR("Failed to write ESP32_S2_SW_CPU_STALL (%d)!", res);
return res;
}
res = esp32s2_set_peri_reg_mask(target,
ESP32_S2_OPTIONS0,
ESP32_S2_SW_STALL_PROCPU_C0_M,
stall ? 0x2 << ESP32_S2_SW_STALL_PROCPU_C0_S : 0);
if (res != ERROR_OK) {
LOG_ERROR("Failed to write ESP32_S2_OPTIONS0 (%d)!", res);
return res;
}
return ERROR_OK;
}
static inline int esp32s2_stall(struct target *target)
{
return esp32s2_stall_set(target, true);
}
static inline int esp32s2_unstall(struct target *target)
{
return esp32s2_stall_set(target, false);
}
/* Reset ESP32-S2's peripherals.
Postconditions: all peripherals except RTC_CNTL are reset, CPU's PC is undefined, PRO CPU is halted, APP CPU is in reset
How this works:
0. make sure target is halted; if not, try to halt it; if that fails, try to reset it (via OCD) and then halt
1. Resets clock related registers
2. Stalls CPU
3. trigger SoC reset using RTC_CNTL_SW_SYS_RST bit
4. CPU is reset and stalled at the first reset vector instruction
5. wait for the OCD to be reset
6. halt the target
7. Unstalls CPU
8. Disables WDTs and trace memory mapping
*/
static int esp32s2_soc_reset(struct target *target)
{
int res;
struct xtensa *xtensa = target_to_xtensa(target);
LOG_DEBUG("start");
/* In order to write to peripheral registers, target must be halted first */
if (target->state != TARGET_HALTED) {
LOG_TARGET_DEBUG(target, "Target not halted before SoC reset, trying to halt it first");
xtensa_halt(target);
res = target_wait_state(target, TARGET_HALTED, 1000);
if (res != ERROR_OK) {
LOG_TARGET_DEBUG(target, "Couldn't halt target before SoC reset, trying to do reset-halt");
res = xtensa_assert_reset(target);
if (res != ERROR_OK) {
LOG_TARGET_ERROR(
target,
"Couldn't halt target before SoC reset! (xtensa_assert_reset returned %d)",
res);
return res;
}
alive_sleep(10);
xtensa_poll(target);
int reset_halt_save = target->reset_halt;
target->reset_halt = 1;
res = xtensa_deassert_reset(target);
target->reset_halt = reset_halt_save;
if (res != ERROR_OK) {
LOG_TARGET_ERROR(
target,
"Couldn't halt target before SoC reset! (xtensa_deassert_reset returned %d)",
res);
return res;
}
alive_sleep(10);
xtensa_poll(target);
xtensa_halt(target);
res = target_wait_state(target, TARGET_HALTED, 1000);
if (res != ERROR_OK) {
LOG_TARGET_ERROR(target, "Couldn't halt target before SoC reset");
return res;
}
}
}
assert(target->state == TARGET_HALTED);
/* Set some clock-related RTC registers to the default values */
res = target_write_u32(target, ESP32_S2_STORE4, 0);
if (res != ERROR_OK) {
LOG_ERROR("Failed to write ESP32_S2_STORE4 (%d)!", res);
return res;
}
res = target_write_u32(target, ESP32_S2_STORE5, 0);
if (res != ERROR_OK) {
LOG_ERROR("Failed to write ESP32_S2_STORE5 (%d)!", res);
return res;
}
res = target_write_u32(target, ESP32_S2_RTC_CNTL_DIG_PWC_REG, 0);
if (res != ERROR_OK) {
LOG_ERROR("Failed to write ESP32_S2_RTC_CNTL_DIG_PWC_REG (%d)!", res);
return res;
}
res = target_write_u32(target, ESP32_S2_CLK_CONF, ESP32_S2_CLK_CONF_DEF);
if (res != ERROR_OK) {
LOG_ERROR("Failed to write ESP32_S2_CLK_CONF (%d)!", res);
return res;
}
/* Stall CPU */
res = esp32s2_stall(target);
if (res != ERROR_OK)
return res;
/* enable stall */
res = xtensa_smpbreak_write(xtensa, OCDDCR_RUNSTALLINEN);
if (res != ERROR_OK) {
LOG_ERROR("Failed to set smpbreak (%d)!", res);
return res;
}
/* Reset CPU */
xtensa->suppress_dsr_errors = true;
res = esp32s2_set_peri_reg_mask(target,
ESP32_S2_OPTIONS0,
ESP32_S2_SW_SYS_RST_M,
1U << ESP32_S2_SW_SYS_RST_S);
xtensa->suppress_dsr_errors = false;
if (res != ERROR_OK) {
LOG_ERROR("Failed to write ESP32_S2_OPTIONS0 (%d)!", res);
return res;
}
/* Wait for SoC to reset */
alive_sleep(100);
int timeout = 100;
while (target->state != TARGET_RESET && target->state != TARGET_RUNNING && --timeout > 0) {
alive_sleep(10);
xtensa_poll(target);
}
if (timeout == 0) {
LOG_ERROR("Timed out waiting for CPU to be reset, target->state=%d", target->state);
return ERROR_TARGET_TIMEOUT;
}
xtensa_halt(target);
res = target_wait_state(target, TARGET_HALTED, 1000);
if (res != ERROR_OK) {
LOG_TARGET_ERROR(target, "Couldn't halt target before SoC reset");
return res;
}
/* Unstall CPU */
res = esp32s2_unstall(target);
if (res != ERROR_OK)
return res;
/* Disable WDTs */
res = esp32s2_disable_wdts(target);
if (res != ERROR_OK)
return res;
/* Disable trace memory mapping */
res = target_write_u32(target, ESP32_S2_DPORT_PMS_OCCUPY_3, 0);
if (res != ERROR_OK) {
LOG_ERROR("Failed to write ESP32_S2_DPORT_PMS_OCCUPY_3 (%d)!", res);
return res;
}
return ERROR_OK;
}
static int esp32s2_disable_wdts(struct target *target)
{
/* TIMG1 WDT */
int res = target_write_u32(target, ESP32_S2_TIMG0WDT_PROTECT, ESP32_S2_WDT_WKEY_VALUE);
if (res != ERROR_OK) {
LOG_ERROR("Failed to write ESP32_S2_TIMG0WDT_PROTECT (%d)!", res);
return res;
}
res = target_write_u32(target, ESP32_S2_TIMG0WDT_CFG0, 0);
if (res != ERROR_OK) {
LOG_ERROR("Failed to write ESP32_S2_TIMG0WDT_CFG0 (%d)!", res);
return res;
}
/* TIMG2 WDT */
res = target_write_u32(target, ESP32_S2_TIMG1WDT_PROTECT, ESP32_S2_WDT_WKEY_VALUE);
if (res != ERROR_OK) {
LOG_ERROR("Failed to write ESP32_S2_TIMG1WDT_PROTECT (%d)!", res);
return res;
}
res = target_write_u32(target, ESP32_S2_TIMG1WDT_CFG0, 0);
if (res != ERROR_OK) {
LOG_ERROR("Failed to write ESP32_S2_TIMG1WDT_CFG0 (%d)!", res);
return res;
}
/* RTC WDT */
res = target_write_u32(target, ESP32_S2_RTCWDT_PROTECT, ESP32_S2_WDT_WKEY_VALUE);
if (res != ERROR_OK) {
LOG_ERROR("Failed to write ESP32_S2_RTCWDT_PROTECT (%d)!", res);
return res;
}
res = target_write_u32(target, ESP32_S2_RTCWDT_CFG, 0);
if (res != ERROR_OK) {
LOG_ERROR("Failed to write ESP32_S2_RTCWDT_CFG (%d)!", res);
return res;
}
/* Enable SWD auto-feed */
res = target_write_u32(target, ESP32_S2_SWD_WPROTECT_REG, ESP32_S2_SWD_WKEY_VALUE);
if (res != ERROR_OK) {
LOG_ERROR("Failed to write ESP32_S2_SWD_WPROTECT_REG (%d)!", res);
return res;
}
uint32_t swd_conf_reg = 0;
res = target_read_u32(target, ESP32_S2_SWD_CONF_REG, &swd_conf_reg);
if (res != ERROR_OK) {
LOG_ERROR("Failed to read ESP32_S2_SWD_CONF_REG (%d)!", res);
return res;
}
swd_conf_reg |= ESP32_S2_SWD_AUTO_FEED_EN_M;
res = target_write_u32(target, ESP32_S2_SWD_CONF_REG, swd_conf_reg);
if (res != ERROR_OK) {
LOG_ERROR("Failed to write ESP32_S2_SWD_CONF_REG (%d)!", res);
return res;
}
return ERROR_OK;
}
static int esp32s2_arch_state(struct target *target)
{
return ERROR_OK;
}
static int esp32s2_on_halt(struct target *target)
{
return esp32s2_disable_wdts(target);
}
static int esp32s2_step(struct target *target, int current, target_addr_t address, int handle_breakpoints)
{
int ret = xtensa_step(target, current, address, handle_breakpoints);
if (ret == ERROR_OK) {
esp32s2_on_halt(target);
target_call_event_callbacks(target, TARGET_EVENT_HALTED);
}
return ret;
}
static int esp32s2_poll(struct target *target)
{
enum target_state old_state = target->state;
int ret = esp_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 {
esp32s2_on_halt(target);
target_call_event_callbacks(target, TARGET_EVENT_HALTED);
}
}
return ret;
}
static int esp32s2_virt2phys(struct target *target,
target_addr_t virtual, target_addr_t *physical)
{
*physical = virtual;
return ERROR_OK;
}
static int esp32s2_target_init(struct command_context *cmd_ctx, struct target *target)
{
return esp_xtensa_target_init(cmd_ctx, target);
}
static const struct xtensa_debug_ops esp32s2_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 esp32s2_pwr_ops = {
.queue_reg_read = xtensa_dm_queue_pwr_reg_read,
.queue_reg_write = xtensa_dm_queue_pwr_reg_write
};
static int esp32s2_target_create(struct target *target, Jim_Interp *interp)
{
struct xtensa_debug_module_config esp32s2_dm_cfg = {
.dbg_ops = &esp32s2_dbg_ops,
.pwr_ops = &esp32s2_pwr_ops,
.tap = target->tap,
.queue_tdi_idle = NULL,
.queue_tdi_idle_arg = NULL
};
/* creates xtensa object */
struct esp32s2_common *esp32 = calloc(1, sizeof(*esp32));
if (!esp32) {
LOG_ERROR("Failed to alloc memory for arch info!");
return ERROR_FAIL;
}
int ret = esp_xtensa_init_arch_info(target, &esp32->esp_xtensa, &esp32s2_xtensa_cfg, &esp32s2_dm_cfg);
if (ret != ERROR_OK) {
LOG_ERROR("Failed to init arch info!");
free(esp32);
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;
}
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
};
/* Holds methods for Xtensa targets. */
struct target_type esp32s2_target = {
.name = "esp32s2",
.poll = esp32s2_poll,
.arch_state = esp32s2_arch_state,
.halt = xtensa_halt,
.resume = xtensa_resume,
.step = esp32s2_step,
.assert_reset = esp32s2_assert_reset,
.deassert_reset = esp32s2_deassert_reset,
.soft_reset_halt = esp32s2_soft_reset_halt,
.virt2phys = esp32s2_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_arch = xtensa_get_gdb_arch,
.get_gdb_reg_list = xtensa_get_gdb_reg_list,
.add_breakpoint = esp_xtensa_breakpoint_add,
.remove_breakpoint = esp_xtensa_breakpoint_remove,
.add_watchpoint = xtensa_watchpoint_add,
.remove_watchpoint = xtensa_watchpoint_remove,
.target_create = esp32s2_target_create,
.init_target = esp32s2_target_init,
.examine = xtensa_examine,
.deinit_target = esp_xtensa_target_deinit,
.commands = esp32s2_command_handlers,
};

View File

@ -0,0 +1,40 @@
/***************************************************************************
* ESP32-S2 target for OpenOCD *
* Copyright (C) 2019 Espressif Systems Ltd. *
* Author: Alexey Gerenkov <alexey@espressif.com> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
#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 */

View File

@ -0,0 +1,71 @@
/***************************************************************************
* Espressif Xtensa target API for OpenOCD *
* Copyright (C) 2019 Espressif Systems Ltd. *
* Author: Alexey Gerenkov <alexey@espressif.com> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdbool.h>
#include <stdint.h>
#include <target/smp.h>
#include "esp_xtensa.h"
#include <target/register.h>
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);
}
int esp_xtensa_target_init(struct command_context *cmd_ctx, struct target *target)
{
return xtensa_target_init(cmd_ctx, target);
}
void esp_xtensa_target_deinit(struct target *target)
{
LOG_DEBUG("start");
xtensa_target_deinit(target);
free(target_to_esp_xtensa(target)); /* same as free(xtensa) */
}
int esp_xtensa_arch_state(struct target *target)
{
return ERROR_OK;
}
int esp_xtensa_poll(struct target *target)
{
return xtensa_poll(target);
}
int esp_xtensa_breakpoint_add(struct target *target, struct breakpoint *breakpoint)
{
return xtensa_breakpoint_add(target, breakpoint);
/* flash breakpoints will be handled in another patch */
}
int esp_xtensa_breakpoint_remove(struct target *target, struct breakpoint *breakpoint)
{
return xtensa_breakpoint_remove(target, breakpoint);
/* flash breakpoints will be handled in another patch */
}

View File

@ -0,0 +1,48 @@
/***************************************************************************
* Generic ESP xtensa target implementation for OpenOCD *
* Copyright (C) 2019 Espressif Systems Ltd. *
* Author: Alexey Gerenkov <alexey@espressif.com> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
#ifndef OPENOCD_TARGET_ESP_XTENSA_H
#define OPENOCD_TARGET_ESP_XTENSA_H
#include <helper/command.h>
#include <target/target.h>
#include <target/xtensa/xtensa.h>
struct esp_xtensa_common {
struct xtensa xtensa; /* must be the first element */
};
static inline struct esp_xtensa_common *target_to_esp_xtensa(struct target *target)
{
return container_of(target->arch_info, struct esp_xtensa_common, xtensa);
}
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);
int esp_xtensa_arch_state(struct target *target);
void esp_xtensa_queue_tdi_idle(struct target *target);
int esp_xtensa_breakpoint_add(struct target *target, struct breakpoint *breakpoint);
int esp_xtensa_breakpoint_remove(struct target *target, struct breakpoint *breakpoint);
int esp_xtensa_poll(struct target *target);
#endif /* OPENOCD_TARGET_ESP_XTENSA_H */

View File

@ -105,6 +105,7 @@ extern struct target_type hla_target;
extern struct target_type nds32_v2_target;
extern struct target_type nds32_v3_target;
extern struct target_type nds32_v3m_target;
extern struct target_type esp32s2_target;
extern struct target_type or1k_target;
extern struct target_type quark_x10xx_target;
extern struct target_type quark_d20xx_target;
@ -141,6 +142,7 @@ static struct target_type *target_types[] = {
&nds32_v2_target,
&nds32_v3_target,
&nds32_v3m_target,
&esp32s2_target,
&or1k_target,
&quark_x10xx_target,
&quark_d20xx_target,

View File

@ -0,0 +1,7 @@
noinst_LTLIBRARIES += %D%/libxtensa.la
%C%_libxtensa_la_SOURCES = \
%D%/xtensa.c \
%D%/xtensa.h \
%D%/xtensa_debug_module.c \
%D%/xtensa_debug_module.h \
%D%/xtensa_regs.h

2731
src/target/xtensa/xtensa.c Normal file

File diff suppressed because it is too large Load Diff

309
src/target/xtensa/xtensa.h Normal file
View File

@ -0,0 +1,309 @@
/***************************************************************************
* Generic Xtensa target *
* Copyright (C) 2019 Espressif Systems Ltd. *
* Author: Alexey Gerenkov <alexey@espressif.com> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
#ifndef OPENOCD_TARGET_XTENSA_H
#define OPENOCD_TARGET_XTENSA_H
#include "assert.h"
#include <target/target.h>
#include <target/breakpoints.h>
#include "xtensa_regs.h"
#include "xtensa_debug_module.h"
/**
* @file
* Holds the interface to Xtensa cores.
*/
#define XT_ISNS_SZ_MAX 3
#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_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
enum xtensa_mem_err_detect {
XT_MEM_ERR_DETECT_NONE,
XT_MEM_ERR_DETECT_PARITY,
XT_MEM_ERR_DETECT_ECC,
};
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;
};
struct xtensa_local_mem_region_config {
target_addr_t base;
uint32_t size;
enum xtensa_mem_err_detect mem_err_check;
int access;
};
struct xtensa_local_mem_config {
uint16_t count;
struct xtensa_local_mem_region_config regions[XT_LOCAL_MEM_REGIONS_NUM_MAX];
};
struct xtensa_mmu_config {
bool enabled;
uint8_t itlb_entries_count;
uint8_t dtlb_entries_count;
bool ivarway56;
bool dvarway56;
};
struct xtensa_exception_config {
bool enabled;
uint8_t depc_num;
};
struct xtensa_irq_config {
bool enabled;
uint8_t irq_num;
};
struct xtensa_high_prio_irq_config {
bool enabled;
uint8_t excm_level;
uint8_t nmi_num;
};
struct xtensa_debug_config {
bool enabled;
uint8_t irq_level;
uint8_t ibreaks_num;
uint8_t dbreaks_num;
uint8_t icount_sz;
};
struct xtensa_tracing_config {
bool enabled;
uint32_t mem_sz;
bool reversed_mem_access;
};
struct xtensa_timer_irq_config {
bool enabled;
uint8_t comp_num;
};
struct xtensa_config {
bool density;
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);
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;
};
typedef uint32_t xtensa_insn_t;
enum xtensa_stepping_isr_mode {
XT_STEPPING_ISR_OFF, /* interrupts are disabled during stepping */
XT_STEPPING_ISR_ON, /* interrupts are enabled during stepping */
};
/* Only supported in cores with in-CPU MMU. None of Espressif chips as of now. */
enum xtensa_mode {
XT_MODE_RING0,
XT_MODE_RING1,
XT_MODE_RING2,
XT_MODE_RING3,
XT_MODE_ANY /* special value to run algorithm in current core mode */
};
struct xtensa_sw_breakpoint {
struct breakpoint *oocd_bp;
/* original insn */
uint8_t insn[XT_ISNS_SZ_MAX];
/* original insn size */
uint8_t insn_sz; /* 2 or 3 bytes */
};
#define XTENSA_COMMON_MAGIC 0x54E4E555U
/**
* Represents a generic Xtensa core.
*/
struct xtensa {
unsigned int common_magic;
const struct xtensa_config *core_config;
struct xtensa_debug_module dbg_mod;
struct reg_cache *core_cache;
unsigned int regs_num;
/* An array of pointers to buffers to backup registers' values while algo is run on target.
* Size is 'regs_num'. */
void **algo_context_backup;
struct target *target;
bool reset_asserted;
enum xtensa_stepping_isr_mode stepping_isr_mode;
struct breakpoint **hw_brps;
struct watchpoint **hw_wps;
struct xtensa_sw_breakpoint *sw_brps;
bool trace_active;
bool permissive_mode; /* bypass memory checks */
bool suppress_dsr_errors;
uint32_t smp_break;
/* 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 regs_fetched; /* true after first register fetch completed successfully */
};
static inline struct xtensa *target_to_xtensa(struct target *target)
{
assert(target);
struct xtensa *xtensa = target->arch_info;
assert(xtensa->common_magic == XTENSA_COMMON_MAGIC);
return xtensa;
}
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);
static inline bool xtensa_addr_in_mem(const struct xtensa_local_mem_config *mem, uint32_t addr)
{
for (unsigned int i = 0; i < mem->count; i++) {
if (addr >= mem->regions[i].base &&
addr < mem->regions[i].base + mem->regions[i].size)
return true;
}
return false;
}
static inline bool xtensa_data_addr_valid(struct target *target, uint32_t addr)
{
struct xtensa *xtensa = target_to_xtensa(target);
if (xtensa_addr_in_mem(&xtensa->core_config->drom, 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))
return true;
return false;
}
int xtensa_core_status_check(struct target *target);
int xtensa_examine(struct target *target);
int xtensa_wakeup(struct target *target);
int xtensa_smpbreak_set(struct target *target, uint32_t set);
int xtensa_smpbreak_get(struct target *target, uint32_t *val);
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);
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);
int xtensa_poll(struct target *target);
void xtensa_on_poll(struct target *target);
int xtensa_halt(struct target *target);
int xtensa_resume(struct target *target,
int current,
target_addr_t address,
int handle_breakpoints,
int debug_execution);
int xtensa_prepare_resume(struct target *target,
int current,
target_addr_t address,
int handle_breakpoints,
int debug_execution);
int xtensa_do_resume(struct target *target);
int xtensa_step(struct target *target, int current, target_addr_t address, int handle_breakpoints);
int xtensa_do_step(struct target *target, int current, target_addr_t address, int handle_breakpoints);
int xtensa_mmu_is_enabled(struct target *target, int *enabled);
int xtensa_read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer);
int xtensa_read_buffer(struct target *target, target_addr_t address, uint32_t count, uint8_t *buffer);
int xtensa_write_memory(struct target *target,
target_addr_t address,
uint32_t size,
uint32_t count,
const uint8_t *buffer);
int xtensa_write_buffer(struct target *target, target_addr_t address, uint32_t count, const uint8_t *buffer);
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_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);
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 */

View File

@ -0,0 +1,359 @@
/***************************************************************************
* Generic Xtensa debug module API for OpenOCD *
* Copyright (C) 2019 Espressif Systems Ltd. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "xtensa_debug_module.h"
#define TAPINS_PWRCTL 0x08
#define TAPINS_PWRSTAT 0x09
#define TAPINS_NARSEL 0x1C
#define TAPINS_IDCODE 0x1E
#define TAPINS_BYPASS 0x1F
#define TAPINS_PWRCTL_LEN 8
#define TAPINS_PWRSTAT_LEN 8
#define TAPINS_NARSEL_ADRLEN 8
#define TAPINS_NARSEL_DATALEN 32
#define TAPINS_IDCODE_LEN 32
#define TAPINS_BYPASS_LEN 1
static void xtensa_dm_add_set_ir(struct xtensa_debug_module *dm, uint8_t value)
{
struct scan_field field;
uint8_t t[4] = { 0 };
memset(&field, 0, sizeof(field));
field.num_bits = dm->tap->ir_length;
field.out_value = t;
buf_set_u32(t, 0, field.num_bits, value);
jtag_add_ir_scan(dm->tap, &field, TAP_IDLE);
}
static void xtensa_dm_add_dr_scan(struct xtensa_debug_module *dm,
int len,
const uint8_t *src,
uint8_t *dest,
tap_state_t endstate)
{
struct scan_field field;
memset(&field, 0, sizeof(field));
field.num_bits = len;
field.out_value = src;
field.in_value = dest;
jtag_add_dr_scan(dm->tap, 1, &field, endstate);
}
int xtensa_dm_init(struct xtensa_debug_module *dm, const struct xtensa_debug_module_config *cfg)
{
if (!dm || !cfg)
return ERROR_FAIL;
dm->pwr_ops = cfg->pwr_ops;
dm->dbg_ops = cfg->dbg_ops;
dm->tap = cfg->tap;
dm->queue_tdi_idle = cfg->queue_tdi_idle;
dm->queue_tdi_idle_arg = cfg->queue_tdi_idle_arg;
return ERROR_OK;
}
int xtensa_dm_queue_enable(struct xtensa_debug_module *dm)
{
return dm->dbg_ops->queue_reg_write(dm, NARADR_DCRSET, OCDDCR_ENABLEOCD);
}
int xtensa_dm_queue_reg_read(struct xtensa_debug_module *dm, unsigned int reg, uint8_t *value)
{
uint8_t regdata = (reg << 1) | 0;
uint8_t dummy[4] = { 0, 0, 0, 0 };
if (reg > NARADR_MAX) {
LOG_ERROR("Invalid DBG reg ID %d!", reg);
return ERROR_FAIL;
}
xtensa_dm_add_set_ir(dm, TAPINS_NARSEL);
xtensa_dm_add_dr_scan(dm, TAPINS_NARSEL_ADRLEN, &regdata, NULL, TAP_IDLE);
xtensa_dm_add_dr_scan(dm, TAPINS_NARSEL_DATALEN, dummy, value, TAP_IDLE);
return ERROR_OK;
}
int xtensa_dm_queue_reg_write(struct xtensa_debug_module *dm, unsigned int reg, uint32_t value)
{
uint8_t regdata = (reg << 1) | 1;
uint8_t valdata[] = { value, value >> 8, value >> 16, value >> 24 };
if (reg > NARADR_MAX) {
LOG_ERROR("Invalid DBG reg ID %d!", reg);
return ERROR_FAIL;
}
xtensa_dm_add_set_ir(dm, TAPINS_NARSEL);
xtensa_dm_add_dr_scan(dm, TAPINS_NARSEL_ADRLEN, &regdata, NULL, TAP_IDLE);
xtensa_dm_add_dr_scan(dm, TAPINS_NARSEL_DATALEN, valdata, NULL, TAP_IDLE);
return ERROR_OK;
}
int xtensa_dm_queue_pwr_reg_read(struct xtensa_debug_module *dm, unsigned int reg, uint8_t *data, uint8_t clear)
{
uint8_t value_clr = clear;
uint8_t tap_insn;
int tap_insn_sz;
if (reg == DMREG_PWRCTL) {
tap_insn = TAPINS_PWRCTL;
tap_insn_sz = TAPINS_PWRCTL_LEN;
} else if (reg == DMREG_PWRSTAT) {
tap_insn = TAPINS_PWRSTAT;
tap_insn_sz = TAPINS_PWRSTAT_LEN;
} else {
LOG_ERROR("Invalid PWR reg ID %d!", reg);
return ERROR_FAIL;
}
xtensa_dm_add_set_ir(dm, tap_insn);
xtensa_dm_add_dr_scan(dm, tap_insn_sz, &value_clr, data, TAP_IDLE);
return ERROR_OK;
}
int xtensa_dm_queue_pwr_reg_write(struct xtensa_debug_module *dm, unsigned int reg, uint8_t data)
{
uint8_t value = data;
uint8_t tap_insn;
int tap_insn_sz;
if (reg == DMREG_PWRCTL) {
tap_insn = TAPINS_PWRCTL;
tap_insn_sz = TAPINS_PWRCTL_LEN;
} else if (reg == DMREG_PWRSTAT) {
tap_insn = TAPINS_PWRSTAT;
tap_insn_sz = TAPINS_PWRSTAT_LEN;
} else {
LOG_ERROR("Invalid PWR reg ID %d!", reg);
return ERROR_FAIL;
}
xtensa_dm_add_set_ir(dm, tap_insn);
xtensa_dm_add_dr_scan(dm, tap_insn_sz, &value, NULL, TAP_IDLE);
return ERROR_OK;
}
int xtensa_dm_device_id_read(struct xtensa_debug_module *dm)
{
uint8_t id_buf[sizeof(uint32_t)];
dm->dbg_ops->queue_reg_read(dm, NARADR_OCDID, id_buf);
xtensa_dm_queue_tdi_idle(dm);
int res = jtag_execute_queue();
if (res != ERROR_OK)
return res;
dm->device_id = buf_get_u32(id_buf, 0, 32);
return ERROR_OK;
}
int xtensa_dm_power_status_read(struct xtensa_debug_module *dm, uint32_t clear)
{
/* uint8_t id_buf[sizeof(uint32_t)]; */
/* TODO: JTAG does not work when PWRCTL_JTAGDEBUGUSE is not set.
* It is set in xtensa_examine(), need to move reading of NARADR_OCDID out of this function */
/* dm->dbg_ops->queue_reg_read(dm, NARADR_OCDID, id_buf);
*Read reset state */
dm->pwr_ops->queue_reg_read(dm, DMREG_PWRSTAT, &dm->power_status.stat, clear);
dm->pwr_ops->queue_reg_read(dm, DMREG_PWRSTAT, &dm->power_status.stath, clear);
xtensa_dm_queue_tdi_idle(dm);
return jtag_execute_queue();
}
int xtensa_dm_core_status_read(struct xtensa_debug_module *dm)
{
uint8_t dsr_buf[sizeof(uint32_t)];
xtensa_dm_queue_enable(dm);
dm->dbg_ops->queue_reg_read(dm, NARADR_DSR, dsr_buf);
xtensa_dm_queue_tdi_idle(dm);
int res = jtag_execute_queue();
if (res != ERROR_OK)
return res;
dm->core_status.dsr = buf_get_u32(dsr_buf, 0, 32);
return res;
}
int xtensa_dm_core_status_clear(struct xtensa_debug_module *dm, xtensa_dsr_t bits)
{
dm->dbg_ops->queue_reg_write(dm, NARADR_DSR, bits);
xtensa_dm_queue_tdi_idle(dm);
return jtag_execute_queue();
}
int xtensa_dm_trace_start(struct xtensa_debug_module *dm, struct xtensa_trace_start_config *cfg)
{
/*Turn off trace unit so we can start a new trace. */
dm->dbg_ops->queue_reg_write(dm, NARADR_TRAXCTRL, 0);
xtensa_dm_queue_tdi_idle(dm);
int res = jtag_execute_queue();
if (res != ERROR_OK)
return res;
/*Set up parameters */
dm->dbg_ops->queue_reg_write(dm, NARADR_TRAXADDR, 0);
if (cfg->stopmask != XTENSA_STOPMASK_DISABLED) {
dm->dbg_ops->queue_reg_write(dm, NARADR_PCMATCHCTRL,
(cfg->stopmask << PCMATCHCTRL_PCML_SHIFT));
dm->dbg_ops->queue_reg_write(dm, NARADR_TRIGGERPC, cfg->stoppc);
}
dm->dbg_ops->queue_reg_write(dm, NARADR_DELAYCNT, cfg->after);
/*Options are mostly hardcoded for now. ToDo: make this more configurable. */
dm->dbg_ops->queue_reg_write(
dm,
NARADR_TRAXCTRL,
TRAXCTRL_TREN |
((cfg->stopmask != XTENSA_STOPMASK_DISABLED) ? TRAXCTRL_PCMEN : 0) | TRAXCTRL_TMEN |
(cfg->after_is_words ? 0 : TRAXCTRL_CNTU) | (0 << TRAXCTRL_SMPER_SHIFT) | TRAXCTRL_PTOWS);
xtensa_dm_queue_tdi_idle(dm);
return jtag_execute_queue();
}
int xtensa_dm_trace_stop(struct xtensa_debug_module *dm, bool pto_enable)
{
uint8_t traxctl_buf[sizeof(uint32_t)];
uint32_t traxctl;
struct xtensa_trace_status trace_status;
dm->dbg_ops->queue_reg_read(dm, NARADR_TRAXCTRL, traxctl_buf);
xtensa_dm_queue_tdi_idle(dm);
int res = jtag_execute_queue();
if (res != ERROR_OK)
return res;
traxctl = buf_get_u32(traxctl_buf, 0, 32);
if (!pto_enable)
traxctl &= ~(TRAXCTRL_PTOWS | TRAXCTRL_PTOWT);
dm->dbg_ops->queue_reg_write(dm, NARADR_TRAXCTRL, traxctl | TRAXCTRL_TRSTP);
xtensa_dm_queue_tdi_idle(dm);
res = jtag_execute_queue();
if (res != ERROR_OK)
return res;
/*Check current status of trace hardware */
res = xtensa_dm_trace_status_read(dm, &trace_status);
if (res != ERROR_OK)
return res;
if (trace_status.stat & TRAXSTAT_TRACT) {
LOG_ERROR("Failed to stop tracing (0x%x)!", trace_status.stat);
return ERROR_FAIL;
}
return ERROR_OK;
}
int xtensa_dm_trace_status_read(struct xtensa_debug_module *dm, struct xtensa_trace_status *status)
{
uint8_t traxstat_buf[sizeof(uint32_t)];
dm->dbg_ops->queue_reg_read(dm, NARADR_TRAXSTAT, traxstat_buf);
xtensa_dm_queue_tdi_idle(dm);
int res = jtag_execute_queue();
if (res == ERROR_OK && status)
status->stat = buf_get_u32(traxstat_buf, 0, 32);
return res;
}
int xtensa_dm_trace_config_read(struct xtensa_debug_module *dm, struct xtensa_trace_config *config)
{
uint8_t traxctl_buf[sizeof(uint32_t)];
uint8_t memadrstart_buf[sizeof(uint32_t)];
uint8_t memadrend_buf[sizeof(uint32_t)];
uint8_t adr_buf[sizeof(uint32_t)];
if (!config)
return ERROR_FAIL;
dm->dbg_ops->queue_reg_read(dm, NARADR_TRAXCTRL, traxctl_buf);
dm->dbg_ops->queue_reg_read(dm, NARADR_MEMADDRSTART, memadrstart_buf);
dm->dbg_ops->queue_reg_read(dm, NARADR_MEMADDREND, memadrend_buf);
dm->dbg_ops->queue_reg_read(dm, NARADR_TRAXADDR, adr_buf);
xtensa_dm_queue_tdi_idle(dm);
int res = jtag_execute_queue();
if (res == ERROR_OK) {
config->ctrl = buf_get_u32(traxctl_buf, 0, 32);
config->memaddr_start = buf_get_u32(memadrstart_buf, 0, 32);
config->memaddr_end = buf_get_u32(memadrend_buf, 0, 32);
config->addr = buf_get_u32(adr_buf, 0, 32);
}
return res;
}
int xtensa_dm_trace_data_read(struct xtensa_debug_module *dm, uint8_t *dest, uint32_t size)
{
if (!dest)
return ERROR_FAIL;
for (unsigned int i = 0; i < size / 4; i++)
dm->dbg_ops->queue_reg_read(dm, NARADR_TRAXDATA, &dest[i * 4]);
xtensa_dm_queue_tdi_idle(dm);
return jtag_execute_queue();
}
int xtensa_dm_perfmon_enable(struct xtensa_debug_module *dm, int counter_id,
const struct xtensa_perfmon_config *config)
{
if (!config)
return ERROR_FAIL;
uint8_t pmstat_buf[4];
uint32_t pmctrl = ((config->tracelevel) << 4) +
(config->select << 8) +
(config->mask << 16) +
(config->kernelcnt << 3);
/* enable performance monitor */
dm->dbg_ops->queue_reg_write(dm, NARADR_PMG, 0x1);
/* reset counter */
dm->dbg_ops->queue_reg_write(dm, NARADR_PM0 + counter_id, 0);
dm->dbg_ops->queue_reg_write(dm, NARADR_PMCTRL0 + counter_id, pmctrl);
dm->dbg_ops->queue_reg_read(dm, NARADR_PMSTAT0 + counter_id, pmstat_buf);
xtensa_dm_queue_tdi_idle(dm);
return jtag_execute_queue();
}
int xtensa_dm_perfmon_dump(struct xtensa_debug_module *dm, int counter_id,
struct xtensa_perfmon_result *out_result)
{
uint8_t pmstat_buf[4];
uint8_t pmcount_buf[4];
dm->dbg_ops->queue_reg_read(dm, NARADR_PMSTAT0 + counter_id, pmstat_buf);
dm->dbg_ops->queue_reg_read(dm, NARADR_PM0 + counter_id, pmcount_buf);
xtensa_dm_queue_tdi_idle(dm);
int res = jtag_execute_queue();
if (res == ERROR_OK) {
uint32_t stat = buf_get_u32(pmstat_buf, 0, 32);
uint64_t result = buf_get_u32(pmcount_buf, 0, 32);
/* TODO: if counter # counter_id+1 has 'select' set to 1, use its value as the
* high 32 bits of the counter. */
if (out_result) {
out_result->overflow = ((stat & 1) != 0);
out_result->value = result;
}
}
return res;
}

View File

@ -0,0 +1,385 @@
/***************************************************************************
* Xtensa debug module API *
* Copyright (C) 2019 Espressif Systems Ltd. *
* <alexey@espressif.com> *
* *
* Derived from original ESP8266 target. *
* Copyright (C) 2015 by Angus Gratton *
* gus@projectgus.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
#ifndef OPENOCD_TARGET_XTENSA_DEBUG_MODULE_H
#define OPENOCD_TARGET_XTENSA_DEBUG_MODULE_H
#include <jtag/jtag.h>
#include <helper/bits.h>
#include <target/target.h>
/* Virtual IDs for using with xtensa_power_ops API */
#define DMREG_PWRCTL 0x00
#define DMREG_PWRSTAT 0x01
/*
From the manual:
To properly use Debug registers through JTAG, software must ensure that:
- Tap is out of reset
- Xtensa Debug Module is out of reset
- Other bits of PWRCTL are set to their desired values, and finally
- JtagDebugUse transitions from 0 to 1
The bit must continue to be 1 in order for JTAG accesses to the Debug
Module to happen correctly. When it is set, any write to this bit clears it.
Either don't access it, or re-write it to 1 so JTAG accesses continue.
*/
#define PWRCTL_JTAGDEBUGUSE BIT(7)
#define PWRCTL_DEBUGRESET BIT(6)
#define PWRCTL_CORERESET BIT(4)
#define PWRCTL_DEBUGWAKEUP BIT(2)
#define PWRCTL_MEMWAKEUP BIT(1)
#define PWRCTL_COREWAKEUP BIT(0)
#define PWRSTAT_DEBUGWASRESET BIT(6)
#define PWRSTAT_COREWASRESET BIT(4)
#define PWRSTAT_CORESTILLNEEDED BIT(3)
#define PWRSTAT_DEBUGDOMAINON BIT(2)
#define PWRSTAT_MEMDOMAINON BIT(1)
#define PWRSTAT_COREDOMAINON BIT(0)
/* *** NAR addresses (also used as IDs for debug registers in xtensa_debug_ops API) ***
*TRAX registers */
#define NARADR_TRAXID 0x00
#define NARADR_TRAXCTRL 0x01
#define NARADR_TRAXSTAT 0x02
#define NARADR_TRAXDATA 0x03
#define NARADR_TRAXADDR 0x04
#define NARADR_TRIGGERPC 0x05
#define NARADR_PCMATCHCTRL 0x06
#define NARADR_DELAYCNT 0x07
#define NARADR_MEMADDRSTART 0x08
#define NARADR_MEMADDREND 0x09
/*Performance monitor registers */
#define NARADR_PMG 0x20
#define NARADR_INTPC 0x24
#define NARADR_PM0 0x28
/*... */
#define NARADR_PM7 0x2F
#define NARADR_PMCTRL0 0x30
/*... */
#define NARADR_PMCTRL7 0x37
#define NARADR_PMSTAT0 0x38
/*... */
#define NARADR_PMSTAT7 0x3F
/*OCD registers */
#define NARADR_OCDID 0x40
#define NARADR_DCRCLR 0x42
#define NARADR_DCRSET 0x43
#define NARADR_DSR 0x44
#define NARADR_DDR 0x45
#define NARADR_DDREXEC 0x46
#define NARADR_DIR0EXEC 0x47
#define NARADR_DIR0 0x48
#define NARADR_DIR1 0x49
/*... */
#define NARADR_DIR7 0x4F
/*Misc registers */
#define NARADR_PWRCTL 0x58
#define NARADR_PWRSTAT 0x59
#define NARADR_ERISTAT 0x5A
/*CoreSight registers */
#define NARADR_ITCTRL 0x60
#define NARADR_CLAIMSET 0x68
#define NARADR_CLAIMCLR 0x69
#define NARADR_LOCKACCESS 0x6c
#define NARADR_LOCKSTATUS 0x6d
#define NARADR_AUTHSTATUS 0x6e
#define NARADR_DEVID 0x72
#define NARADR_DEVTYPE 0x73
#define NARADR_PERID4 0x74
/*... */
#define NARADR_PERID7 0x77
#define NARADR_PERID0 0x78
/*... */
#define NARADR_PERID3 0x7b
#define NARADR_COMPID0 0x7c
/*... */
#define NARADR_COMPID3 0x7f
#define NARADR_MAX NARADR_COMPID3
/*OCD registers, bit definitions */
#define OCDDCR_ENABLEOCD BIT(0)
#define OCDDCR_DEBUGINTERRUPT BIT(1)
#define OCDDCR_INTERRUPTALLCONDS BIT(2)
#define OCDDCR_BREAKINEN BIT(16)
#define OCDDCR_BREAKOUTEN BIT(17)
#define OCDDCR_DEBUGSWACTIVE BIT(20)
#define OCDDCR_RUNSTALLINEN BIT(21)
#define OCDDCR_DEBUGMODEOUTEN BIT(22)
#define OCDDCR_BREAKOUTITO BIT(24)
#define OCDDCR_BREAKACKITO BIT(25)
#define OCDDSR_EXECDONE BIT(0)
#define OCDDSR_EXECEXCEPTION BIT(1)
#define OCDDSR_EXECBUSY BIT(2)
#define OCDDSR_EXECOVERRUN BIT(3)
#define OCDDSR_STOPPED BIT(4)
#define OCDDSR_COREWROTEDDR BIT(10)
#define OCDDSR_COREREADDDR BIT(11)
#define OCDDSR_HOSTWROTEDDR BIT(14)
#define OCDDSR_HOSTREADDDR BIT(15)
#define OCDDSR_DEBUGPENDBREAK BIT(16)
#define OCDDSR_DEBUGPENDHOST BIT(17)
#define OCDDSR_DEBUGPENDTRAX BIT(18)
#define OCDDSR_DEBUGINTBREAK BIT(20)
#define OCDDSR_DEBUGINTHOST BIT(21)
#define OCDDSR_DEBUGINTTRAX BIT(22)
#define OCDDSR_RUNSTALLTOGGLE BIT(23)
#define OCDDSR_RUNSTALLSAMPLE BIT(24)
#define OCDDSR_BREACKOUTACKITI BIT(25)
#define OCDDSR_BREAKINITI BIT(26)
#define OCDDSR_DBGMODPOWERON BIT(31)
#define DEBUGCAUSE_IC BIT(0) /* ICOUNT exception */
#define DEBUGCAUSE_IB BIT(1) /* IBREAK exception */
#define DEBUGCAUSE_DB BIT(2) /* DBREAK exception */
#define DEBUGCAUSE_BI BIT(3) /* BREAK instruction encountered */
#define DEBUGCAUSE_BN BIT(4) /* BREAK.N instruction encountered */
#define DEBUGCAUSE_DI BIT(5) /* Debug Interrupt */
#define TRAXCTRL_TREN BIT(0) /* Trace enable. Tracing starts on 0->1 */
#define TRAXCTRL_TRSTP BIT(1) /* Trace Stop. Make 1 to stop trace. */
#define TRAXCTRL_PCMEN BIT(2) /* PC match enable */
#define TRAXCTRL_PTIEN BIT(4) /* Processor-trigger enable */
#define TRAXCTRL_CTIEN BIT(5) /* Cross-trigger enable */
#define TRAXCTRL_TMEN BIT(7) /* Tracemem Enable. Always set. */
#define TRAXCTRL_CNTU BIT(9) /* Post-stop-trigger countdown units; selects when DelayCount-- happens.
*0 - every 32-bit word written to tracemem, 1 - every cpu instruction */
#define TRAXCTRL_TSEN BIT(11) /* Undocumented/deprecated? */
#define TRAXCTRL_SMPER_SHIFT 12 /* Send sync every 2^(9-smper) messages. 7=reserved, 0=no sync msg */
#define TRAXCTRL_SMPER_MASK 0x07 /* Synchronization message period */
#define TRAXCTRL_PTOWT BIT(16) /* Processor Trigger Out (OCD halt) enabled when stop triggered */
#define TRAXCTRL_PTOWS BIT(17) /* Processor Trigger Out (OCD halt) enabled when trace stop completes */
#define TRAXCTRL_CTOWT BIT(20) /* Cross-trigger Out enabled when stop triggered */
#define TRAXCTRL_CTOWS BIT(21) /* Cross-trigger Out enabled when trace stop completes */
#define TRAXCTRL_ITCTO BIT(22) /* Integration mode: cross-trigger output */
#define TRAXCTRL_ITCTIA BIT(23) /* Integration mode: cross-trigger ack */
#define TRAXCTRL_ITATV BIT(24) /* replaces ATID when in integration mode: ATVALID output */
#define TRAXCTRL_ATID_MASK 0x7F /* ARB source ID */
#define TRAXCTRL_ATID_SHIFT 24
#define TRAXCTRL_ATEN BIT(31) /* ATB interface enable */
#define TRAXSTAT_TRACT BIT(0) /* Trace active flag. */
#define TRAXSTAT_TRIG BIT(1) /* Trace stop trigger. Clears on TREN 1->0 */
#define TRAXSTAT_PCMTG BIT(2) /* Stop trigger caused by PC match. Clears on TREN 1->0 */
#define TRAXSTAT_PJTR BIT(3) /* JTAG transaction result. 1=err in preceding jtag transaction. */
#define TRAXSTAT_PTITG BIT(4) /* Stop trigger caused by Processor Trigger Input.Clears on TREN 1->0 */
#define TRAXSTAT_CTITG BIT(5) /* Stop trigger caused by Cross-Trigger Input. Clears on TREN 1->0 */
#define TRAXSTAT_MEMSZ_SHIFT 8 /* Traceram size inducator. Usable trace ram is 2^MEMSZ bytes. */
#define TRAXSTAT_MEMSZ_MASK 0x1F
#define TRAXSTAT_PTO BIT(16) /* Processor Trigger Output: current value */
#define TRAXSTAT_CTO BIT(17) /* Cross-Trigger Output: current value */
#define TRAXSTAT_ITCTOA BIT(22) /* Cross-Trigger Out Ack: current value */
#define TRAXSTAT_ITCTI BIT(23) /* Cross-Trigger Input: current value */
#define TRAXSTAT_ITATR BIT(24) /* ATREADY Input: current value */
#define TRAXADDR_TADDR_SHIFT 0 /* Trax memory address, in 32-bit words. */
#define TRAXADDR_TADDR_MASK 0x1FFFFF /* Actually is only as big as the trace buffer size max addr. */
#define TRAXADDR_TWRAP_SHIFT 21 /* Amount of times TADDR has overflown */
#define TRAXADDR_TWRAP_MASK 0x3FF
#define TRAXADDR_TWSAT BIT(31) /* 1 if TWRAP has overflown, clear by disabling tren.*/
#define PCMATCHCTRL_PCML_SHIFT 0 /* Amount of lower bits to ignore in pc trigger register */
#define PCMATCHCTRL_PCML_MASK 0x1F
#define PCMATCHCTRL_PCMS BIT(31) /* PC Match Sense, 0-match when procs PC is in-range, 1-match when
*out-of-range */
#define XTENSA_MAX_PERF_COUNTERS 2
#define XTENSA_MAX_PERF_SELECT 32
#define XTENSA_MAX_PERF_MASK 0xffff
#define XTENSA_STOPMASK_DISABLED UINT32_MAX
struct xtensa_debug_module;
struct xtensa_debug_ops {
/** enable operation */
int (*queue_enable)(struct xtensa_debug_module *dm);
/** register read. */
int (*queue_reg_read)(struct xtensa_debug_module *dm, unsigned int reg, uint8_t *data);
/** register write. */
int (*queue_reg_write)(struct xtensa_debug_module *dm, unsigned int reg, uint32_t data);
};
struct xtensa_power_ops {
/** register read. */
int (*queue_reg_read)(struct xtensa_debug_module *dm, unsigned int reg, uint8_t *data,
uint8_t clear);
/** register write. */
int (*queue_reg_write)(struct xtensa_debug_module *dm, unsigned int reg, uint8_t data);
};
typedef uint8_t xtensa_pwrstat_t;
typedef uint32_t xtensa_ocdid_t;
typedef uint32_t xtensa_dsr_t;
typedef uint32_t xtensa_traxstat_t;
struct xtensa_power_status {
xtensa_pwrstat_t stat;
xtensa_pwrstat_t stath;
/* TODO: do not need to keep previous status to detect that core or debug module has been
* reset, */
/* we can clear PWRSTAT_DEBUGWASRESET and PWRSTAT_COREWASRESET after reading will do
* the job; */
/* upon next reet those bits will be set again. So we can get rid of
* xtensa_dm_power_status_cache_reset() and xtensa_dm_power_status_cache(). */
xtensa_pwrstat_t prev_stat;
};
struct xtensa_core_status {
xtensa_dsr_t dsr;
};
struct xtensa_trace_config {
uint32_t ctrl;
uint32_t memaddr_start;
uint32_t memaddr_end;
uint32_t addr;
};
struct xtensa_trace_status {
xtensa_traxstat_t stat;
};
struct xtensa_trace_start_config {
uint32_t stoppc;
bool after_is_words;
uint32_t after;
uint32_t stopmask; /* UINT32_MAX: disable PC match option */
};
struct xtensa_perfmon_config {
int select;
uint32_t mask;
int kernelcnt;
int tracelevel;
};
struct xtensa_perfmon_result {
uint64_t value;
bool overflow;
};
struct xtensa_debug_module_config {
const struct xtensa_power_ops *pwr_ops;
const struct xtensa_debug_ops *dbg_ops;
struct jtag_tap *tap;
void (*queue_tdi_idle)(struct target *target);
void *queue_tdi_idle_arg;
};
struct xtensa_debug_module {
const struct xtensa_power_ops *pwr_ops;
const struct xtensa_debug_ops *dbg_ops;
struct jtag_tap *tap;
void (*queue_tdi_idle)(struct target *target);
void *queue_tdi_idle_arg;
struct xtensa_power_status power_status;
struct xtensa_core_status core_status;
xtensa_ocdid_t device_id;
};
int xtensa_dm_init(struct xtensa_debug_module *dm, const struct xtensa_debug_module_config *cfg);
int xtensa_dm_queue_enable(struct xtensa_debug_module *dm);
int xtensa_dm_queue_reg_read(struct xtensa_debug_module *dm, unsigned int reg, uint8_t *value);
int xtensa_dm_queue_reg_write(struct xtensa_debug_module *dm, unsigned int reg, uint32_t value);
int xtensa_dm_queue_pwr_reg_read(struct xtensa_debug_module *dm, unsigned int reg, uint8_t *data, uint8_t clear);
int xtensa_dm_queue_pwr_reg_write(struct xtensa_debug_module *dm, unsigned int reg, uint8_t data);
static inline void xtensa_dm_queue_tdi_idle(struct xtensa_debug_module *dm)
{
if (dm->queue_tdi_idle)
dm->queue_tdi_idle(dm->queue_tdi_idle_arg);
}
int xtensa_dm_power_status_read(struct xtensa_debug_module *dm, uint32_t clear);
static inline void xtensa_dm_power_status_cache_reset(struct xtensa_debug_module *dm)
{
dm->power_status.prev_stat = 0;
}
static inline void xtensa_dm_power_status_cache(struct xtensa_debug_module *dm)
{
dm->power_status.prev_stat = dm->power_status.stath;
}
static inline xtensa_pwrstat_t xtensa_dm_power_status_get(struct xtensa_debug_module *dm)
{
return dm->power_status.stat;
}
int xtensa_dm_core_status_read(struct xtensa_debug_module *dm);
int xtensa_dm_core_status_clear(struct xtensa_debug_module *dm, xtensa_dsr_t bits);
int xtensa_dm_core_status_check(struct xtensa_debug_module *dm);
static inline xtensa_dsr_t xtensa_dm_core_status_get(struct xtensa_debug_module *dm)
{
return dm->core_status.dsr;
}
int xtensa_dm_device_id_read(struct xtensa_debug_module *dm);
static inline xtensa_ocdid_t xtensa_dm_device_id_get(struct xtensa_debug_module *dm)
{
return dm->device_id;
}
int xtensa_dm_trace_start(struct xtensa_debug_module *dm, struct xtensa_trace_start_config *cfg);
int xtensa_dm_trace_stop(struct xtensa_debug_module *dm, bool pto_enable);
int xtensa_dm_trace_config_read(struct xtensa_debug_module *dm, struct xtensa_trace_config *config);
int xtensa_dm_trace_status_read(struct xtensa_debug_module *dm, struct xtensa_trace_status *status);
int xtensa_dm_trace_data_read(struct xtensa_debug_module *dm, uint8_t *dest, uint32_t size);
static inline bool xtensa_dm_is_online(struct xtensa_debug_module *dm)
{
int res = xtensa_dm_device_id_read(dm);
if (res != ERROR_OK)
return false;
return (dm->device_id != 0xffffffff && dm->device_id != 0);
}
static inline bool xtensa_dm_tap_was_reset(struct xtensa_debug_module *dm)
{
return !(dm->power_status.prev_stat & PWRSTAT_DEBUGWASRESET) &&
dm->power_status.stat & PWRSTAT_DEBUGWASRESET;
}
static inline bool xtensa_dm_core_was_reset(struct xtensa_debug_module *dm)
{
return !(dm->power_status.prev_stat & PWRSTAT_COREWASRESET) &&
dm->power_status.stat & PWRSTAT_COREWASRESET;
}
static inline bool xtensa_dm_core_is_stalled(struct xtensa_debug_module *dm)
{
return dm->core_status.dsr & OCDDSR_RUNSTALLSAMPLE;
}
static inline bool xtensa_dm_is_powered(struct xtensa_debug_module *dm)
{
return dm->core_status.dsr & OCDDSR_DBGMODPOWERON;
}
int xtensa_dm_perfmon_enable(struct xtensa_debug_module *dm, int counter_id,
const struct xtensa_perfmon_config *config);
int xtensa_dm_perfmon_dump(struct xtensa_debug_module *dm, int counter_id,
struct xtensa_perfmon_result *out_result);
#endif /* OPENOCD_TARGET_XTENSA_DEBUG_MODULE_H */

View File

@ -0,0 +1,278 @@
/***************************************************************************
* Generic Xtensa target API for OpenOCD *
* Copyright (C) 2016-2019 Espressif Systems Ltd. *
* Author: Angus Gratton gus@projectgus.com *
* Author: Jeroen Domburg <jeroen@espressif.com> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
#ifndef OPENOCD_TARGET_XTENSA_REGS_H
#define OPENOCD_TARGET_XTENSA_REGS_H
struct reg_arch_type;
enum xtensa_reg_id {
XT_REG_IDX_PC = 0,
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,
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_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,
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,
XT_REG_IDX_OCD_DDR,
XT_NUM_REGS,
/* chip-specific user registers go after ISA-defined ones */
XT_USR_REG_START = XT_NUM_REGS
};
typedef uint32_t xtensa_reg_val_t;
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 */
XT_REG_FR = 5, /* Floating-point register */
};
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 */
};
struct xtensa_reg_desc {
const char *name;
unsigned int reg_num; /* ISA register num (meaning depends on register type) */
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;
};
extern const struct xtensa_reg_desc xtensa_regs[XT_NUM_REGS];
#endif /* OPENOCD_TARGET_XTENSA_REGS_H */

View File

@ -0,0 +1,18 @@
# SPDX-License-Identifier: GPL-2.0-or-later
#
# Example OpenOCD configuration file for ESP32-S2 Kaluga board.
#
# For example, OpenOCD can be started for ESP32-S2 debugging on
#
# openocd -f board/esp32s2-kaluga-1.cfg
#
source [find interface/ftdi/esp32s2_kaluga_v1.cfg]
source [find target/esp32s2.cfg]
# The speed of the JTAG interface, in kHz. If you get DSR/DIR errors (and they
# do not relate to OpenOCD trying to read from a memory range without physical
# memory being present there), you can try lowering this.
# On ESP32-S2, this can go as high as 20MHz if CPU frequency is 80MHz, or 26MHz
# if CPU frequency is 160MHz or 240MHz.
adapter speed 20000

View File

@ -0,0 +1,29 @@
# SPDX-License-Identifier: GPL-2.0-or-later
#
# Driver for the FT2232H JTAG chip on the Espressif Kaluga-1 ESP32-S2 board
# (and most other FT2232H and FT232H based boards)
#
# JTAG DIP switch (labelled SW5 in the schematic) should be "ON" for lines
# labelled TCK, TDO, TDI and TWS, to connect the FT2232H to the ESP32-S2.
#
adapter driver ftdi
ftdi vid_pid 0x0403 0x6010 0x0403 0x6014
# interface 1 is the uart
ftdi channel 0
# TCK, TDI, TDO, TMS: ADBUS0-3
# TRST/SRST: ADBUS5 (unused for now)
# LEDs: ACBUS3-4 (inverted)
ftdi layout_init 0x0008 0x180b
ftdi layout_signal LED -ndata 0x0800
ftdi layout_signal LED2 -ndata 0x1000
# ESP32* series chips do not have a TRST input, and the SRST line is connected
# to the EN pin.
# The target code doesn't handle SRST reset properly yet, so this is
# commented out:
# ftdi layout_signal nSRST -oe 0x0020
# reset_config srst_only

30
tcl/target/esp32s2.cfg Normal file
View File

@ -0,0 +1,30 @@
# SPDX-License-Identifier: GPL-2.0-or-later
#
# The ESP32-S2 only supports JTAG.
transport select jtag
if { [info exists CHIPNAME] } {
set _CHIPNAME $CHIPNAME
} else {
set _CHIPNAME esp32s2
}
if { [info exists CPUTAPID] } {
set _CPUTAPID $CPUTAPID
} else {
set _CPUTAPID 0x120034e5
}
set _TARGETNAME $_CHIPNAME
set _CPUNAME cpu
set _TAPNAME $_CHIPNAME.$_CPUNAME
jtag newtap $_CHIPNAME $_CPUNAME -irlen 5 -expected-id $_CPUTAPID
target create $_TARGETNAME esp32s2 -endian little -chain-position $_TAPNAME
xtensa maskisr on
$_TARGETNAME configure -event reset-assert-post { soft_reset_halt }
gdb_breakpoint_override hard