forked from auracaster/openocd
target/xtensa: virtualize XDM registers
Use indirect enum IDs to access XDM registers in preparation for supporting both NAR (JTAG) and APB (DAP). No new clang static analysis warnings. Signed-off-by: Ian Thompson <ianst@cadence.com> Change-Id: I0b742fe4661ff3cf609454b8650493d141a1e1ff Reviewed-on: https://review.openocd.org/c/openocd/+/7143 Tested-by: jenkins Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
This commit is contained in:
committed by
Antonio Borneo
parent
ea165d8e89
commit
de99836cf6
@@ -1,7 +1,8 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/***************************************************************************
|
||||
* Generic Xtensa debug module API for OpenOCD *
|
||||
* Xtensa Debug Module (XDM) Support for OpenOCD *
|
||||
* Copyright (C) 2020-2022 Cadence Design Systems, Inc. *
|
||||
* Copyright (C) 2019 Espressif Systems Ltd. *
|
||||
***************************************************************************/
|
||||
|
||||
@@ -24,11 +25,14 @@
|
||||
#define TAPINS_IDCODE_LEN 32
|
||||
#define TAPINS_BYPASS_LEN 1
|
||||
|
||||
/* Table of debug register offsets for Nexus and APB space */
|
||||
static const struct xtensa_dm_reg_offsets xdm_regs[XDMREG_NUM] =
|
||||
XTENSA_DM_REG_OFFSETS;
|
||||
|
||||
static void xtensa_dm_add_set_ir(struct xtensa_debug_module *dm, uint8_t value)
|
||||
{
|
||||
struct scan_field field;
|
||||
uint8_t t[4] = { 0 };
|
||||
uint8_t t[4] = { 0, 0, 0, 0 };
|
||||
|
||||
memset(&field, 0, sizeof(field));
|
||||
field.num_bits = dm->tap->ir_length;
|
||||
@@ -67,76 +71,65 @@ int xtensa_dm_init(struct xtensa_debug_module *dm, const struct xtensa_debug_mod
|
||||
|
||||
int xtensa_dm_queue_enable(struct xtensa_debug_module *dm)
|
||||
{
|
||||
return dm->dbg_ops->queue_reg_write(dm, NARADR_DCRSET, OCDDCR_ENABLEOCD);
|
||||
return dm->dbg_ops->queue_reg_write(dm, XDMREG_DCRSET, OCDDCR_ENABLEOCD);
|
||||
}
|
||||
|
||||
int xtensa_dm_queue_reg_read(struct xtensa_debug_module *dm, unsigned int reg, uint8_t *value)
|
||||
int xtensa_dm_queue_reg_read(struct xtensa_debug_module *dm, enum xtensa_dm_reg reg, uint8_t *value)
|
||||
{
|
||||
uint8_t regdata = (reg << 1) | 0;
|
||||
uint8_t dummy[4] = { 0, 0, 0, 0 };
|
||||
|
||||
if (reg > NARADR_MAX) {
|
||||
if (reg >= XDMREG_NUM) {
|
||||
LOG_ERROR("Invalid DBG reg ID %d!", reg);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
uint8_t regdata = (xdm_regs[reg].nar << 1) | 0;
|
||||
uint8_t dummy[4] = { 0, 0, 0, 0 };
|
||||
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)
|
||||
int xtensa_dm_queue_reg_write(struct xtensa_debug_module *dm, enum xtensa_dm_reg reg, uint32_t value)
|
||||
{
|
||||
uint8_t regdata = (reg << 1) | 1;
|
||||
uint8_t valdata[] = { value, value >> 8, value >> 16, value >> 24 };
|
||||
|
||||
if (reg > NARADR_MAX) {
|
||||
if (reg >= XDMREG_NUM) {
|
||||
LOG_ERROR("Invalid DBG reg ID %d!", reg);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
uint8_t regdata = (xdm_regs[reg].nar << 1) | 1;
|
||||
uint8_t valdata[] = { value, value >> 8, value >> 16, value >> 24 };
|
||||
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)
|
||||
int xtensa_dm_queue_pwr_reg_read(struct xtensa_debug_module *dm,
|
||||
enum xtensa_dm_pwr_reg reg,
|
||||
uint8_t *data,
|
||||
uint32_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 {
|
||||
if (reg >= XDMREG_PWRNUM) {
|
||||
LOG_ERROR("Invalid PWR reg ID %d!", reg);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
uint8_t value_clr = (uint8_t)clear;
|
||||
uint8_t tap_insn = (reg == XDMREG_PWRCTL) ? TAPINS_PWRCTL : TAPINS_PWRSTAT;
|
||||
int tap_insn_sz = (reg == XDMREG_PWRCTL) ? TAPINS_PWRCTL_LEN : TAPINS_PWRSTAT_LEN;
|
||||
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)
|
||||
int xtensa_dm_queue_pwr_reg_write(struct xtensa_debug_module *dm,
|
||||
enum xtensa_dm_pwr_reg reg,
|
||||
uint32_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 {
|
||||
if (reg >= XDMREG_PWRNUM) {
|
||||
LOG_ERROR("Invalid PWR reg ID %d!", reg);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
uint8_t tap_insn = (reg == XDMREG_PWRCTL) ? TAPINS_PWRCTL : TAPINS_PWRSTAT;
|
||||
int tap_insn_sz = (reg == XDMREG_PWRCTL) ? TAPINS_PWRCTL_LEN : TAPINS_PWRSTAT_LEN;
|
||||
uint8_t value = (uint8_t)data;
|
||||
xtensa_dm_add_set_ir(dm, tap_insn);
|
||||
xtensa_dm_add_dr_scan(dm, tap_insn_sz, &value, NULL, TAP_IDLE);
|
||||
return ERROR_OK;
|
||||
@@ -146,9 +139,9 @@ 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);
|
||||
dm->dbg_ops->queue_reg_read(dm, XDMREG_OCDID, id_buf);
|
||||
xtensa_dm_queue_tdi_idle(dm);
|
||||
int res = jtag_execute_queue();
|
||||
int res = xtensa_dm_queue_execute(dm);
|
||||
if (res != ERROR_OK)
|
||||
return res;
|
||||
dm->device_id = buf_get_u32(id_buf, 0, 32);
|
||||
@@ -157,16 +150,22 @@ int xtensa_dm_device_id_read(struct xtensa_debug_module *dm)
|
||||
|
||||
int xtensa_dm_power_status_read(struct xtensa_debug_module *dm, uint32_t clear)
|
||||
{
|
||||
/* uint8_t id_buf[sizeof(uint32_t)]; */
|
||||
uint8_t stat_buf[sizeof(uint32_t)];
|
||||
uint8_t stath_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);
|
||||
* It is set in xtensa_examine(), need to move reading of XDMREG_OCDID out of this function */
|
||||
/* dm->dbg_ops->queue_reg_read(dm, XDMREG_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);
|
||||
dm->pwr_ops->queue_reg_read(dm, XDMREG_PWRSTAT, stat_buf, clear);
|
||||
dm->pwr_ops->queue_reg_read(dm, XDMREG_PWRSTAT, stath_buf, clear);
|
||||
xtensa_dm_queue_tdi_idle(dm);
|
||||
return jtag_execute_queue();
|
||||
int res = xtensa_dm_queue_execute(dm);
|
||||
if (res != ERROR_OK)
|
||||
return res;
|
||||
dm->power_status.stat = buf_get_u32(stat_buf, 0, 32);
|
||||
dm->power_status.stath = buf_get_u32(stath_buf, 0, 32);
|
||||
return res;
|
||||
}
|
||||
|
||||
int xtensa_dm_core_status_read(struct xtensa_debug_module *dm)
|
||||
@@ -174,9 +173,9 @@ 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);
|
||||
dm->dbg_ops->queue_reg_read(dm, XDMREG_DSR, dsr_buf);
|
||||
xtensa_dm_queue_tdi_idle(dm);
|
||||
int res = jtag_execute_queue();
|
||||
int res = xtensa_dm_queue_execute(dm);
|
||||
if (res != ERROR_OK)
|
||||
return res;
|
||||
dm->core_status.dsr = buf_get_u32(dsr_buf, 0, 32);
|
||||
@@ -185,37 +184,37 @@ 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)
|
||||
{
|
||||
dm->dbg_ops->queue_reg_write(dm, NARADR_DSR, bits);
|
||||
dm->dbg_ops->queue_reg_write(dm, XDMREG_DSR, bits);
|
||||
xtensa_dm_queue_tdi_idle(dm);
|
||||
return jtag_execute_queue();
|
||||
return xtensa_dm_queue_execute(dm);
|
||||
}
|
||||
|
||||
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);
|
||||
dm->dbg_ops->queue_reg_write(dm, XDMREG_TRAXCTRL, 0);
|
||||
xtensa_dm_queue_tdi_idle(dm);
|
||||
int res = jtag_execute_queue();
|
||||
int res = xtensa_dm_queue_execute(dm);
|
||||
if (res != ERROR_OK)
|
||||
return res;
|
||||
|
||||
/*Set up parameters */
|
||||
dm->dbg_ops->queue_reg_write(dm, NARADR_TRAXADDR, 0);
|
||||
dm->dbg_ops->queue_reg_write(dm, XDMREG_TRAXADDR, 0);
|
||||
if (cfg->stopmask != XTENSA_STOPMASK_DISABLED) {
|
||||
dm->dbg_ops->queue_reg_write(dm, NARADR_PCMATCHCTRL,
|
||||
dm->dbg_ops->queue_reg_write(dm, XDMREG_PCMATCHCTRL,
|
||||
(cfg->stopmask << PCMATCHCTRL_PCML_SHIFT));
|
||||
dm->dbg_ops->queue_reg_write(dm, NARADR_TRIGGERPC, cfg->stoppc);
|
||||
dm->dbg_ops->queue_reg_write(dm, XDMREG_TRIGGERPC, cfg->stoppc);
|
||||
}
|
||||
dm->dbg_ops->queue_reg_write(dm, NARADR_DELAYCNT, cfg->after);
|
||||
dm->dbg_ops->queue_reg_write(dm, XDMREG_DELAYCNT, cfg->after);
|
||||
/*Options are mostly hardcoded for now. ToDo: make this more configurable. */
|
||||
dm->dbg_ops->queue_reg_write(
|
||||
dm,
|
||||
NARADR_TRAXCTRL,
|
||||
XDMREG_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();
|
||||
return xtensa_dm_queue_execute(dm);
|
||||
}
|
||||
|
||||
int xtensa_dm_trace_stop(struct xtensa_debug_module *dm, bool pto_enable)
|
||||
@@ -224,9 +223,9 @@ int xtensa_dm_trace_stop(struct xtensa_debug_module *dm, bool pto_enable)
|
||||
uint32_t traxctl;
|
||||
struct xtensa_trace_status trace_status;
|
||||
|
||||
dm->dbg_ops->queue_reg_read(dm, NARADR_TRAXCTRL, traxctl_buf);
|
||||
dm->dbg_ops->queue_reg_read(dm, XDMREG_TRAXCTRL, traxctl_buf);
|
||||
xtensa_dm_queue_tdi_idle(dm);
|
||||
int res = jtag_execute_queue();
|
||||
int res = xtensa_dm_queue_execute(dm);
|
||||
if (res != ERROR_OK)
|
||||
return res;
|
||||
traxctl = buf_get_u32(traxctl_buf, 0, 32);
|
||||
@@ -234,9 +233,9 @@ int xtensa_dm_trace_stop(struct xtensa_debug_module *dm, bool pto_enable)
|
||||
if (!pto_enable)
|
||||
traxctl &= ~(TRAXCTRL_PTOWS | TRAXCTRL_PTOWT);
|
||||
|
||||
dm->dbg_ops->queue_reg_write(dm, NARADR_TRAXCTRL, traxctl | TRAXCTRL_TRSTP);
|
||||
dm->dbg_ops->queue_reg_write(dm, XDMREG_TRAXCTRL, traxctl | TRAXCTRL_TRSTP);
|
||||
xtensa_dm_queue_tdi_idle(dm);
|
||||
res = jtag_execute_queue();
|
||||
res = xtensa_dm_queue_execute(dm);
|
||||
if (res != ERROR_OK)
|
||||
return res;
|
||||
|
||||
@@ -256,9 +255,9 @@ int xtensa_dm_trace_status_read(struct xtensa_debug_module *dm, struct xtensa_tr
|
||||
{
|
||||
uint8_t traxstat_buf[sizeof(uint32_t)];
|
||||
|
||||
dm->dbg_ops->queue_reg_read(dm, NARADR_TRAXSTAT, traxstat_buf);
|
||||
dm->dbg_ops->queue_reg_read(dm, XDMREG_TRAXSTAT, traxstat_buf);
|
||||
xtensa_dm_queue_tdi_idle(dm);
|
||||
int res = jtag_execute_queue();
|
||||
int res = xtensa_dm_queue_execute(dm);
|
||||
if (res == ERROR_OK && status)
|
||||
status->stat = buf_get_u32(traxstat_buf, 0, 32);
|
||||
return res;
|
||||
@@ -274,12 +273,12 @@ int xtensa_dm_trace_config_read(struct xtensa_debug_module *dm, struct xtensa_tr
|
||||
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);
|
||||
dm->dbg_ops->queue_reg_read(dm, XDMREG_TRAXCTRL, traxctl_buf);
|
||||
dm->dbg_ops->queue_reg_read(dm, XDMREG_MEMADDRSTART, memadrstart_buf);
|
||||
dm->dbg_ops->queue_reg_read(dm, XDMREG_MEMADDREND, memadrend_buf);
|
||||
dm->dbg_ops->queue_reg_read(dm, XDMREG_TRAXADDR, adr_buf);
|
||||
xtensa_dm_queue_tdi_idle(dm);
|
||||
int res = jtag_execute_queue();
|
||||
int res = xtensa_dm_queue_execute(dm);
|
||||
if (res == ERROR_OK) {
|
||||
config->ctrl = buf_get_u32(traxctl_buf, 0, 32);
|
||||
config->memaddr_start = buf_get_u32(memadrstart_buf, 0, 32);
|
||||
@@ -295,9 +294,9 @@ int xtensa_dm_trace_data_read(struct xtensa_debug_module *dm, uint8_t *dest, uin
|
||||
return ERROR_FAIL;
|
||||
|
||||
for (unsigned int i = 0; i < size / 4; i++)
|
||||
dm->dbg_ops->queue_reg_read(dm, NARADR_TRAXDATA, &dest[i * 4]);
|
||||
dm->dbg_ops->queue_reg_read(dm, XDMREG_TRAXDATA, &dest[i * 4]);
|
||||
xtensa_dm_queue_tdi_idle(dm);
|
||||
return jtag_execute_queue();
|
||||
return xtensa_dm_queue_execute(dm);
|
||||
}
|
||||
|
||||
int xtensa_dm_perfmon_enable(struct xtensa_debug_module *dm, int counter_id,
|
||||
@@ -313,13 +312,13 @@ int xtensa_dm_perfmon_enable(struct xtensa_debug_module *dm, int counter_id,
|
||||
(config->kernelcnt << 3);
|
||||
|
||||
/* enable performance monitor */
|
||||
dm->dbg_ops->queue_reg_write(dm, NARADR_PMG, 0x1);
|
||||
dm->dbg_ops->queue_reg_write(dm, XDMREG_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);
|
||||
dm->dbg_ops->queue_reg_write(dm, XDMREG_PM0 + counter_id, 0);
|
||||
dm->dbg_ops->queue_reg_write(dm, XDMREG_PMCTRL0 + counter_id, pmctrl);
|
||||
dm->dbg_ops->queue_reg_read(dm, XDMREG_PMSTAT0 + counter_id, pmstat_buf);
|
||||
xtensa_dm_queue_tdi_idle(dm);
|
||||
return jtag_execute_queue();
|
||||
return xtensa_dm_queue_execute(dm);
|
||||
}
|
||||
|
||||
int xtensa_dm_perfmon_dump(struct xtensa_debug_module *dm, int counter_id,
|
||||
@@ -328,10 +327,10 @@ int xtensa_dm_perfmon_dump(struct xtensa_debug_module *dm, int counter_id,
|
||||
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);
|
||||
dm->dbg_ops->queue_reg_read(dm, XDMREG_PMSTAT0 + counter_id, pmstat_buf);
|
||||
dm->dbg_ops->queue_reg_read(dm, XDMREG_PM0 + counter_id, pmcount_buf);
|
||||
xtensa_dm_queue_tdi_idle(dm);
|
||||
int res = jtag_execute_queue();
|
||||
int res = xtensa_dm_queue_execute(dm);
|
||||
if (res == ERROR_OK) {
|
||||
uint32_t stat = buf_get_u32(pmstat_buf, 0, 32);
|
||||
uint64_t result = buf_get_u32(pmcount_buf, 0, 32);
|
||||
|
||||
Reference in New Issue
Block a user