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:
parent
b470b664ca
commit
78c87f5e81
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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, ®_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,
|
||||
};
|
|
@ -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 */
|
|
@ -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 */
|
||||
}
|
|
@ -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 */
|
|
@ -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,
|
||||
|
|
|
@ -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
|
File diff suppressed because it is too large
Load Diff
|
@ -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 */
|
|
@ -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, ®data, 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, ®data, 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;
|
||||
}
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
Loading…
Reference in New Issue