+static int dsp563xx_write_memory(struct target *target,
+ int mem_type,
+ uint32_t address,
+ uint32_t size,
+ uint32_t count,
+ const uint8_t *buffer)
+{
+ int err;
+ uint32_t i, i1;
+ uint8_t *buffer_y, *buffer_x;
+
+ /* if size equals zero we are called from target write memory
+ * and have to handle the parameter here */
+ if ((size == 0) && (count != 0)) {
+ size = count % 4;
+
+ if (size)
+ LOG_DEBUG("size is not aligned to 4 byte");
+
+ count = (count - size) / 4;
+ size = 4;
+ }
+
+ /* we only support 4 byte aligned data */
+ if ((size != 4) || (!count))
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ if (mem_type != MEM_L)
+ return dsp563xx_write_memory_core(target, mem_type, address, size, count, buffer);
+
+ buffer_y = malloc(size * count);
+ if (!buffer_y)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ buffer_x = malloc(size * count);
+ if (!buffer_x) {
+ free(buffer_y);
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+
+ for (i = 0, i1 = 0; i < count; i += 2, i1++) {
+ buf_set_u32(buffer_y + i1 * sizeof(uint32_t), 0, 32,
+ buf_get_u32(buffer + i * sizeof(uint32_t), 0, 32));
+ buf_set_u32(buffer_x + i1 * sizeof(uint32_t), 0, 32,
+ buf_get_u32(buffer + (i + 1) * sizeof(uint32_t), 0, 32));
+ }
+
+ err = dsp563xx_write_memory_core(target, MEM_Y, address, size, count / 2, buffer_y);
+
+ if (err != ERROR_OK) {
+ free(buffer_y);
+ free(buffer_x);
+ return err;
+ }
+
+ err = dsp563xx_write_memory_core(target, MEM_X, address, size, count / 2, buffer_x);
+
+ if (err != ERROR_OK) {
+ free(buffer_y);
+ free(buffer_x);
+ return err;
+ }
+
+ free(buffer_y);
+ free(buffer_x);
+
+ return ERROR_OK;
+}
+
+static int dsp563xx_write_memory_default(struct target *target,
+ uint32_t address,
+ uint32_t size,
+ uint32_t count,
+ const uint8_t *buffer)
+{
+ return dsp563xx_write_memory(target,
+ dsp563xx_get_default_memory(), address, size, count, buffer);
+}
+
+static int dsp563xx_write_buffer_default(struct target *target,
+ uint32_t address,
+ uint32_t size,
+ const uint8_t *buffer)
+{
+ return dsp563xx_write_memory(target, dsp563xx_get_default_memory(), address, size, 0,
+ buffer);
+}
+
+/*
+ * Exit with error here, because we support watchpoints over a custom command.
+ * This is because the DSP has separate X,Y,P memspace which is not compatible to the
+ * traditional watchpoint logic.
+ */
+static int dsp563xx_add_watchpoint(struct target *target, struct watchpoint *watchpoint)
+{
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+}
+
+/*
+ * @see dsp563xx_add_watchpoint
+ */
+static int dsp563xx_remove_watchpoint(struct target *target, struct watchpoint *watchpoint)
+{
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+}
+
+static void handle_md_output(struct command_context *cmd_ctx,
+ struct target *target,
+ uint32_t address,
+ unsigned size,
+ unsigned count,
+ const uint8_t *buffer)
+{
+ const unsigned line_bytecnt = 32;
+ unsigned line_modulo = line_bytecnt / size;
+
+ char output[line_bytecnt * 4 + 1];
+ unsigned output_len = 0;
+
+ const char *value_fmt;
+ switch (size) {
+ case 4:
+ value_fmt = "%8.8x ";
+ break;
+ case 2:
+ value_fmt = "%4.4x ";
+ break;
+ case 1:
+ value_fmt = "%2.2x ";
+ break;
+ default:
+ /* "can't happen", caller checked */
+ LOG_ERROR("invalid memory read size: %u", size);
+ return;
+ }
+
+ for (unsigned i = 0; i < count; i++) {
+ if (i % line_modulo == 0)
+ output_len += snprintf(output + output_len,
+ sizeof(output) - output_len,
+ "0x%8.8x: ",
+ (unsigned) (address + i));
+
+ uint32_t value = 0;
+ const uint8_t *value_ptr = buffer + i * size;
+ switch (size) {
+ case 4:
+ value = target_buffer_get_u32(target, value_ptr);
+ break;
+ case 2:
+ value = target_buffer_get_u16(target, value_ptr);
+ break;
+ case 1:
+ value = *value_ptr;
+ }
+ output_len += snprintf(output + output_len,
+ sizeof(output) - output_len,
+ value_fmt,
+ value);
+
+ if ((i % line_modulo == line_modulo - 1) || (i == count - 1)) {
+ command_print(cmd_ctx, "%s", output);
+ output_len = 0;
+ }
+ }
+}
+
+static int dsp563xx_add_custom_watchpoint(struct target *target, uint32_t address, uint32_t memType,
+ enum watchpoint_rw rw, enum watchpoint_condition cond)
+{
+ int err = ERROR_OK;
+ struct dsp563xx_common *dsp563xx = target_to_dsp563xx(target);
+
+ bool wasRunning = false;
+ /* Only set breakpoint when halted */
+ if (target->state != TARGET_HALTED) {
+ dsp563xx_halt(target);
+ wasRunning = true;
+ }
+
+ if (dsp563xx->hardware_breakpoint[0].used) {
+ LOG_ERROR("Cannot add watchpoint. Hardware resource already used.");
+ err = ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+ }
+
+ uint32_t obcr_value = 0;
+ if (err == ERROR_OK) {
+ obcr_value |= OBCR_b0_or_b1;
+ switch (memType) {
+ case MEM_X:
+ obcr_value |= OBCR_BP_MEM_X;
+ break;
+ case MEM_Y:
+ obcr_value |= OBCR_BP_MEM_Y;
+ break;
+ case MEM_P:
+ obcr_value |= OBCR_BP_MEM_P;
+ break;
+ default:
+ LOG_ERROR("Unknown memType parameter (%" PRIu32 ")", memType);
+ err = ERROR_TARGET_INVALID;
+ }
+ }
+
+ if (err == ERROR_OK) {
+ switch (rw) {
+ case WPT_READ:
+ obcr_value |= OBCR_BP_0(OBCR_BP_ON_READ);
+ break;
+ case WPT_WRITE:
+ obcr_value |= OBCR_BP_0(OBCR_BP_ON_WRITE);
+ break;
+ case WPT_ACCESS:
+ obcr_value |= OBCR_BP_0(OBCR_BP_ON_READ|OBCR_BP_ON_WRITE);
+ break;
+ default:
+ LOG_ERROR("Unsupported write mode (%d)", rw);
+ err = ERROR_TARGET_INVALID;
+ }
+ }
+
+ if (err == ERROR_OK) {
+ switch (cond) {
+ case EQUAL:
+ obcr_value |= OBCR_BP_0(OBCR_BP_CC_EQUAL);
+ break;
+ case NOT_EQUAL:
+ obcr_value |= OBCR_BP_0(OBCR_BP_CC_NOT_EQUAL);
+ break;
+ case LESS_THAN:
+ obcr_value |= OBCR_BP_0(OBCR_BP_CC_LESS_THAN);
+ break;
+ case GREATER:
+ obcr_value |= OBCR_BP_0(OBCR_BP_CC_GREATER_THAN);
+ break;
+ default:
+ LOG_ERROR("Unsupported condition code (%d)", cond);
+ err = ERROR_TARGET_INVALID;
+ }
+ }
+
+ if (err == ERROR_OK)
+ err = dsp563xx_once_reg_write(target->tap, 1, DSP563XX_ONCE_OMLR0, address);
+
+ if (err == ERROR_OK)
+ err = dsp563xx_once_reg_write(target->tap, 1, DSP563XX_ONCE_OMLR1, 0x0);
+
+ if (err == ERROR_OK)
+ err = dsp563xx_once_reg_write(target->tap, 1, DSP563XX_ONCE_OBCR, obcr_value);
+
+ if (err == ERROR_OK) {
+ /* You should write the memory breakpoint counter to 0 */
+ err = dsp563xx_once_reg_write(target->tap, 1, DSP563XX_ONCE_OMBC, 0);
+ }
+
+ if (err == ERROR_OK) {
+ /* You should write the memory breakpoint counter to 0 */
+ err = dsp563xx_once_reg_write(target->tap, 1, DSP563XX_ONCE_OTC, 0);
+ }
+
+ if (err == ERROR_OK)
+ dsp563xx->hardware_breakpoint[0].used = BPU_WATCHPOINT;
+
+ if (err == ERROR_OK && wasRunning) {
+ /* Resume from current PC */
+ err = dsp563xx_resume(target, 1, 0x0, 0, 0);
+ }
+
+ return err;
+}
+
+static int dsp563xx_remove_custom_watchpoint(struct target *target)
+{
+ int err = ERROR_OK;
+ struct dsp563xx_common *dsp563xx = target_to_dsp563xx(target);
+
+ if (dsp563xx->hardware_breakpoint[0].used != BPU_WATCHPOINT) {
+ LOG_ERROR("Cannot remove watchpoint, as no watchpoint is currently configured!");
+ err = ERROR_TARGET_INVALID;
+ }
+
+ if (err == ERROR_OK) {
+ /* Clear watchpoint by clearing OBCR. */
+ err = dsp563xx_once_reg_write(target->tap, 1, DSP563XX_ONCE_OBCR, 0);
+ }
+
+ if (err == ERROR_OK)
+ dsp563xx->hardware_breakpoint[0].used = BPU_NONE;
+
+ return err;
+}
+
+COMMAND_HANDLER(dsp563xx_add_watchpoint_command)
+{
+ int err = ERROR_OK;
+ struct target *target = get_current_target(CMD_CTX);
+
+ uint32_t mem_type = 0;
+ switch (CMD_NAME[2]) {
+ case 'x':
+ mem_type = MEM_X;
+ break;
+ case 'y':
+ mem_type = MEM_Y;
+ break;
+ case 'p':
+ mem_type = MEM_P;
+ break;
+ default:
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+
+ if (CMD_ARGC < 2)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ uint32_t address = 0;
+ if (CMD_ARGC > 2)
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], address);
+
+ enum watchpoint_condition cond;
+ switch (CMD_ARGV[0][0]) {
+ case '>':
+ cond = GREATER;
+ break;
+ case '<':
+ cond = LESS_THAN;
+ break;
+ case '=':
+ cond = EQUAL;
+ break;
+ case '!':
+ cond = NOT_EQUAL;
+ break;
+ default:
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+
+ enum watchpoint_rw rw;
+ switch (CMD_ARGV[1][0]) {
+ case 'r':
+ rw = WPT_READ;
+ break;
+ case 'w':
+ rw = WPT_WRITE;
+ break;
+ case 'a':
+ rw = WPT_ACCESS;
+ break;
+ default:
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+
+ err = dsp563xx_add_custom_watchpoint(target, address, mem_type, rw, cond);
+
+ return err;
+}
+
+/* Adding a breakpoint using the once breakpoint logic.
+ * Note that this mechanism is a true hw breakpoint and is share between the watchpoint logic.
+ * This means, you can only have one breakpoint/watchpoint at any time.
+ */
+static int dsp563xx_add_breakpoint(struct target *target, struct breakpoint *breakpoint)
+{
+ return dsp563xx_add_custom_watchpoint(target, breakpoint->address, MEM_P, WPT_READ, EQUAL);
+}
+
+static int dsp563xx_remove_breakpoint(struct target *target, struct breakpoint *breakpoint)
+{
+ return dsp563xx_remove_custom_watchpoint(target);
+}
+
+COMMAND_HANDLER(dsp563xx_remove_watchpoint_command)
+{
+ struct target *target = get_current_target(CMD_CTX);
+
+ return dsp563xx_remove_custom_watchpoint(target);
+}
+
+COMMAND_HANDLER(dsp563xx_mem_command)
+{
+ struct target *target = get_current_target(CMD_CTX);
+ int err = ERROR_OK;
+ int read_mem;
+ uint32_t address = 0;
+ uint32_t count = 1, i;
+ uint32_t pattern = 0;
+ uint32_t mem_type;
+ uint8_t *buffer, *b;
+
+ switch (CMD_NAME[1]) {
+ case 'w':
+ read_mem = 0;
+ break;
+ case 'd':
+ read_mem = 1;
+ break;
+ default:
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+
+ switch (CMD_NAME[3]) {
+ case 'x':
+ mem_type = MEM_X;
+ break;
+ case 'y':
+ mem_type = MEM_Y;
+ break;
+ case 'p':
+ mem_type = MEM_P;
+ break;
+ default:
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+
+ if (CMD_ARGC > 0)
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address);
+
+ if (read_mem == 0) {
+ if (CMD_ARGC < 2)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ if (CMD_ARGC > 1)
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], pattern);
+ if (CMD_ARGC > 2)
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], count);
+ }
+
+ if (read_mem == 1) {
+ if (CMD_ARGC < 1)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ if (CMD_ARGC > 1)
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], count);
+ }
+
+ buffer = calloc(count, sizeof(uint32_t));
+
+ if (read_mem == 1) {
+ err = dsp563xx_read_memory(target, mem_type, address, sizeof(uint32_t),
+ count, buffer);
+ if (err == ERROR_OK)
+ handle_md_output(CMD_CTX, target, address, sizeof(uint32_t), count, buffer);
+
+ } else {
+ b = buffer;
+
+ for (i = 0; i < count; i++) {
+ target_buffer_set_u32(target, b, pattern);
+ b += 4;
+ }
+
+ err = dsp563xx_write_memory(target,
+ mem_type,
+ address,
+ sizeof(uint32_t),
+ count,
+ buffer);
+ }
+
+ free(buffer);
+
+ return err;
+}
+
+static const struct command_registration dsp563xx_command_handlers[] = {
+ {
+ .name = "mwwx",
+ .handler = dsp563xx_mem_command,
+ .mode = COMMAND_EXEC,
+ .help = "write x memory words",
+ .usage = "address value [count]",
+ },
+ {
+ .name = "mwwy",
+ .handler = dsp563xx_mem_command,
+ .mode = COMMAND_EXEC,
+ .help = "write y memory words",
+ .usage = "address value [count]",
+ },
+ {
+ .name = "mwwp",
+ .handler = dsp563xx_mem_command,
+ .mode = COMMAND_EXEC,
+ .help = "write p memory words",
+ .usage = "address value [count]",
+ },
+ {
+ .name = "mdwx",
+ .handler = dsp563xx_mem_command,
+ .mode = COMMAND_EXEC,
+ .help = "display x memory words",
+ .usage = "address [count]",
+ },
+ {
+ .name = "mdwy",
+ .handler = dsp563xx_mem_command,
+ .mode = COMMAND_EXEC,
+ .help = "display y memory words",
+ .usage = "address [count]",
+ },
+ {
+ .name = "mdwp",
+ .handler = dsp563xx_mem_command,
+ .mode = COMMAND_EXEC,
+ .help = "display p memory words",
+ .usage = "address [count]",
+ },
+ /*
+ * Watchpoint commands
+ */
+ {
+ .name = "wpp",
+ .handler = dsp563xx_add_watchpoint_command,
+ .mode = COMMAND_EXEC,
+ .help = "Create p memspace watchpoint",
+ .usage = "(>|<|=|!) (r|w|a) address",
+ },
+ {
+ .name = "wpx",
+ .handler = dsp563xx_add_watchpoint_command,
+ .mode = COMMAND_EXEC,
+ .help = "Create x memspace watchpoint",
+ .usage = "(>|<|=|!) (r|w|a) address",
+ },
+ {
+ .name = "wpy",
+ .handler = dsp563xx_add_watchpoint_command,
+ .mode = COMMAND_EXEC,
+ .help = "Create y memspace watchpoint",
+ .usage = "(>|<|=|!) (r|w|a) address",
+ },
+ {
+ .name = "rwpc",
+ .handler = dsp563xx_remove_watchpoint_command,
+ .mode = COMMAND_EXEC,
+ .help = "remove watchpoint custom",
+ .usage = " ",
+ },
+ COMMAND_REGISTRATION_DONE
+};
+