From 53ec10b61da5de553c01f92bddf80c076bd49331 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Tue, 18 Aug 2020 11:01:41 -0700 Subject: [PATCH] Create `riscv repeat_read` command (#510) * WIP, apply stash with conflicts. Change-Id: Ia794bde419aa29161c68898d20e30527e69f5a31 * Fix conflict resolution problems. Change-Id: I4cedc348cf613f98cc5a36886f37c568ca644238 * Add repeat_read command. Only implemented for sba v1 right now, and poorly tested at that. Change-Id: I1d9ff63e1dea14b3f6a9f8ba4dad53668bf8038b * Hide bogus address in repeat_read Change-Id: Ib66c1fa60df9c7fc7cc87880b0fddc52825b48aa * WIP make repeat read work with progbuf. Change-Id: I555f8b880c8bf0d1ed0f3f90c7987a5b516a7a79 * WIP Change-Id: Ic567cea68355ae907e94bd25185a2c9be6fd798d * Fix error handling when increment is non-zero. Change-Id: I5a2f3f2ee948fd4e12c0443a542e85b7b5c5791a * Correctly(?) handle failures when increment is 0. I'm not 100% convinced that this ensures every read value shows up in the output, but it ought to work. Change-Id: I1af3e7174cf9d5e6f293456fb5ead629e17faaaa * Don't crash when asked to read no data. Change-Id: I4061b5c720a43a4f828384ab9eacc89557adfa05 * Remove unnecessary comment. Change-Id: I1be3d699b86299339b3a830ca1ef13c9f5b9fe0f * Document `riscv repeat_read`. Change-Id: I4a0f071f38784b2de034f8c1b0ce75d6d2d326b2 --- doc/openocd.texi | 6 ++ src/flash/nor/tcl.c | 3 +- src/target/dsp563xx.c | 3 +- src/target/riscv/riscv-011.c | 47 +++++++----- src/target/riscv/riscv-013.c | 143 ++++++++++++++++++++++------------- src/target/riscv/riscv.c | 60 +++++++++++++-- src/target/riscv/riscv.h | 3 + src/target/target.c | 7 +- src/target/target.h | 2 +- 9 files changed, 188 insertions(+), 86 deletions(-) diff --git a/doc/openocd.texi b/doc/openocd.texi index a80f6a41f..9a278b4a9 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -9659,6 +9659,12 @@ indicates the first custom register, whose abstract command number is 0xc000. This command must be executed before `init`. @end deffn +@deffn Command {riscv repeat_read} count address [size=4] +Quickly read count words of the given size from address. This can be useful +to read out a buffer that's memory-mapped to be accessed through a single +address, or to sample a changing value in a memory-mapped device. +@end deffn + @deffn Command {riscv set_command_timeout_sec} [seconds] Set the wall-clock timeout (in seconds) for individual commands. The default should work fine for all but the slowest targets (eg. simulators). diff --git a/src/flash/nor/tcl.c b/src/flash/nor/tcl.c index fb2053b89..741bb5e9e 100644 --- a/src/flash/nor/tcl.c +++ b/src/flash/nor/tcl.c @@ -681,7 +681,8 @@ COMMAND_HANDLER(handle_flash_md_command) retval = flash_driver_read(bank, buffer, offset, sizebytes); if (retval == ERROR_OK) - target_handle_md_output(CMD, target, address, wordsize, count, buffer); + target_handle_md_output(CMD, target, address, wordsize, count, + buffer, true); free(buffer); diff --git a/src/target/dsp563xx.c b/src/target/dsp563xx.c index 6a5c8683e..67c153806 100644 --- a/src/target/dsp563xx.c +++ b/src/target/dsp563xx.c @@ -2148,7 +2148,8 @@ COMMAND_HANDLER(dsp563xx_mem_command) err = dsp563xx_read_memory(target, mem_type, address, sizeof(uint32_t), count, buffer); if (err == ERROR_OK) - target_handle_md_output(CMD, target, address, sizeof(uint32_t), count, buffer); + target_handle_md_output(CMD, target, address, sizeof(uint32_t), + count, buffer, true); } else { b = buffer; diff --git a/src/target/riscv/riscv-011.c b/src/target/riscv/riscv-011.c index f1b3c6658..8bd88283b 100644 --- a/src/target/riscv/riscv-011.c +++ b/src/target/riscv/riscv-011.c @@ -1386,25 +1386,6 @@ static int halt(struct target *target) return ERROR_OK; } -static int init_target(struct command_context *cmd_ctx, - struct target *target) -{ - LOG_DEBUG("init"); - riscv_info_t *generic_info = (riscv_info_t *) target->arch_info; - generic_info->get_register = get_register; - generic_info->set_register = set_register; - - generic_info->version_specific = calloc(1, sizeof(riscv011_info_t)); - if (!generic_info->version_specific) - return ERROR_FAIL; - - /* Assume 32-bit until we discover the real value in examine(). */ - generic_info->xlen[0] = 32; - riscv_init_registers(target); - - return ERROR_OK; -} - static void deinit_target(struct target *target) { LOG_DEBUG("riscv_deinit_target()"); @@ -1980,8 +1961,13 @@ static int deassert_reset(struct target *target) } static int read_memory(struct target *target, target_addr_t address, - uint32_t size, uint32_t count, uint8_t *buffer) + uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment) { + if (increment != size) { + LOG_ERROR("read_memory with custom increment not implemented"); + return ERROR_NOT_IMPLEMENTED; + } + jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE); cache_set32(target, 0, lw(S0, ZERO, DEBUG_RAM_START + 16)); @@ -2283,6 +2269,26 @@ static int arch_state(struct target *target) return ERROR_OK; } +static int init_target(struct command_context *cmd_ctx, + struct target *target) +{ + LOG_DEBUG("init"); + riscv_info_t *generic_info = (riscv_info_t *) target->arch_info; + generic_info->get_register = get_register; + generic_info->set_register = set_register; + generic_info->read_memory = read_memory; + + generic_info->version_specific = calloc(1, sizeof(riscv011_info_t)); + if (!generic_info->version_specific) + return ERROR_FAIL; + + /* Assume 32-bit until we discover the real value in examine(). */ + generic_info->xlen[0] = 32; + riscv_init_registers(target); + + return ERROR_OK; +} + struct target_type riscv011_target = { .name = "riscv", @@ -2300,7 +2306,6 @@ struct target_type riscv011_target = { .assert_reset = assert_reset, .deassert_reset = deassert_reset, - .read_memory = read_memory, .write_memory = write_memory, .arch_state = arch_state, diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 6a252828e..80254963a 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -64,7 +64,7 @@ static int register_read_direct(struct target *target, uint64_t *value, uint32_t static int register_write_direct(struct target *target, unsigned number, uint64_t value); static int read_memory(struct target *target, target_addr_t address, - uint32_t size, uint32_t count, uint8_t *buffer); + uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment); static int write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer); static int riscv013_test_sba_config_reg(struct target *target, target_addr_t legal_address, @@ -1226,7 +1226,7 @@ static int scratch_read64(struct target *target, scratch_mem_t *scratch, case SPACE_DMI_RAM: { uint8_t buffer[8] = {0}; - if (read_memory(target, scratch->debug_address, 4, 2, buffer) != ERROR_OK) + if (read_memory(target, scratch->debug_address, 4, 2, buffer, 4) != ERROR_OK) return ERROR_FAIL; *value = buffer[0] | (((uint64_t) buffer[1]) << 8) | @@ -2030,6 +2030,7 @@ static int init_target(struct command_context *cmd_ctx, generic_info->authdata_write = &riscv013_authdata_write; generic_info->dmi_read = &dmi_read; generic_info->dmi_write = &dmi_write; + generic_info->read_memory = read_memory; generic_info->test_sba_config_reg = &riscv013_test_sba_config_reg; generic_info->test_compliance = &riscv013_test_compliance; generic_info->hart_count = &riscv013_hart_count; @@ -2424,8 +2425,13 @@ static int modify_privilege(struct target *target, uint64_t *mstatus, uint64_t * } static int read_memory_bus_v0(struct target *target, target_addr_t address, - uint32_t size, uint32_t count, uint8_t *buffer) + uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment) { + if (size != increment) { + LOG_ERROR("sba v0 reads only support size==increment"); + return ERROR_NOT_IMPLEMENTED; + } + LOG_DEBUG("System Bus Access: size: %d\tcount:%d\tstart address: 0x%08" TARGET_PRIxADDR, size, count, address); uint8_t *t_buffer = buffer; @@ -2504,8 +2510,13 @@ static int read_memory_bus_v0(struct target *target, target_addr_t address, * Read the requested memory using the system bus interface. */ static int read_memory_bus_v1(struct target *target, target_addr_t address, - uint32_t size, uint32_t count, uint8_t *buffer) + uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment) { + if (increment != size && increment != 0) { + LOG_ERROR("sba v1 reads only support increment of size or 0"); + return ERROR_NOT_IMPLEMENTED; + } + RISCV013_INFO(info); target_addr_t next_address = address; target_addr_t end_address = address + count * size; @@ -2513,7 +2524,8 @@ static int read_memory_bus_v1(struct target *target, target_addr_t address, while (next_address < end_address) { uint32_t sbcs_write = set_field(0, DMI_SBCS_SBREADONADDR, 1); sbcs_write |= sb_sbaccess(size); - sbcs_write = set_field(sbcs_write, DMI_SBCS_SBAUTOINCREMENT, 1); + if (increment == size) + sbcs_write = set_field(sbcs_write, DMI_SBCS_SBAUTOINCREMENT, 1); if (count > 1) sbcs_write = set_field(sbcs_write, DMI_SBCS_SBREADONDATA, count > 1); if (dmi_write(target, DMI_SBCS, sbcs_write) != ERROR_OK) @@ -2651,8 +2663,13 @@ static int batch_run(const struct target *target, struct riscv_batch *batch) * aamsize fields in the memory access abstract command. */ static int read_memory_abstract(struct target *target, target_addr_t address, - uint32_t size, uint32_t count, uint8_t *buffer) + uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment) { + if (size != increment) { + LOG_ERROR("abstract command reads only support size==increment"); + return ERROR_NOT_IMPLEMENTED; + } + int result = ERROR_OK; LOG_DEBUG("reading %d words of %d bytes from 0x%" TARGET_PRIxADDR, count, @@ -2771,7 +2788,7 @@ static int write_memory_abstract(struct target *target, target_addr_t address, * even if cmderr=busy is encountered. */ static int read_memory_progbuf_inner(struct target *target, target_addr_t address, - uint32_t size, uint32_t count, uint8_t *buffer) + uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment) { RISCV013_INFO(info); @@ -2781,6 +2798,11 @@ static int read_memory_progbuf_inner(struct target *target, target_addr_t addres result = register_write_direct(target, GDB_REGNO_S0, address); if (result != ERROR_OK) return result; + + if (increment == 0 && + register_write_direct(target, GDB_REGNO_S2, 0) != ERROR_OK) + return ERROR_FAIL; + uint32_t command = access_register_command(target, GDB_REGNO_S1, riscv_xlen(target), AC_ACCESS_REGISTER_TRANSFER | AC_ACCESS_REGISTER_POSTEXEC); @@ -2808,11 +2830,10 @@ static int read_memory_progbuf_inner(struct target *target, target_addr_t addres /* read_addr is the next address that the hart will read from, which is the * value in s0. */ - riscv_addr_t read_addr = address + 2 * size; - riscv_addr_t fin_addr = address + (count * size); - while (read_addr < fin_addr) { - LOG_DEBUG("read_addr=0x%" PRIx64 ", fin_addr=0x%" PRIx64, read_addr, - fin_addr); + unsigned index = 2; + while (index < count) { + riscv_addr_t read_addr = address + index * increment; + LOG_DEBUG("i=%d, count=%d, read_addr=0x%" PRIx64, index, count, read_addr); /* The pipeline looks like this: * memory -> s1 -> dm_data0 -> debugger * Right now: @@ -2821,14 +2842,11 @@ static int read_memory_progbuf_inner(struct target *target, target_addr_t addres * dm_data0 contains[read_addr-size*2] */ - LOG_DEBUG("creating burst to read from 0x%" PRIx64 - " up to 0x%" PRIx64, read_addr, fin_addr); - assert(read_addr >= address && read_addr < fin_addr); struct riscv_batch *batch = riscv_batch_alloc(target, 32, info->dmi_busy_delay + info->ac_busy_delay); - size_t reads = 0; - for (riscv_addr_t addr = read_addr; addr < fin_addr; addr += size) { + unsigned reads = 0; + for (unsigned j = index; j < count; j++) { if (size > 4) riscv_batch_add_dmi_read(batch, DMI_DATA1); riscv_batch_add_dmi_read(batch, DMI_DATA0); @@ -2851,12 +2869,12 @@ static int read_memory_progbuf_inner(struct target *target, target_addr_t addres return ERROR_FAIL; info->cmderr = get_field(abstractcs, DMI_ABSTRACTCS_CMDERR); - riscv_addr_t next_read_addr; + unsigned next_index; unsigned ignore_last = 0; switch (info->cmderr) { case CMDERR_NONE: LOG_DEBUG("successful (partial?) memory read"); - next_read_addr = read_addr + reads * size; + next_index = index + reads; break; case CMDERR_BUSY: LOG_DEBUG("memory read resulted in busy response"); @@ -2880,21 +2898,30 @@ static int read_memory_progbuf_inner(struct target *target, target_addr_t addres } /* See how far we got, clobbering dmi_data0. */ - result = register_read_direct(target, &next_read_addr, - GDB_REGNO_S0); + if (increment == 0) { + uint64_t counter; + result = register_read_direct(target, &counter, GDB_REGNO_S2); + next_index = counter; + } else { + uint64_t next_read_addr; + result = register_read_direct(target, &next_read_addr, + GDB_REGNO_S0); + next_index = (next_read_addr - address) / increment; + } if (result != ERROR_OK) { riscv_batch_free(batch); goto error; } + uint64_t value64 = (((uint64_t) dmi_data1) << 32) | dmi_data0; - write_to_buf(buffer + next_read_addr - 2 * size - address, value64, size); - log_memory_access(next_read_addr - 2 * size, value64, size, true); + write_to_buf(buffer + (next_index - 2) * size, value64, size); + log_memory_access(address + (next_index - 2) * size, value64, size, true); /* Restore the command, and execute it. * Now DMI_DATA0 contains the next value just as it would if no * error had occurred. */ dmi_write_exec(target, DMI_COMMAND, command, true); - next_read_addr += size; + next_index++; dmi_write(target, DMI_ABSTRACTAUTO, 1 << DMI_ABSTRACTAUTO_AUTOEXECDATA_OFFSET); @@ -2912,13 +2939,13 @@ static int read_memory_progbuf_inner(struct target *target, target_addr_t addres /* Now read whatever we got out of the batch. */ dmi_status_t status = DMI_STATUS_SUCCESS; - riscv_addr_t receive_addr = read_addr - size * 2; unsigned read = 0; - for (size_t i = 0; i < reads; i++) { - assert(receive_addr < address + size * count); - if (receive_addr < address) - continue; - if (receive_addr > next_read_addr - (3 + ignore_last) * size) + assert(index >= 2); + for (unsigned j = index - 2; j < index + reads; j++) { + assert(j < count); + LOG_DEBUG("index=%d, reads=%d, next_index=%d, ignore_last=%d, j=%d", + index, reads, next_index, ignore_last, j); + if (j + 3 + ignore_last > next_index) break; status = riscv_batch_get_dmi_read_op(batch, read); @@ -2952,14 +2979,12 @@ static int read_memory_progbuf_inner(struct target *target, target_addr_t addres value |= riscv_batch_get_dmi_read_data(batch, read); read++; } - riscv_addr_t offset = receive_addr - address; + riscv_addr_t offset = j * size; write_to_buf(buffer + offset, value, size); - log_memory_access(receive_addr, value, size, true); - - receive_addr += size; + log_memory_access(address + j * increment, value, size, true); } - read_addr = next_read_addr; + index = next_index; riscv_batch_free(batch); } @@ -3069,7 +3094,7 @@ static int read_memory_progbuf_one(struct target *target, target_addr_t address, * Read the requested memory, silently handling memory access errors. */ static int read_memory_progbuf(struct target *target, target_addr_t address, - uint32_t size, uint32_t count, uint8_t *buffer) + uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment) { if (riscv_xlen(target) < size * 8) { LOG_ERROR("XLEN (%d) is too short for %d-bit memory read.", @@ -3099,12 +3124,15 @@ static int read_memory_progbuf(struct target *target, target_addr_t address, /* s0 holds the next address to write to * s1 holds the next data value to write + * s2 is a counter in case increment is 0 */ - uint64_t s0, s1; + uint64_t s0, s1, s2; if (register_read(target, &s0, GDB_REGNO_S0) != ERROR_OK) return ERROR_FAIL; if (register_read(target, &s1, GDB_REGNO_S1) != ERROR_OK) return ERROR_FAIL; + if (increment == 0 && register_read(target, &s2, GDB_REGNO_S1) != ERROR_OK) + return ERROR_FAIL; /* Write the program (load, increment) */ struct riscv_program program; @@ -3132,36 +3160,39 @@ static int read_memory_progbuf(struct target *target, target_addr_t address, if (riscv_enable_virtual && has_sufficient_progbuf(target, 5) && get_field(mstatus, MSTATUS_MPRV)) riscv_program_csrrci(&program, GDB_REGNO_ZERO, CSR_DCSR_MPRVEN, GDB_REGNO_DCSR); - riscv_program_addi(&program, GDB_REGNO_S0, GDB_REGNO_S0, size); + if (increment == 0) + riscv_program_addi(&program, GDB_REGNO_S2, GDB_REGNO_S2, 1); + else + riscv_program_addi(&program, GDB_REGNO_S0, GDB_REGNO_S0, increment); if (riscv_program_ebreak(&program) != ERROR_OK) return ERROR_FAIL; if (riscv_program_write(&program) != ERROR_OK) return ERROR_FAIL; - result = read_memory_progbuf_inner(target, address, size, count, buffer); + result = read_memory_progbuf_inner(target, address, size, count, buffer, increment); if (result != ERROR_OK) { /* The full read did not succeed, so we will try to read each word individually. */ /* This will not be fast, but reading outside actual memory is a special case anyway. */ /* It will make the toolchain happier, especially Eclipse Memory View as it reads ahead. */ target_addr_t address_i = address; - uint32_t size_i = size; uint32_t count_i = 1; uint8_t *buffer_i = buffer; - for (uint32_t i = 0; i < count; i++, address_i += size_i, buffer_i += size_i) { + for (uint32_t i = 0; i < count; i++, address_i += increment, buffer_i += size) { + keep_alive(); /* TODO: This is much slower than it needs to be because we end up * writing the address to read for every word we read. */ - result = read_memory_progbuf_inner(target, address_i, size_i, count_i, buffer_i); + result = read_memory_progbuf_inner(target, address_i, size, count_i, buffer_i, increment); /* The read of a single word failed, so we will just return 0 for that instead */ if (result != ERROR_OK) { LOG_DEBUG("error reading single word of %d bytes from 0x%" TARGET_PRIxADDR, - size_i, address_i); + size, address_i); uint64_t value_i = 0; - write_to_buf(buffer_i, value_i, size_i); + write_to_buf(buffer_i, value_i, size); } } result = ERROR_OK; @@ -3169,6 +3200,8 @@ static int read_memory_progbuf(struct target *target, target_addr_t address, riscv_set_register(target, GDB_REGNO_S0, s0); riscv_set_register(target, GDB_REGNO_S1, s1); + if (increment == 0) + riscv_set_register(target, GDB_REGNO_S2, s2); /* Restore MSTATUS */ if (mstatus != mstatus_old) @@ -3179,12 +3212,15 @@ static int read_memory_progbuf(struct target *target, target_addr_t address, } static int read_memory(struct target *target, target_addr_t address, - uint32_t size, uint32_t count, uint8_t *buffer) + uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment) { - RISCV013_INFO(info); + if (count == 0) + return ERROR_OK; + RISCV013_INFO(info); if (has_sufficient_progbuf(target, 3) && !riscv_prefer_sba) - return read_memory_progbuf(target, address, size, count, buffer); + return read_memory_progbuf(target, address, size, count, buffer, + increment); if ((get_field(info->sbcs, DMI_SBCS_SBACCESS8) && size == 1) || (get_field(info->sbcs, DMI_SBCS_SBACCESS16) && size == 2) || @@ -3192,15 +3228,19 @@ static int read_memory(struct target *target, target_addr_t address, (get_field(info->sbcs, DMI_SBCS_SBACCESS64) && size == 8) || (get_field(info->sbcs, DMI_SBCS_SBACCESS128) && size == 16)) { if (get_field(info->sbcs, DMI_SBCS_SBVERSION) == 0) - return read_memory_bus_v0(target, address, size, count, buffer); + return read_memory_bus_v0(target, address, size, count, buffer, + increment); else if (get_field(info->sbcs, DMI_SBCS_SBVERSION) == 1) - return read_memory_bus_v1(target, address, size, count, buffer); + return read_memory_bus_v1(target, address, size, count, buffer, + increment); } if (has_sufficient_progbuf(target, 3)) - return read_memory_progbuf(target, address, size, count, buffer); + return read_memory_progbuf(target, address, size, count, buffer, + increment); - return read_memory_abstract(target, address, size, count, buffer); + return read_memory_abstract(target, address, size, count, buffer, + increment); } static int write_memory_bus_v0(struct target *target, target_addr_t address, @@ -3643,7 +3683,6 @@ struct target_type riscv013_target = { .assert_reset = assert_reset, .deassert_reset = deassert_reset, - .read_memory = read_memory, .write_memory = write_memory, .arch_state = arch_state, diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index e213ffa6c..56c95f8ce 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -1487,12 +1487,12 @@ static int riscv_mmu(struct target *target, int *enabled) static int riscv_address_translate(struct target *target, target_addr_t virtual, target_addr_t *physical) { + RISCV_INFO(r); riscv_reg_t satp_value; int mode; uint64_t ppn_value; target_addr_t table_address; virt2phys_info_t *info; - struct target_type *tt = get_target_type(target); uint64_t pte; int i; @@ -1545,8 +1545,8 @@ static int riscv_address_translate(struct target *target, (vpn << info->pte_shift); uint8_t buffer[8]; assert(info->pte_shift <= 3); - int retval = tt->read_memory(target, pte_address, - 4, (1 << info->pte_shift) / 4, buffer); + int retval = r->read_memory(target, pte_address, + 4, (1 << info->pte_shift) / 4, buffer, 4); if (retval != ERROR_OK) return ERROR_FAIL; @@ -1610,10 +1610,10 @@ static int riscv_virt2phys(struct target *target, target_addr_t virtual, target_ static int riscv_read_phys_memory(struct target *target, target_addr_t phys_address, uint32_t size, uint32_t count, uint8_t *buffer) { + RISCV_INFO(r); if (riscv_select_current_hart(target) != ERROR_OK) return ERROR_FAIL; - struct target_type *tt = get_target_type(target); - return tt->read_memory(target, phys_address, size, count, buffer); + return r->read_memory(target, phys_address, size, count, buffer, size); } static int riscv_read_memory(struct target *target, target_addr_t address, @@ -1631,8 +1631,8 @@ static int riscv_read_memory(struct target *target, target_addr_t address, if (target->type->virt2phys(target, address, &physical_addr) == ERROR_OK) address = physical_addr; - struct target_type *tt = get_target_type(target); - return tt->read_memory(target, address, size, count, buffer); + RISCV_INFO(r); + return r->read_memory(target, address, size, count, buffer, size); } static int riscv_write_phys_memory(struct target *target, target_addr_t phys_address, @@ -2656,7 +2656,53 @@ COMMAND_HANDLER(riscv_set_ebreaku) return ERROR_OK; } +COMMAND_HANDLER(handle_repeat_read) +{ + struct target *target = get_current_target(CMD_CTX); + RISCV_INFO(r); + + if (CMD_ARGC < 2) { + LOG_ERROR("Command requires at least count and address arguments."); + return ERROR_COMMAND_SYNTAX_ERROR; + } + if (CMD_ARGC > 3) { + LOG_ERROR("Command takes at most 3 arguments."); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + uint32_t count; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], count); + target_addr_t address; + COMMAND_PARSE_ADDRESS(CMD_ARGV[1], address); + uint32_t size = 4; + if (CMD_ARGC > 2) + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], size); + + if (count == 0) + return ERROR_OK; + + uint8_t *buffer = malloc(size * count); + if (!buffer) { + LOG_ERROR("malloc failed"); + return ERROR_FAIL; + } + int result = r->read_memory(target, address, size, count, buffer, 0); + if (result == ERROR_OK) { + target_handle_md_output(cmd, target, address, size, count, buffer, + false); + } + free(buffer); + return result; +} + static const struct command_registration riscv_exec_command_handlers[] = { + { + .name = "repeat_read", + .handler = handle_repeat_read, + .mode = COMMAND_ANY, + .usage = "riscv repeat_read count address [size=4]", + .help = "Repeatedly read the value at address." + }, { .name = "test_compliance", .handler = riscv_test_compliance, diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h index 2714d9b9b..87dc3736b 100644 --- a/src/target/riscv/riscv.h +++ b/src/target/riscv/riscv.h @@ -152,6 +152,9 @@ typedef struct { int (*test_compliance)(struct target *target); + int (*read_memory)(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment); + /* How many harts are attached to the DM that this target is attached to? */ int (*hart_count)(struct target *target); unsigned (*data_bits)(struct target *target); diff --git a/src/target/target.c b/src/target/target.c index ad33fa404..3395b2a28 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -3184,7 +3184,7 @@ COMMAND_HANDLER(handle_step_command) void target_handle_md_output(struct command_invocation *cmd, struct target *target, target_addr_t address, unsigned size, - unsigned count, const uint8_t *buffer) + unsigned count, const uint8_t *buffer, bool include_address) { const unsigned line_bytecnt = 32; unsigned line_modulo = line_bytecnt / size; @@ -3213,7 +3213,7 @@ void target_handle_md_output(struct command_invocation *cmd, } for (unsigned i = 0; i < count; i++) { - if (i % line_modulo == 0) { + if (include_address && (i % line_modulo == 0)) { output_len += snprintf(output + output_len, sizeof(output) - output_len, TARGET_ADDR_FMT ": ", @@ -3297,7 +3297,8 @@ COMMAND_HANDLER(handle_md_command) struct target *target = get_current_target(CMD_CTX); int retval = fn(target, address, size, count, buffer); if (ERROR_OK == retval) - target_handle_md_output(CMD, target, address, size, count, buffer); + target_handle_md_output(CMD, target, address, size, count, buffer, + true); free(buffer); diff --git a/src/target/target.h b/src/target/target.h index 57440006c..b6f8d5da1 100644 --- a/src/target/target.h +++ b/src/target/target.h @@ -753,7 +753,7 @@ void target_handle_event(struct target *t, enum target_event e); void target_handle_md_output(struct command_invocation *cmd, struct target *target, target_addr_t address, unsigned size, - unsigned count, const uint8_t *buffer); + unsigned count, const uint8_t *buffer, bool include_address); #define ERROR_TARGET_INVALID (-300) #define ERROR_TARGET_INIT_FAILED (-301)