#include <helper/time_support.h>
#include <helper/align.h>
#include <target/register.h>
+#include <target/algorithm.h>
#include "xtensa_chip.h"
#include "xtensa.h"
struct xtensa *xtensa = target_to_xtensa(target);
unsigned int cmd = PWRCTL_DEBUGWAKEUP(xtensa) | PWRCTL_MEMWAKEUP(xtensa) | PWRCTL_COREWAKEUP(xtensa);
- LOG_DEBUG("coreid = %d", target->coreid);
+ LOG_TARGET_DEBUG(target, "");
if (xtensa->core_config->core_type == XT_UNDEF) {
LOG_ERROR("XTensa core not configured; is xtensa-core-openocd.cfg missing?");
{
struct xtensa *xtensa = target_to_xtensa(target);
- LOG_TARGET_DEBUG(target, "target_number=%i, begin", target->target_number);
+ LOG_TARGET_DEBUG(target, " begin");
xtensa_queue_pwr_reg_write(xtensa,
XDMREG_PWRCTL,
PWRCTL_JTAGDEBUGUSE(xtensa) | PWRCTL_DEBUGWAKEUP(xtensa) | PWRCTL_MEMWAKEUP(xtensa) |
debug_execution);
if (target->state != TARGET_HALTED) {
- LOG_TARGET_WARNING(target, "target not halted");
+ LOG_TARGET_ERROR(target, "not halted");
return ERROR_TARGET_NOT_HALTED;
}
+ xtensa->halt_request = false;
if (address && !current) {
xtensa_reg_set(target, XT_REG_IDX_PC, address);
current, address, handle_breakpoints);
if (target->state != TARGET_HALTED) {
- LOG_TARGET_WARNING(target, "target not halted");
+ LOG_TARGET_ERROR(target, "not halted");
return ERROR_TARGET_NOT_HALTED;
}
bool bswap = xtensa->target->endianness == TARGET_BIG_ENDIAN;
if (target->state != TARGET_HALTED) {
- LOG_TARGET_WARNING(target, "target not halted");
+ LOG_TARGET_ERROR(target, "not halted");
return ERROR_TARGET_NOT_HALTED;
}
bool fill_head_tail = false;
if (target->state != TARGET_HALTED) {
- LOG_TARGET_WARNING(target, "target not halted");
+ LOG_TARGET_ERROR(target, "not halted");
return ERROR_TARGET_NOT_HALTED;
}
xtensa_reg_val_t dbreakcval;
if (target->state != TARGET_HALTED) {
- LOG_TARGET_WARNING(target, "target not halted");
+ LOG_TARGET_ERROR(target, "not halted");
return ERROR_TARGET_NOT_HALTED;
}
- if (watchpoint->mask != ~(uint32_t)0) {
+ if (watchpoint->mask != WATCHPOINT_IGNORE_DATA_VALUE_MASK) {
LOG_TARGET_ERROR(target, "watchpoint value masks not supported");
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
}
return ERROR_OK;
}
+int xtensa_start_algorithm(struct target *target,
+ int num_mem_params, struct mem_param *mem_params,
+ int num_reg_params, struct reg_param *reg_params,
+ target_addr_t entry_point, target_addr_t exit_point,
+ void *arch_info)
+{
+ struct xtensa *xtensa = target_to_xtensa(target);
+ struct xtensa_algorithm *algorithm_info = arch_info;
+ int retval = ERROR_OK;
+ bool usr_ps = false;
+ uint32_t newps;
+
+ /* NOTE: xtensa_run_algorithm requires that each algorithm uses a software breakpoint
+ * at the exit point */
+
+ if (target->state != TARGET_HALTED) {
+ LOG_WARNING("Target not halted!");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ for (unsigned int i = 0; i < xtensa->core_cache->num_regs; i++) {
+ struct reg *reg = &xtensa->core_cache->reg_list[i];
+ buf_cpy(reg->value, xtensa->algo_context_backup[i], reg->size);
+ }
+ /* save debug reason, it will be changed */
+ if (!algorithm_info) {
+ LOG_ERROR("BUG: arch_info not specified");
+ return ERROR_FAIL;
+ }
+ algorithm_info->ctx_debug_reason = target->debug_reason;
+ if (xtensa->core_config->core_type == XT_LX) {
+ /* save PS and set to debug_level - 1 */
+ algorithm_info->ctx_ps = xtensa_reg_get(target, xtensa->eps_dbglevel_idx);
+ newps = (algorithm_info->ctx_ps & ~0xf) | (xtensa->core_config->debug.irq_level - 1);
+ xtensa_reg_set(target, xtensa->eps_dbglevel_idx, newps);
+ }
+ /* write mem params */
+ for (int i = 0; i < num_mem_params; i++) {
+ if (mem_params[i].direction != PARAM_IN) {
+ retval = target_write_buffer(target, mem_params[i].address,
+ mem_params[i].size,
+ mem_params[i].value);
+ if (retval != ERROR_OK)
+ return retval;
+ }
+ }
+ /* write reg params */
+ for (int i = 0; i < num_reg_params; i++) {
+ if (reg_params[i].size > 32) {
+ LOG_ERROR("BUG: not supported register size (%d)", reg_params[i].size);
+ return ERROR_FAIL;
+ }
+ struct reg *reg = register_get_by_name(xtensa->core_cache, reg_params[i].reg_name, 0);
+ if (!reg) {
+ LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name);
+ return ERROR_FAIL;
+ }
+ if (reg->size != reg_params[i].size) {
+ LOG_ERROR("BUG: register '%s' size doesn't match reg_params[i].size", reg_params[i].reg_name);
+ return ERROR_FAIL;
+ }
+ if (memcmp(reg_params[i].reg_name, "ps", 3)) {
+ usr_ps = true;
+ } else if (xtensa->core_config->core_type == XT_LX) {
+ unsigned int reg_id = xtensa->eps_dbglevel_idx;
+ assert(reg_id < xtensa->core_cache->num_regs && "Attempt to access non-existing reg!");
+ reg = &xtensa->core_cache->reg_list[reg_id];
+ }
+ xtensa_reg_set_value(reg, buf_get_u32(reg_params[i].value, 0, reg->size));
+ reg->valid = 1;
+ }
+ /* ignore custom core mode if custom PS value is specified */
+ if (!usr_ps && xtensa->core_config->core_type == XT_LX) {
+ unsigned int eps_reg_idx = xtensa->eps_dbglevel_idx;
+ xtensa_reg_val_t ps = xtensa_reg_get(target, eps_reg_idx);
+ enum xtensa_mode core_mode = XT_PS_RING_GET(ps);
+ if (algorithm_info->core_mode != XT_MODE_ANY && algorithm_info->core_mode != core_mode) {
+ LOG_DEBUG("setting core_mode: 0x%x", algorithm_info->core_mode);
+ xtensa_reg_val_t new_ps = (ps & ~XT_PS_RING_MSK) | XT_PS_RING(algorithm_info->core_mode);
+ /* save previous core mode */
+ /* TODO: core_mode is not restored for now. Can be added to the end of wait_algorithm */
+ algorithm_info->core_mode = core_mode;
+ xtensa_reg_set(target, eps_reg_idx, new_ps);
+ xtensa->core_cache->reg_list[eps_reg_idx].valid = 1;
+ }
+ }
+
+ return xtensa_resume(target, 0, entry_point, 1, 1);
+}
+
+/** Waits for an algorithm in the target. */
+int xtensa_wait_algorithm(struct target *target,
+ int num_mem_params, struct mem_param *mem_params,
+ int num_reg_params, struct reg_param *reg_params,
+ target_addr_t exit_point, unsigned int timeout_ms,
+ void *arch_info)
+{
+ struct xtensa *xtensa = target_to_xtensa(target);
+ struct xtensa_algorithm *algorithm_info = arch_info;
+ int retval = ERROR_OK;
+ xtensa_reg_val_t pc;
+
+ /* NOTE: xtensa_run_algorithm requires that each algorithm uses a software breakpoint
+ * at the exit point */
+
+ retval = target_wait_state(target, TARGET_HALTED, timeout_ms);
+ /* If the target fails to halt due to the breakpoint, force a halt */
+ if (retval != ERROR_OK || target->state != TARGET_HALTED) {
+ retval = target_halt(target);
+ if (retval != ERROR_OK)
+ return retval;
+ retval = target_wait_state(target, TARGET_HALTED, 500);
+ if (retval != ERROR_OK)
+ return retval;
+ LOG_TARGET_ERROR(target, "not halted %d, pc 0x%" PRIx32 ", ps 0x%" PRIx32, retval,
+ xtensa_reg_get(target, XT_REG_IDX_PC),
+ xtensa_reg_get(target, (xtensa->core_config->core_type == XT_LX) ?
+ xtensa->eps_dbglevel_idx : XT_REG_IDX_PS));
+ return ERROR_TARGET_TIMEOUT;
+ }
+ pc = xtensa_reg_get(target, XT_REG_IDX_PC);
+ if (exit_point && pc != exit_point) {
+ LOG_ERROR("failed algorithm halted at 0x%" PRIx32 ", expected " TARGET_ADDR_FMT, pc, exit_point);
+ return ERROR_TARGET_TIMEOUT;
+ }
+ /* Copy core register values to reg_params[] */
+ for (int i = 0; i < num_reg_params; i++) {
+ if (reg_params[i].direction != PARAM_OUT) {
+ struct reg *reg = register_get_by_name(xtensa->core_cache, reg_params[i].reg_name, 0);
+ if (!reg) {
+ LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name);
+ return ERROR_FAIL;
+ }
+ if (reg->size != reg_params[i].size) {
+ LOG_ERROR("BUG: register '%s' size doesn't match reg_params[i].size", reg_params[i].reg_name);
+ return ERROR_FAIL;
+ }
+ buf_set_u32(reg_params[i].value, 0, 32, xtensa_reg_get_value(reg));
+ }
+ }
+ /* Read memory values to mem_params */
+ LOG_DEBUG("Read mem params");
+ for (int i = 0; i < num_mem_params; i++) {
+ LOG_DEBUG("Check mem param @ " TARGET_ADDR_FMT, mem_params[i].address);
+ if (mem_params[i].direction != PARAM_OUT) {
+ LOG_DEBUG("Read mem param @ " TARGET_ADDR_FMT, mem_params[i].address);
+ retval = target_read_buffer(target, mem_params[i].address, mem_params[i].size, mem_params[i].value);
+ if (retval != ERROR_OK)
+ return retval;
+ }
+ }
+
+ /* avoid gdb keep_alive warning */
+ keep_alive();
+
+ for (int i = xtensa->core_cache->num_regs - 1; i >= 0; i--) {
+ struct reg *reg = &xtensa->core_cache->reg_list[i];
+ if (i == XT_REG_IDX_PS) {
+ continue; /* restore mapped reg number of PS depends on NDEBUGLEVEL */
+ } else if (i == XT_REG_IDX_DEBUGCAUSE) {
+ /*FIXME: restoring DEBUGCAUSE causes exception when executing corresponding
+ * instruction in DIR */
+ LOG_DEBUG("Skip restoring register %s: 0x%8.8" PRIx32 " -> 0x%8.8" PRIx32,
+ xtensa->core_cache->reg_list[i].name,
+ buf_get_u32(reg->value, 0, 32),
+ buf_get_u32(xtensa->algo_context_backup[i], 0, 32));
+ buf_cpy(xtensa->algo_context_backup[i], reg->value, reg->size);
+ xtensa->core_cache->reg_list[i].dirty = 0;
+ xtensa->core_cache->reg_list[i].valid = 0;
+ } else if (memcmp(xtensa->algo_context_backup[i], reg->value, reg->size / 8)) {
+ if (reg->size <= 32) {
+ LOG_DEBUG("restoring register %s: 0x%8.8" PRIx32 " -> 0x%8.8" PRIx32,
+ xtensa->core_cache->reg_list[i].name,
+ buf_get_u32(reg->value, 0, reg->size),
+ buf_get_u32(xtensa->algo_context_backup[i], 0, reg->size));
+ } else if (reg->size <= 64) {
+ LOG_DEBUG("restoring register %s: 0x%8.8" PRIx64 " -> 0x%8.8" PRIx64,
+ xtensa->core_cache->reg_list[i].name,
+ buf_get_u64(reg->value, 0, reg->size),
+ buf_get_u64(xtensa->algo_context_backup[i], 0, reg->size));
+ } else {
+ LOG_DEBUG("restoring register %s %u-bits", xtensa->core_cache->reg_list[i].name, reg->size);
+ }
+ buf_cpy(xtensa->algo_context_backup[i], reg->value, reg->size);
+ xtensa->core_cache->reg_list[i].dirty = 1;
+ xtensa->core_cache->reg_list[i].valid = 1;
+ }
+ }
+ target->debug_reason = algorithm_info->ctx_debug_reason;
+ if (xtensa->core_config->core_type == XT_LX)
+ xtensa_reg_set(target, xtensa->eps_dbglevel_idx, algorithm_info->ctx_ps);
+
+ retval = xtensa_write_dirty_registers(target);
+ if (retval != ERROR_OK)
+ LOG_ERROR("Failed to write dirty regs (%d)!", retval);
+
+ return retval;
+}
+
+int xtensa_run_algorithm(struct target *target,
+ int num_mem_params, struct mem_param *mem_params,
+ int num_reg_params, struct reg_param *reg_params,
+ target_addr_t entry_point, target_addr_t exit_point,
+ unsigned int timeout_ms, void *arch_info)
+{
+ int retval = xtensa_start_algorithm(target,
+ num_mem_params, mem_params,
+ num_reg_params, reg_params,
+ entry_point, exit_point,
+ arch_info);
+
+ if (retval == ERROR_OK) {
+ retval = xtensa_wait_algorithm(target,
+ num_mem_params, mem_params,
+ num_reg_params, reg_params,
+ exit_point, timeout_ms,
+ arch_info);
+ }
+
+ return retval;
+}
+
static int xtensa_build_reg_cache(struct target *target)
{
struct xtensa *xtensa = target_to_xtensa(target);
free(xtensa->core_config);
}
-const char *xtensa_get_gdb_arch(struct target *target)
+const char *xtensa_get_gdb_arch(const struct target *target)
{
return "xtensa";
}
const char *parm = CMD_ARGV[0];
unsigned int parm_len = strlen(parm);
if ((parm_len >= 64) || (parm_len & 1)) {
- LOG_ERROR("Invalid parameter length (%d): must be even, < 64 characters", parm_len);
- return ERROR_FAIL;
+ command_print(CMD, "Invalid parameter length (%d): must be even, < 64 characters", parm_len);
+ return ERROR_COMMAND_ARGUMENT_INVALID;
}
uint8_t ops[32];
*/
int status = xtensa_write_dirty_registers(target);
if (status != ERROR_OK) {
- LOG_ERROR("%s: Failed to write back register cache.", target_name(target));
+ command_print(CMD, "%s: Failed to write back register cache.", target_name(target));
return ERROR_FAIL;
}
xtensa_reg_val_t exccause = xtensa_reg_get(target, XT_REG_IDX_EXCCAUSE);
LOG_TARGET_DEBUG(target, "execute stub: %s", CMD_ARGV[0]);
xtensa_queue_exec_ins_wide(xtensa, ops, oplen); /* Handles endian-swap */
status = xtensa_dm_queue_execute(&xtensa->dbg_mod);
- if (status != ERROR_OK)
- LOG_TARGET_ERROR(target, "TIE queue execute: %d\n", status);
- status = xtensa_core_status_check(target);
- if (status != ERROR_OK)
- LOG_TARGET_ERROR(target, "TIE instr execute: %d\n", status);
+ if (status != ERROR_OK) {
+ command_print(CMD, "exec: queue error %d", status);
+ } else {
+ status = xtensa_core_status_check(target);
+ if (status != ERROR_OK)
+ command_print(CMD, "exec: status error %d", status);
+ }
/* Reread register cache and restore saved regs after instruction execution */
if (xtensa_fetch_all_regs(target) != ERROR_OK)
- LOG_TARGET_ERROR(target, "%s: Failed to fetch register cache (post-exec).", target_name(target));
+ command_print(CMD, "post-exec: register fetch error");
+ if (status != ERROR_OK) {
+ command_print(CMD, "post-exec: EXCCAUSE 0x%02" PRIx32,
+ xtensa_reg_get(target, XT_REG_IDX_EXCCAUSE));
+ }
xtensa_reg_set(target, XT_REG_IDX_EXCCAUSE, exccause);
xtensa_reg_set(target, XT_REG_IDX_CPENABLE, cpenable);
return status;
} else if (strcasecmp(core_name, "NX") == 0) {
xtensa->core_config->core_type = XT_NX;
} else {
- LOG_ERROR("xtdef [LX|NX]\n");
- return ERROR_COMMAND_SYNTAX_ERROR;
+ command_print(CMD, "xtdef [LX|NX]\n");
+ return ERROR_COMMAND_ARGUMENT_INVALID;
}
return ERROR_OK;
}
if (!xtensa_cmd_xtopt_legal_val("excmlevel", opt_val, 1, 6))
return ERROR_COMMAND_ARGUMENT_INVALID;
if (!xtensa->core_config->high_irq.enabled) {
- LOG_ERROR("xtopt excmlevel requires hipriints\n");
+ command_print(CMD, "xtopt excmlevel requires hipriints\n");
return ERROR_COMMAND_ARGUMENT_INVALID;
}
xtensa->core_config->high_irq.excm_level = opt_val;
return ERROR_COMMAND_ARGUMENT_INVALID;
}
if (!xtensa->core_config->high_irq.enabled) {
- LOG_ERROR("xtopt intlevels requires hipriints\n");
+ command_print(CMD, "xtopt intlevels requires hipriints\n");
return ERROR_COMMAND_ARGUMENT_INVALID;
}
xtensa->core_config->high_irq.level_num = opt_val;
int mem_access = 0;
bool is_dcache = false;
- if (CMD_ARGC == 0) {
- LOG_ERROR("xtmem <type> [parameters]\n");
+ if (CMD_ARGC == 0)
return ERROR_COMMAND_SYNTAX_ERROR;
- }
const char *mem_name = CMD_ARGV[0];
if (strcasecmp(mem_name, "icache") == 0) {
memp = &xtensa->core_config->srom;
mem_access = XT_MEM_ACCESS_READ;
} else {
- LOG_ERROR("xtmem types: <icache|dcache|l2cache|l2addr|iram|irom|dram|drom|sram|srom>\n");
+ command_print(CMD, "xtmem types: <icache|dcache|l2cache|l2addr|iram|irom|dram|drom|sram|srom>\n");
return ERROR_COMMAND_ARGUMENT_INVALID;
}
if (cachep) {
- if ((CMD_ARGC != 4) && (CMD_ARGC != 5)) {
- LOG_ERROR("xtmem <cachetype> <linebytes> <cachebytes> <ways> [writeback]\n");
+ if (CMD_ARGC != 4 && CMD_ARGC != 5)
return ERROR_COMMAND_SYNTAX_ERROR;
- }
cachep->line_size = strtoul(CMD_ARGV[1], NULL, 0);
cachep->size = strtoul(CMD_ARGV[2], NULL, 0);
cachep->way_count = strtoul(CMD_ARGV[3], NULL, 0);
cachep->writeback = ((CMD_ARGC == 5) && is_dcache) ?
strtoul(CMD_ARGV[4], NULL, 0) : 0;
} else if (memp) {
- if (CMD_ARGC != 3) {
- LOG_ERROR("xtmem <memtype> <baseaddr> <bytes>\n");
+ if (CMD_ARGC != 3)
return ERROR_COMMAND_SYNTAX_ERROR;
- }
struct xtensa_local_mem_region_config *memcfgp = &memp->regions[memp->count];
memcfgp->base = strtoul(CMD_ARGV[1], NULL, 0);
memcfgp->size = strtoul(CMD_ARGV[2], NULL, 0);
/* xtmpu <num FG seg> <min seg size> <lockable> <executeonly> */
COMMAND_HELPER(xtensa_cmd_xtmpu_do, struct xtensa *xtensa)
{
- if (CMD_ARGC != 4) {
- LOG_ERROR("xtmpu <num FG seg> <min seg size> <lockable> <executeonly>\n");
+ if (CMD_ARGC != 4)
return ERROR_COMMAND_SYNTAX_ERROR;
- }
unsigned int nfgseg = strtoul(CMD_ARGV[0], NULL, 0);
unsigned int minsegsize = strtoul(CMD_ARGV[1], NULL, 0);
unsigned int execonly = strtoul(CMD_ARGV[3], NULL, 0);
if ((nfgseg > 32)) {
- LOG_ERROR("<nfgseg> must be within [0..32]\n");
+ command_print(CMD, "<nfgseg> must be within [0..32]\n");
return ERROR_COMMAND_ARGUMENT_INVALID;
} else if (minsegsize & (minsegsize - 1)) {
- LOG_ERROR("<minsegsize> must be a power of 2 >= 32\n");
+ command_print(CMD, "<minsegsize> must be a power of 2 >= 32\n");
return ERROR_COMMAND_ARGUMENT_INVALID;
} else if (lockable > 1) {
- LOG_ERROR("<lockable> must be 0 or 1\n");
+ command_print(CMD, "<lockable> must be 0 or 1\n");
return ERROR_COMMAND_ARGUMENT_INVALID;
} else if (execonly > 1) {
- LOG_ERROR("<execonly> must be 0 or 1\n");
+ command_print(CMD, "<execonly> must be 0 or 1\n");
return ERROR_COMMAND_ARGUMENT_INVALID;
}
/* xtmmu <NIREFILLENTRIES> <NDREFILLENTRIES> <IVARWAY56> <DVARWAY56> */
COMMAND_HELPER(xtensa_cmd_xtmmu_do, struct xtensa *xtensa)
{
- if (CMD_ARGC != 2) {
- LOG_ERROR("xtmmu <NIREFILLENTRIES> <NDREFILLENTRIES>\n");
+ if (CMD_ARGC != 2)
return ERROR_COMMAND_SYNTAX_ERROR;
- }
unsigned int nirefillentries = strtoul(CMD_ARGV[0], NULL, 0);
unsigned int ndrefillentries = strtoul(CMD_ARGV[1], NULL, 0);
if ((nirefillentries != 16) && (nirefillentries != 32)) {
- LOG_ERROR("<nirefillentries> must be 16 or 32\n");
+ command_print(CMD, "<nirefillentries> must be 16 or 32\n");
return ERROR_COMMAND_ARGUMENT_INVALID;
} else if ((ndrefillentries != 16) && (ndrefillentries != 32)) {
- LOG_ERROR("<ndrefillentries> must be 16 or 32\n");
+ command_print(CMD, "<ndrefillentries> must be 16 or 32\n");
return ERROR_COMMAND_ARGUMENT_INVALID;
}
if (CMD_ARGC == 1) {
int32_t numregs = strtoul(CMD_ARGV[0], NULL, 0);
if ((numregs <= 0) || (numregs > UINT16_MAX)) {
- LOG_ERROR("xtreg <numregs>: Invalid 'numregs' (%d)", numregs);
- return ERROR_COMMAND_SYNTAX_ERROR;
+ command_print(CMD, "xtreg <numregs>: Invalid 'numregs' (%d)", numregs);
+ return ERROR_COMMAND_ARGUMENT_INVALID;
}
if ((xtensa->genpkt_regs_num > 0) && (numregs < (int32_t)xtensa->genpkt_regs_num)) {
- LOG_ERROR("xtregs (%d) must be larger than numgenregs (%d) (if xtregfmt specified)",
+ command_print(CMD, "xtregs (%d) must be larger than numgenregs (%d) (if xtregfmt specified)",
numregs, xtensa->genpkt_regs_num);
- return ERROR_COMMAND_SYNTAX_ERROR;
+ return ERROR_COMMAND_ARGUMENT_INVALID;
}
xtensa->total_regs_num = numregs;
xtensa->core_regs_num = 0;
const char *regname = CMD_ARGV[0];
unsigned int regnum = strtoul(CMD_ARGV[1], NULL, 0);
if (regnum > UINT16_MAX) {
- LOG_ERROR("<regnum> must be a 16-bit number");
+ command_print(CMD, "<regnum> must be a 16-bit number");
return ERROR_COMMAND_ARGUMENT_INVALID;
}
if ((xtensa->num_optregs + xtensa->core_regs_num) >= xtensa->total_regs_num) {
if (xtensa->total_regs_num)
- LOG_ERROR("'xtreg %s 0x%04x': Too many registers (%d expected, %d core %d extended)",
+ command_print(CMD, "'xtreg %s 0x%04x': Too many registers (%d expected, %d core %d extended)",
regname, regnum,
xtensa->total_regs_num, xtensa->core_regs_num, xtensa->num_optregs);
else
- LOG_ERROR("'xtreg %s 0x%04x': Number of registers unspecified",
+ command_print(CMD, "'xtreg %s 0x%04x': Number of registers unspecified",
regname, regnum);
return ERROR_FAIL;
}
idx = XT_NX_REG_IDX_MESRCLR;
if (idx < XT_NX_REG_IDX_NUM) {
if (xtensa->nx_reg_idx[idx] != 0) {
- LOG_ERROR("nx_reg_idx[%d] previously set to %d",
+ command_print(CMD, "nx_reg_idx[%d] previously set to %d",
idx, xtensa->nx_reg_idx[idx]);
return ERROR_FAIL;
}
if ((numgregs <= 0) ||
((numgregs > xtensa->total_regs_num) &&
(xtensa->total_regs_num > 0))) {
- LOG_ERROR("xtregfmt: if specified, numgregs (%d) must be <= numregs (%d)",
+ command_print(CMD, "xtregfmt: if specified, numgregs (%d) must be <= numregs (%d)",
numgregs, xtensa->total_regs_num);
- return ERROR_COMMAND_SYNTAX_ERROR;
+ return ERROR_COMMAND_ARGUMENT_INVALID;
}
xtensa->genpkt_regs_num = numgregs;
}
"%-12" PRIu64 "%s",
result.value,
result.overflow ? " (overflow)" : "");
- LOG_INFO("%s", result_buf);
+ command_print(CMD, "%s", result_buf);
}
return ERROR_OK;
get_current_target(CMD_CTX));
}
+COMMAND_HELPER(xtensa_cmd_dm_rw_do, struct xtensa *xtensa)
+{
+ if (CMD_ARGC == 1) {
+ // read: xtensa dm addr
+ uint32_t addr = strtoul(CMD_ARGV[0], NULL, 0);
+ uint32_t val;
+ int res = xtensa_dm_read(&xtensa->dbg_mod, addr, &val);
+ if (res == ERROR_OK)
+ command_print(CMD, "xtensa DM(0x%08" PRIx32 ") -> 0x%08" PRIx32, addr, val);
+ else
+ command_print(CMD, "xtensa DM(0x%08" PRIx32 ") : read ERROR %" PRId32, addr, res);
+ return res;
+ } else if (CMD_ARGC == 2) {
+ // write: xtensa dm addr value
+ uint32_t addr = strtoul(CMD_ARGV[0], NULL, 0);
+ uint32_t val = strtoul(CMD_ARGV[1], NULL, 0);
+ int res = xtensa_dm_write(&xtensa->dbg_mod, addr, val);
+ if (res == ERROR_OK)
+ command_print(CMD, "xtensa DM(0x%08" PRIx32 ") <- 0x%08" PRIx32, addr, val);
+ else
+ command_print(CMD, "xtensa DM(0x%08" PRIx32 ") : write ERROR %" PRId32, addr, res);
+ return res;
+ }
+ return ERROR_COMMAND_SYNTAX_ERROR;
+}
+
+COMMAND_HANDLER(xtensa_cmd_dm_rw)
+{
+ return CALL_COMMAND_HANDLER(xtensa_cmd_dm_rw_do,
+ target_to_xtensa(get_current_target(CMD_CTX)));
+}
+
COMMAND_HELPER(xtensa_cmd_tracestart_do, struct xtensa *xtensa)
{
struct xtensa_trace_status trace_status;
}
memsz = trace_config.memaddr_end - trace_config.memaddr_start + 1;
- LOG_INFO("Total trace memory: %d words", memsz);
+ command_print(CMD, "Total trace memory: %d words", memsz);
if ((trace_config.addr &
((TRAXADDR_TWRAP_MASK << TRAXADDR_TWRAP_SHIFT) | TRAXADDR_TWSAT)) == 0) {
/*Memory hasn't overwritten itself yet. */
wmem = trace_config.addr & TRAXADDR_TADDR_MASK;
- LOG_INFO("...but trace is only %d words", wmem);
+ command_print(CMD, "...but trace is only %d words", wmem);
if (wmem < memsz)
memsz = wmem;
} else {
if (trace_config.addr & TRAXADDR_TWSAT) {
- LOG_INFO("Real trace is many times longer than that (overflow)");
+ command_print(CMD, "Real trace is many times longer than that (overflow)");
} else {
uint32_t trc_sz = (trace_config.addr >> TRAXADDR_TWRAP_SHIFT) & TRAXADDR_TWRAP_MASK;
trc_sz = (trc_sz * memsz) + (trace_config.addr & TRAXADDR_TADDR_MASK);
- LOG_INFO("Real trace is %d words, but the start has been truncated.", trc_sz);
+ command_print(CMD, "Real trace is %d words, but the start has been truncated.", trc_sz);
}
}
.help = "Set the way the CPU chains OCD breaks",
.usage = "[none|breakinout|runstall] | [BreakIn] [BreakOut] [RunStallIn] [DebugModeOut]",
},
+ {
+ .name = "dm",
+ .handler = xtensa_cmd_dm_rw,
+ .mode = COMMAND_ANY,
+ .help = "Xtensa DM read/write",
+ .usage = "addr [value]"
+ },
{
.name = "perfmon_enable",
.handler = xtensa_cmd_perfmon_enable,