From 77802af655fef154a1eff30d59e699c11917ecd2 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Tue, 10 Oct 2017 16:27:51 -0700 Subject: [PATCH 01/20] Remove duplicate progbuf size variable. Change-Id: I662ff84d13ecfc7faae51406a4df57a3643116f0 --- src/target/riscv/riscv-013.c | 34 +++++++++++++--------------------- 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index f17ef72e6..f8fd7e67e 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -32,7 +32,6 @@ static void riscv013_on_step_or_resume(struct target *target, bool step); static void riscv013_step_or_resume_current_hart(struct target *target, bool step); static riscv_addr_t riscv013_progbuf_addr(struct target *target); -static riscv_addr_t riscv013_progbuf_size(struct target *target); static riscv_addr_t riscv013_data_size(struct target *target); static riscv_addr_t riscv013_data_addr(struct target *target); static void riscv013_set_autoexec(struct target *target, unsigned index, @@ -176,7 +175,7 @@ typedef struct { bool need_strict_step; // Some memoized values - int progbuf_size, progbuf_addr, data_addr, data_size; + int progbuf_addr, data_addr, data_size; bool abstract_read_csr_supported; bool abstract_write_csr_supported; @@ -908,7 +907,7 @@ static int init_target(struct command_context *cmd_ctx, return ERROR_FAIL; riscv013_info_t *info = get_info(target); - info->progbuf_size = -1; + info->progsize = -1; info->progbuf_addr = -1; info->data_size = -1; info->data_addr = -1; @@ -1078,7 +1077,7 @@ static int examine(struct target *target) /* Without knowing anything else we can at least mess with the * program buffer. */ - r->debug_buffer_size[i] = riscv013_progbuf_size(target); + r->debug_buffer_size[i] = info->progsize; /* Guess this is a 32-bit system, we're probing it. */ r->xlen[i] = 32; @@ -1874,15 +1873,17 @@ void riscv013_debug_buffer_leave(struct target *target, struct riscv_program *pr void riscv013_write_debug_buffer(struct target *target, unsigned index, riscv_insn_t data) { - if (index >= riscv013_progbuf_size(target)) - return dmi_write(target, DMI_DATA0 + index - riscv013_progbuf_size(target), data); + RISCV013_INFO(info); + if (index >= info->progsize) + return dmi_write(target, DMI_DATA0 + index - info->progsize, data); return dmi_write(target, DMI_PROGBUF0 + index, data); } riscv_insn_t riscv013_read_debug_buffer(struct target *target, unsigned index) { - if (index >= riscv013_progbuf_size(target)) - return dmi_read(target, DMI_DATA0 + index - riscv013_progbuf_size(target)); + RISCV013_INFO(info); + if (index >= info->progsize) + return dmi_read(target, DMI_DATA0 + index - info->progsize); return dmi_read(target, DMI_PROGBUF0 + index); } @@ -1998,16 +1999,6 @@ riscv_addr_t riscv013_progbuf_addr(struct target *target) return info->progbuf_addr; } -riscv_addr_t riscv013_progbuf_size(struct target *target) -{ - RISCV013_INFO(info); - if (info->progbuf_size == -1) { - uint32_t acs = dmi_read(target, DMI_ABSTRACTCS); - info->progbuf_size = get_field(acs, DMI_ABSTRACTCS_PROGSIZE); - } - return info->progbuf_size; -} - riscv_addr_t riscv013_data_size(struct target *target) { RISCV013_INFO(info); @@ -2030,12 +2021,13 @@ riscv_addr_t riscv013_data_addr(struct target *target) void riscv013_set_autoexec(struct target *target, unsigned index, bool enabled) { - if (index >= riscv013_progbuf_size(target)) { + RISCV013_INFO(info); + if (index >= info->progsize) { LOG_DEBUG("setting bit %d in AUTOEXECDATA to %d", index, enabled); uint32_t aa = dmi_read(target, DMI_ABSTRACTAUTO); uint32_t aa_aed = get_field(aa, DMI_ABSTRACTAUTO_AUTOEXECDATA); - aa_aed &= ~(1 << (index - riscv013_progbuf_size(target))); - aa_aed |= (enabled << (index - riscv013_progbuf_size(target))); + aa_aed &= ~(1 << (index - info->progsize)); + aa_aed |= (enabled << (index - info->progsize)); aa = set_field(aa, DMI_ABSTRACTAUTO_AUTOEXECDATA, aa_aed); dmi_write(target, DMI_ABSTRACTAUTO, aa); } else { From 94e82507134610180843d70c8b244d98de26171a Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Thu, 12 Oct 2017 11:45:52 -0700 Subject: [PATCH 02/20] WIP; doesn't work. Change-Id: Ia407e82ccbd2044ad61e0845d285dd5765154476 --- src/target/riscv/program.c | 71 ------------------- src/target/riscv/program.h | 16 ----- src/target/riscv/riscv-013.c | 129 +++++++++++++++-------------------- src/target/riscv/riscv.c | 9 --- src/target/riscv/riscv.h | 4 -- 5 files changed, 55 insertions(+), 174 deletions(-) diff --git a/src/target/riscv/program.c b/src/target/riscv/program.c index d052574d4..2fc80419b 100644 --- a/src/target/riscv/program.c +++ b/src/target/riscv/program.c @@ -100,77 +100,6 @@ int riscv_program_exec(struct riscv_program *p, struct target *t) return ERROR_OK; } -riscv_addr_t riscv_program_alloc_data(struct riscv_program *p, size_t bytes) -{ - riscv_addr_t addr = - riscv_debug_buffer_addr(p->target) - + riscv_debug_buffer_size(p->target) * sizeof(p->debug_buffer[0]) - - p->data_count * sizeof(p->debug_buffer[0]) - - bytes; - while (addr % bytes != 0) addr--; - - riscv_addr_t ptop = - riscv_debug_buffer_addr(p->target) - + p->instruction_count * sizeof(p->debug_buffer[0]); - - if (addr <= ptop) { - LOG_ERROR("unable to allocate %d bytes", (int)bytes); - return RISCV_PROGRAM_ALLOC_FAIL; - } - - p->data_count = - + riscv_debug_buffer_size(p->target) - - (addr - riscv_debug_buffer_addr(p->target)) / sizeof(p->debug_buffer[0]); - return addr; -} - -riscv_addr_t riscv_program_alloc_x(struct riscv_program *p) -{ - return riscv_program_alloc_data(p, p->target_xlen / 8); -} - -riscv_addr_t riscv_program_alloc_d(struct riscv_program *p) -{ - return riscv_program_alloc_data(p, 8); -} - -riscv_addr_t riscv_program_alloc_w(struct riscv_program *p) -{ - return riscv_program_alloc_data(p, 4); -} - -riscv_addr_t riscv_program_alloc_h(struct riscv_program *p) -{ - return riscv_program_alloc_data(p, 2); -} - -riscv_addr_t riscv_program_alloc_b(struct riscv_program *p) -{ - return riscv_program_alloc_data(p, 1); -} - -riscv_insn_t riscv_program_read_ram(struct riscv_program *p, riscv_addr_t addr) -{ - if (addr < riscv_debug_buffer_addr(p->target)) - return -1; - if ((size_t)addr > riscv_debug_buffer_addr(p->target) + (riscv_debug_buffer_size(p->target) * sizeof(p->debug_buffer[0]))) - return -1; - - int off = (addr - riscv_debug_buffer_addr(p->target)) / sizeof(p->debug_buffer[0]); - return p->debug_buffer[off]; -} - -void riscv_program_write_ram(struct riscv_program *p, riscv_addr_t addr, uint64_t d) -{ - if (addr < riscv_debug_buffer_addr(p->target)) - return; - if ((size_t)addr > riscv_debug_buffer_addr(p->target) + (riscv_debug_buffer_size(p->target) * sizeof(p->debug_buffer[0]))) - return; - - int off = (addr - riscv_debug_buffer_addr(p->target)) / sizeof(p->debug_buffer[0]); - p->debug_buffer[off] = d; -} - int riscv_program_swr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int offset) { p->writes_memory = 1; diff --git a/src/target/riscv/program.h b/src/target/riscv/program.h index ac1127ed9..82e9b5e99 100644 --- a/src/target/riscv/program.h +++ b/src/target/riscv/program.h @@ -60,22 +60,6 @@ int riscv_program_insert(struct riscv_program *p, riscv_insn_t i); * memory. */ int riscv_program_save_to_dscratch(struct riscv_program *p, enum gdb_regno to_save); -/* Allocates data of various sizes. Either returns the absolute physical - * address or RISCV_PROGRAM_ALLOC_FAIL on failure. */ -riscv_addr_t riscv_program_alloc_data(struct riscv_program *p, size_t bytes); -riscv_addr_t riscv_program_alloc_x(struct riscv_program *p); -riscv_addr_t riscv_program_alloc_d(struct riscv_program *p); -riscv_addr_t riscv_program_alloc_w(struct riscv_program *p); -riscv_addr_t riscv_program_alloc_h(struct riscv_program *p); -riscv_addr_t riscv_program_alloc_b(struct riscv_program *p); -#define RISCV_PROGRAM_ALLOC_FAIL ((riscv_addr_t)(-1)) - -/* Reads a word of memory from this program's internal view of the debug RAM. - * This is what you want to use to get data back from the program after it - * executes. */ -riscv_insn_t riscv_program_read_ram(struct riscv_program *p, riscv_addr_t addr); -void riscv_program_write_ram(struct riscv_program *p, riscv_addr_t a, uint64_t d); - /* Helpers to assembly various instructions. Return 0 on success. These might * assembly into a multi-instruction sequence that overwrites some other * register, but those will be properly saved and restored. */ diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index f8fd7e67e..483c5237b 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -31,13 +31,13 @@ static void riscv013_on_step_or_resume(struct target *target, bool step); static void riscv013_step_or_resume_current_hart(struct target *target, bool step); -static riscv_addr_t riscv013_progbuf_addr(struct target *target); -static riscv_addr_t riscv013_data_size(struct target *target); -static riscv_addr_t riscv013_data_addr(struct target *target); -static void riscv013_set_autoexec(struct target *target, unsigned index, - bool enabled); -static int riscv013_debug_buffer_register(struct target *target, riscv_addr_t addr); -static void riscv013_clear_abstract_error(struct target *target); +//static riscv_addr_t riscv013_progbuf_addr(struct target *target); +//static riscv_addr_t riscv013_data_size(struct target *target); +//static riscv_addr_t riscv013_data_addr(struct target *target); +//static void riscv013_set_autoexec(struct target *target, unsigned index, + //bool enabled); +//static int riscv013_debug_buffer_register(struct target *target, riscv_addr_t addr); +//static void riscv013_clear_abstract_error(struct target *target); /* Implementations of the functions in riscv_info_t. */ static riscv_reg_t riscv013_get_register(struct target *target, int hartid, int regid); @@ -517,6 +517,7 @@ static void dmi_write(struct target *target, uint16_t address, uint64_t value) } } +#if 0 static void increase_ac_busy_delay(struct target *target) { riscv013_info_t *info = get_info(target); @@ -525,6 +526,7 @@ static void increase_ac_busy_delay(struct target *target) info->dtmcontrol_idle, info->dmi_busy_delay, info->ac_busy_delay); } +#endif uint32_t abstract_register_size(unsigned width) { @@ -769,6 +771,8 @@ static int register_write_direct(struct target *target, unsigned number, riscv_program_init(&program, target); + assert(0); +#if 0 riscv_addr_t input = riscv_program_alloc_d(&program); riscv_program_write_ram(&program, input + 4, value >> 32); riscv_program_write_ram(&program, input, value); @@ -794,6 +798,7 @@ static int register_write_direct(struct target *target, unsigned number, } return ERROR_OK; +#endif } /** Actually read registers from the target right now. */ @@ -805,6 +810,22 @@ static int register_read_direct(struct target *target, uint64_t *value, uint32_t if (result != ERROR_OK) { struct riscv_program program; riscv_program_init(&program, target); + assert(0); + assert(number != GDB_REGNO_S0); + + uint64_t s0; + if (register_read_direct(target, &s0, GDB_REGNO_S0) != ERROR_OK) + return ERROR_FAIL; + + // Write program to move data into s0. + // Execute program. + // Read S0 + if (register_read_direct(target, value, GDB_REGNO_S0) != ERROR_OK) + return ERROR_FAIL; + // Restore S0. + if (register_write_direct(target, GDB_REGNO_S0, &s0) != ERROR_OK) + return ERROR_FAIL; +#if 0 riscv_addr_t output = riscv_program_alloc_d(&program); riscv_program_write_ram(&program, output + 4, 0); riscv_program_write_ram(&program, output, 0); @@ -833,6 +854,7 @@ static int register_read_direct(struct target *target, uint64_t *value, uint32_t *value = 0; *value |= ((uint64_t)(riscv_program_read_ram(&program, output + 4))) << 32; *value |= riscv_program_read_ram(&program, output); +#endif } LOG_DEBUG("[%d] reg[0x%x] = 0x%" PRIx64, riscv_current_hartid(target), @@ -1080,77 +1102,19 @@ static int examine(struct target *target) r->debug_buffer_size[i] = info->progsize; /* Guess this is a 32-bit system, we're probing it. */ - r->xlen[i] = 32; - - /* First find the low 32 bits of the program buffer. This is - * used to check for alignment. */ - struct riscv_program program32; - riscv_program_init(&program32, target); - riscv_program_csrrw(&program32, GDB_REGNO_S0, GDB_REGNO_S0, GDB_REGNO_DSCRATCH); - riscv_program_insert(&program32, auipc(GDB_REGNO_S0)); - riscv_program_insert(&program32, sw(GDB_REGNO_S0, GDB_REGNO_S0, -4)); - riscv_program_csrrw(&program32, GDB_REGNO_S0, GDB_REGNO_S0, GDB_REGNO_DSCRATCH); - riscv_program_fence(&program32); - riscv_program_exec(&program32, target); - - riscv_addr_t progbuf_addr = dmi_read(target, DMI_PROGBUF0) - 4; - if (get_field(dmi_read(target, DMI_ABSTRACTCS), DMI_ABSTRACTCS_CMDERR) != 0) { - LOG_ERROR("Unable to find the address of the program buffer on hart %d", i); - r->xlen[i] = -1; - continue; - } - r->debug_buffer_addr[i] = progbuf_addr; - - /* Check to see if the core can execute 64 bit instructions. - * In order to make this work we first need to */ - int offset = (progbuf_addr % 8 == 0) ? -4 : 0; - - /* This program uses a temporary register. If the core can not - * execute 64 bit instruction, the original value of temporary - * register (s0) will not be restored due to an exception. - * So we have to save it and restore manually in that case. - * If the core can execute 64 bit instruction, the saved value - * is wrong, because it was read with 32 bit lw instruction, - * but the value of s0 will be restored by the reverse swap - * of s0 and dscratch registers. */ - uint64_t s0 = riscv_get_register(target, GDB_REGNO_S0); - - struct riscv_program program64; - riscv_program_init(&program64, target); - riscv_program_csrrw(&program64, GDB_REGNO_S0, GDB_REGNO_S0, GDB_REGNO_DSCRATCH); - riscv_program_insert(&program64, auipc(GDB_REGNO_S0)); - riscv_program_insert(&program64, sd(GDB_REGNO_S0, GDB_REGNO_S0, offset)); - riscv_program_csrrw(&program64, GDB_REGNO_S0, GDB_REGNO_S0, GDB_REGNO_DSCRATCH); - riscv_program_fence(&program64); - int result = riscv_program_exec(&program64, target); + // >>> r->xlen[i] = 32; + uint64_t value; + int result = register_read_abstract(target, &value, GDB_REGNO_S0, 64); if (result == ERROR_OK) { - r->debug_buffer_addr[i] = - (dmi_read(target, DMI_PROGBUF0 + (8 + offset) / 4) << 32) - + dmi_read(target, DMI_PROGBUF0 + (4 + offset) / 4) - - 4; r->xlen[i] = 64; } else { - riscv_set_register(target, GDB_REGNO_S0, s0); + r->xlen[i] = 32; } /* Display this as early as possible to help people who are using * really slow simulators. */ - LOG_DEBUG(" hart %d: XLEN=%d, program buffer at 0x%" PRIx64, i, - r->xlen[i], r->debug_buffer_addr[i]); - - if (riscv_program_gah(&program64, r->debug_buffer_addr[i])) { - LOG_ERROR("This implementation will not work with hart %d with debug_buffer_addr of 0x%lx", i, - (long)r->debug_buffer_addr[i]); - abort(); - } - - /* Check to see if we can use the data words as an extended - * program buffer or not. */ - if (r->debug_buffer_addr[i] + (4 * r->debug_buffer_size[i]) == riscv013_data_addr(target)) { - r->debug_buffer_size[i] += riscv013_data_size(target); - LOG_DEBUG("extending the debug buffer using data words, total size %d", r->debug_buffer_size[i]); - } + LOG_DEBUG(" hart %d: XLEN=%d", i, r->xlen[i]); } /* Then we check the number of triggers availiable to each hart. */ @@ -1172,8 +1136,7 @@ static int examine(struct target *target) riscv_count_harts(target)); for (int i = 0; i < riscv_count_harts(target); ++i) { if (riscv_hart_enabled(target, i)) { - LOG_INFO(" hart %d: XLEN=%d, program buffer at 0x%" PRIx64 - ", %d triggers", i, r->xlen[i], r->debug_buffer_addr[i], + LOG_INFO(" hart %d: XLEN=%d, %d triggers", i, r->xlen[i], r->trigger_count[i]); } else { LOG_INFO(" hart %d: currently disabled", i); @@ -1296,6 +1259,7 @@ static int deassert_reset(struct target *target) return ERROR_OK; } +#if 0 static void write_to_buf(uint8_t *buffer, uint64_t value, unsigned size) { switch (size) { @@ -1316,6 +1280,7 @@ static void write_to_buf(uint8_t *buffer, uint64_t value, unsigned size) assert(false); } } +#endif /** * Read the requested memory, taking care to execute every read exactly once, @@ -1324,7 +1289,7 @@ static void write_to_buf(uint8_t *buffer, uint64_t value, unsigned size) static int read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { - RISCV013_INFO(info); + //RISCV013_INFO(info); LOG_DEBUG("reading %d words of %d bytes from 0x%" TARGET_PRIxADDR, count, size, address); @@ -1342,6 +1307,8 @@ static int read_memory(struct target *target, target_addr_t address, struct riscv_program program; riscv_program_init(&program, target); + assert(0); +#if 0 riscv_addr_t r_data = riscv_program_alloc_w(&program); riscv_addr_t r_addr = riscv_program_alloc_x(&program); riscv_program_fence(&program); @@ -1496,6 +1463,7 @@ static int read_memory(struct target *target, target_addr_t address, riscv_addr_t addr = cur_addr - size; write_to_buf(buffer + addr - address, value, size); LOG_DEBUG("M[0x%" TARGET_PRIxADDR "] reads 0x%08x", addr, value); +#endif riscv_set_register(target, GDB_REGNO_S0, s0); riscv_set_register(target, GDB_REGNO_S1, s1); @@ -1505,7 +1473,7 @@ static int read_memory(struct target *target, target_addr_t address, static int write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { - RISCV013_INFO(info); + //RISCV013_INFO(info); LOG_DEBUG("writing %d words of %d bytes to 0x%08lx", count, size, (long)address); @@ -1522,6 +1490,8 @@ static int write_memory(struct target *target, target_addr_t address, struct riscv_program program; riscv_program_init(&program, target); + assert(0); +#if 0 riscv_addr_t r_data = riscv_program_alloc_w(&program); riscv_addr_t r_addr = riscv_program_alloc_x(&program); riscv_program_fence(&program); @@ -1682,6 +1652,7 @@ static int write_memory(struct target *target, target_addr_t address, } riscv013_set_autoexec(target, d_data, 0); +#endif riscv_set_register(target, GDB_REGNO_S0, s0); riscv_set_register(target, GDB_REGNO_S1, s1); return ERROR_OK; @@ -1992,13 +1963,16 @@ static void riscv013_step_or_resume_current_hart(struct target *target, bool ste abort(); } +#if 0 riscv_addr_t riscv013_progbuf_addr(struct target *target) { RISCV013_INFO(info); assert(info->progbuf_addr != -1); return info->progbuf_addr; } +#endif +#if 0 riscv_addr_t riscv013_data_size(struct target *target) { RISCV013_INFO(info); @@ -2008,7 +1982,9 @@ riscv_addr_t riscv013_data_size(struct target *target) } return info->data_size; } +#endif +#if 0 riscv_addr_t riscv013_data_addr(struct target *target) { RISCV013_INFO(info); @@ -2018,7 +1994,9 @@ riscv_addr_t riscv013_data_addr(struct target *target) } return info->data_addr; } +#endif +#if 0 void riscv013_set_autoexec(struct target *target, unsigned index, bool enabled) { RISCV013_INFO(info); @@ -2040,7 +2018,9 @@ void riscv013_set_autoexec(struct target *target, unsigned index, bool enabled) dmi_write(target, DMI_ABSTRACTAUTO, aa); } } +#endif +#if 0 int riscv013_debug_buffer_register(struct target *target, riscv_addr_t addr) { if (addr >= riscv013_data_addr(target)) @@ -2069,3 +2049,4 @@ void riscv013_clear_abstract_error(struct target *target) // Clear the error status. dmi_write(target, DMI_ABSTRACTCS, abstractcs & DMI_ABSTRACTCS_CMDERR); } +#endif diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index a8fc4378c..80ecfff77 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -1235,7 +1235,6 @@ void riscv_info_init(struct target *target, riscv_info_t *r) for (size_t h = 0; h < RISCV_MAX_HARTS; ++h) { r->xlen[h] = -1; - r->debug_buffer_addr[h] = -1; for (size_t e = 0; e < RISCV_MAX_REGISTERS; ++e) r->valid_saved_registers[h][e] = false; @@ -1483,14 +1482,6 @@ size_t riscv_debug_buffer_size(struct target *target) return r->debug_buffer_size[riscv_current_hartid(target)]; } -riscv_addr_t riscv_debug_buffer_addr(struct target *target) -{ - RISCV_INFO(r); - riscv_addr_t out = r->debug_buffer_addr[riscv_current_hartid(target)]; - assert((out & 3) == 0); - return out; -} - int riscv_debug_buffer_enter(struct target *target, struct riscv_program *program) { RISCV_INFO(r); diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h index 1197cbfbc..192d5c9fa 100644 --- a/src/target/riscv/riscv.h +++ b/src/target/riscv/riscv.h @@ -72,9 +72,6 @@ typedef struct { * target controls, while otherwise only a single hart is controlled. */ int trigger_unique_id[RISCV_MAX_HWBPS]; - /* The address of the debug RAM buffer. */ - riscv_addr_t debug_buffer_addr[RISCV_MAX_HARTS]; - /* The number of entries in the debug buffer. */ int debug_buffer_size[RISCV_MAX_HARTS]; @@ -213,7 +210,6 @@ int riscv_count_triggers_of_hart(struct target *target, int hartid); /* These helper functions let the generic program interface get target-specific * information. */ size_t riscv_debug_buffer_size(struct target *target); -riscv_addr_t riscv_debug_buffer_addr(struct target *target); int riscv_debug_buffer_enter(struct target *target, struct riscv_program *program); int riscv_debug_buffer_leave(struct target *target, struct riscv_program *program); From e7bb815e87ff36e58ef4e5a5b8d7cc3e4518ec23 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Thu, 12 Oct 2017 14:38:52 -0700 Subject: [PATCH 03/20] Register read/write might be working. Change-Id: I6c51d6157dde56d8cd666b4d30ec7bbc7a4bef9f --- src/target/riscv/program.c | 3 +- src/target/riscv/riscv-013.c | 136 +++++++++++++++++------------------ 2 files changed, 67 insertions(+), 72 deletions(-) diff --git a/src/target/riscv/program.c b/src/target/riscv/program.c index 2fc80419b..36e3f3910 100644 --- a/src/target/riscv/program.c +++ b/src/target/riscv/program.c @@ -40,6 +40,7 @@ int riscv_program_init(struct riscv_program *p, struct target *target) return ERROR_OK; } +/** Add ebreak and execute the program. */ int riscv_program_exec(struct riscv_program *p, struct target *t) { keep_alive(); @@ -258,7 +259,7 @@ int riscv_program_sb(struct riscv_program *p, enum gdb_regno d, riscv_addr_t add int riscv_program_csrr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno csr) { - assert(csr >= GDB_REGNO_CSR0); + assert(csr >= GDB_REGNO_CSR0 && csr <= GDB_REGNO_CSR4095); return riscv_program_insert(p, csrrs(d, GDB_REGNO_X0, csr - GDB_REGNO_CSR0)); } diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 483c5237b..0ff104d97 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -37,7 +37,7 @@ static void riscv013_step_or_resume_current_hart(struct target *target, bool ste //static void riscv013_set_autoexec(struct target *target, unsigned index, //bool enabled); //static int riscv013_debug_buffer_register(struct target *target, riscv_addr_t addr); -//static void riscv013_clear_abstract_error(struct target *target); +static void riscv013_clear_abstract_error(struct target *target); /* Implementations of the functions in riscv_info_t. */ static riscv_reg_t riscv013_get_register(struct target *target, int hartid, int regid); @@ -62,6 +62,7 @@ static void riscv013_fill_dmi_write_u64(struct target *target, char *buf, int a, static void riscv013_fill_dmi_read_u64(struct target *target, char *buf, int a); static int riscv013_dmi_write_u64_bits(struct target *target); static void riscv013_fill_dmi_nop_u64(struct target *target, char *buf); +static int register_read_direct(struct target *target, uint64_t *value, uint32_t number); /** * Since almost everything can be accomplish by scanning the dbus register, all @@ -771,21 +772,21 @@ static int register_write_direct(struct target *target, unsigned number, riscv_program_init(&program, target); - assert(0); -#if 0 - riscv_addr_t input = riscv_program_alloc_d(&program); - riscv_program_write_ram(&program, input + 4, value >> 32); - riscv_program_write_ram(&program, input, value); + uint64_t s0; + if (register_read_direct(target, &s0, GDB_REGNO_S0) != ERROR_OK) + return ERROR_FAIL; - assert(GDB_REGNO_XPR0 == 0); - if (number <= GDB_REGNO_XPR31) { - riscv_program_lx(&program, number, input); - } else if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { - riscv_program_flx(&program, number, input); + if (register_write_direct(target, GDB_REGNO_S0, value) != ERROR_OK) + return ERROR_FAIL; + + if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { + if (supports_extension(target, 'D') && riscv_xlen(target) >= 64) { + riscv_program_insert(&program, fmv_x_d(S0, number - GDB_REGNO_FPR0)); + } else { + riscv_program_insert(&program, fmv_x_s(S0, number - GDB_REGNO_FPR0)); + } } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) { - enum gdb_regno temp = riscv_program_gettemp(&program); - riscv_program_lx(&program, temp, input); - riscv_program_csrw(&program, temp, number); + riscv_program_csrw(&program, S0, number); } else { LOG_ERROR("Unsupported register (enum gdb_regno)(%d)", number); abort(); @@ -797,8 +798,11 @@ static int register_write_direct(struct target *target, unsigned number, return ERROR_FAIL; } + // Restore S0. + if (register_write_direct(target, GDB_REGNO_S0, s0) != ERROR_OK) + return ERROR_FAIL; + return ERROR_OK; -#endif } /** Actually read registers from the target right now. */ @@ -810,7 +814,6 @@ static int register_read_direct(struct target *target, uint64_t *value, uint32_t if (result != ERROR_OK) { struct riscv_program program; riscv_program_init(&program, target); - assert(0); assert(number != GDB_REGNO_S0); uint64_t s0; @@ -818,43 +821,34 @@ static int register_read_direct(struct target *target, uint64_t *value, uint32_t return ERROR_FAIL; // Write program to move data into s0. - // Execute program. - // Read S0 - if (register_read_direct(target, value, GDB_REGNO_S0) != ERROR_OK) - return ERROR_FAIL; - // Restore S0. - if (register_write_direct(target, GDB_REGNO_S0, &s0) != ERROR_OK) - return ERROR_FAIL; -#if 0 - riscv_addr_t output = riscv_program_alloc_d(&program); - riscv_program_write_ram(&program, output + 4, 0); - riscv_program_write_ram(&program, output, 0); - - assert(GDB_REGNO_XPR0 == 0); - if (number <= GDB_REGNO_XPR31) { - riscv_program_sx(&program, number, output); - } else if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { - riscv_program_fsx(&program, number, output); + if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { + // TODO: Possibly set F in mstatus. + // TODO: Fully support D extension on RV32. + if (supports_extension(target, 'D') && riscv_xlen(target) >= 64) { + riscv_program_insert(&program, fmv_d_x(number - GDB_REGNO_FPR0, S0)); + } else { + riscv_program_insert(&program, fmv_s_x(number - GDB_REGNO_FPR0, S0)); + } } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) { - LOG_DEBUG("reading CSR index=0x%03x", number - GDB_REGNO_CSR0); - enum gdb_regno temp = riscv_program_gettemp(&program); - riscv_program_csrr(&program, temp, number); - riscv_program_sx(&program, temp, output); + riscv_program_csrr(&program, S0, number); } else { LOG_ERROR("Unsupported register (enum gdb_regno)(%d)", number); abort(); } + // Execute program. int exec_out = riscv_program_exec(&program, target); if (exec_out != ERROR_OK) { riscv013_clear_abstract_error(target); return ERROR_FAIL; } - *value = 0; - *value |= ((uint64_t)(riscv_program_read_ram(&program, output + 4))) << 32; - *value |= riscv_program_read_ram(&program, output); -#endif + // Read S0 + if (register_read_direct(target, value, GDB_REGNO_S0) != ERROR_OK) + return ERROR_FAIL; + // Restore S0. + if (register_write_direct(target, GDB_REGNO_S0, s0) != ERROR_OK) + return ERROR_FAIL; } LOG_DEBUG("[%d] reg[0x%x] = 0x%" PRIx64, riscv_current_hartid(target), @@ -1539,14 +1533,14 @@ static int write_memory(struct target *target, target_addr_t address, } switch (riscv_xlen(target)) { - case 64: - riscv_program_write_ram(&program, r_addr + 4, (uint64_t)address >> 32); - case 32: - riscv_program_write_ram(&program, r_addr, address); - break; - default: - LOG_ERROR("unknown XLEN %d", riscv_xlen(target)); - return ERROR_FAIL; + case 64: + riscv_program_write_ram(&program, r_addr + 4, (uint64_t)address >> 32); + case 32: + riscv_program_write_ram(&program, r_addr, address); + break; + default: + LOG_ERROR("unknown XLEN %d", riscv_xlen(target)); + return ERROR_FAIL; } riscv_program_write_ram(&program, r_data, value); @@ -1582,9 +1576,9 @@ static int write_memory(struct target *target, target_addr_t address, riscv_addr_t start = (cur_addr - address) / size; assert (cur_addr > address); struct riscv_batch *batch = riscv_batch_alloc( - target, - 32, - info->dmi_busy_delay + info->ac_busy_delay); + target, + 32, + info->dmi_busy_delay + info->ac_busy_delay); for (riscv_addr_t i = start; i < count; ++i) { riscv_addr_t offset = size*i; @@ -1613,9 +1607,9 @@ static int write_memory(struct target *target, target_addr_t address, LOG_DEBUG("M[0x%08lx] writes 0x%08x", (long)t_addr, value); riscv_batch_add_dmi_write( - batch, - riscv013_debug_buffer_register(target, r_data), - value); + batch, + riscv013_debug_buffer_register(target, r_data), + value); if (riscv_batch_full(batch)) break; } @@ -1633,21 +1627,21 @@ static int write_memory(struct target *target, target_addr_t address, abstractcs = dmi_read(target, DMI_ABSTRACTCS); info->cmderr = get_field(abstractcs, DMI_ABSTRACTCS_CMDERR); switch (info->cmderr) { - case CMDERR_NONE: - LOG_DEBUG("successful (partial?) memory write"); - break; - case CMDERR_BUSY: - LOG_DEBUG("memory write resulted in busy response"); - riscv013_clear_abstract_error(target); - increase_ac_busy_delay(target); - break; - default: - LOG_ERROR("error when writing memory, abstractcs=0x%08lx", (long)abstractcs); - riscv013_set_autoexec(target, d_data, 0); - riscv013_clear_abstract_error(target); - riscv_set_register(target, GDB_REGNO_S0, s0); - riscv_set_register(target, GDB_REGNO_S1, s1); - return ERROR_FAIL; + case CMDERR_NONE: + LOG_DEBUG("successful (partial?) memory write"); + break; + case CMDERR_BUSY: + LOG_DEBUG("memory write resulted in busy response"); + riscv013_clear_abstract_error(target); + increase_ac_busy_delay(target); + break; + default: + LOG_ERROR("error when writing memory, abstractcs=0x%08lx", (long)abstractcs); + riscv013_set_autoexec(target, d_data, 0); + riscv013_clear_abstract_error(target); + riscv_set_register(target, GDB_REGNO_S0, s0); + riscv_set_register(target, GDB_REGNO_S1, s1); + return ERROR_FAIL; } } @@ -2028,6 +2022,7 @@ int riscv013_debug_buffer_register(struct target *target, riscv_addr_t addr) else return DMI_PROGBUF0 + (addr - riscv013_progbuf_addr(target)) / 4; } +#endif void riscv013_clear_abstract_error(struct target *target) { @@ -2049,4 +2044,3 @@ void riscv013_clear_abstract_error(struct target *target) // Clear the error status. dmi_write(target, DMI_ABSTRACTCS, abstractcs & DMI_ABSTRACTCS_CMDERR); } -#endif From 7ec7bc32fe01f632bdfa02649d92cdad9019e28e Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Fri, 13 Oct 2017 12:50:02 -0700 Subject: [PATCH 04/20] At least some memory writes work. Change-Id: I6fcf261341f10ec34df01bb844744439d02471a8 --- src/target/riscv/program.c | 23 ++-- src/target/riscv/program.h | 3 + src/target/riscv/riscv-013.c | 196 ++++++++++++++--------------------- 3 files changed, 93 insertions(+), 129 deletions(-) diff --git a/src/target/riscv/program.c b/src/target/riscv/program.c index 36e3f3910..8981ea33f 100644 --- a/src/target/riscv/program.c +++ b/src/target/riscv/program.c @@ -40,6 +40,17 @@ int riscv_program_init(struct riscv_program *p, struct target *target) return ERROR_OK; } +int riscv_program_write(struct riscv_program *program) +{ + for (unsigned i = 0; i < riscv_debug_buffer_size(program->target); ++i) { + LOG_DEBUG("%p: debug_buffer[%02x] = DASM(0x%08x)", program, i, program->debug_buffer[i]); + if (riscv_write_debug_buffer(program->target, i, + program->debug_buffer[i]) != ERROR_OK) + return ERROR_FAIL; + } + return ERROR_OK; +} + /** Add ebreak and execute the program. */ int riscv_program_exec(struct riscv_program *p, struct target *t) { @@ -74,16 +85,8 @@ int riscv_program_exec(struct riscv_program *p, struct target *t) return ERROR_FAIL; } - for (unsigned i = 0; i < riscv_debug_buffer_size(p->target); ++i) { - if (i < p->instruction_count) { - LOG_DEBUG("%p: debug_buffer[%02x] = DASM(0x%08x)", p, i, p->debug_buffer[i]); - riscv_write_debug_buffer(t, i, p->debug_buffer[i]); - } - if (i >= riscv_debug_buffer_size(p->target) - p->data_count) { - LOG_DEBUG("%p: debug_buffer[%02x] = 0x%08x", p, i, p->debug_buffer[i]); - riscv_write_debug_buffer(t, i, p->debug_buffer[i]); - } - } + if (riscv_program_write(p) != ERROR_OK) + return ERROR_FAIL; if (riscv_execute_debug_buffer(t) != ERROR_OK) { LOG_ERROR("Unable to execute program %p", p); diff --git a/src/target/riscv/program.h b/src/target/riscv/program.h index 82e9b5e99..e5f6c29e2 100644 --- a/src/target/riscv/program.h +++ b/src/target/riscv/program.h @@ -40,6 +40,9 @@ struct riscv_program { /* Initializes a program with the header. */ int riscv_program_init(struct riscv_program *p, struct target *t); +/* Write the program to the program buffer. */ +int riscv_program_write(struct riscv_program *program); + /* Executes a program, returning 0 if the program successfully executed. Note * that this may cause registers to be saved or restored, which could result to * calls to things like riscv_save_register which itself could require a diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 0ff104d97..ec921dcff 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -34,8 +34,6 @@ static void riscv013_step_or_resume_current_hart(struct target *target, bool ste //static riscv_addr_t riscv013_progbuf_addr(struct target *target); //static riscv_addr_t riscv013_data_size(struct target *target); //static riscv_addr_t riscv013_data_addr(struct target *target); -//static void riscv013_set_autoexec(struct target *target, unsigned index, - //bool enabled); //static int riscv013_debug_buffer_register(struct target *target, riscv_addr_t addr); static void riscv013_clear_abstract_error(struct target *target); @@ -518,7 +516,6 @@ static void dmi_write(struct target *target, uint16_t address, uint64_t value) } } -#if 0 static void increase_ac_busy_delay(struct target *target) { riscv013_info_t *info = get_info(target); @@ -527,7 +524,6 @@ static void increase_ac_busy_delay(struct target *target) info->dtmcontrol_idle, info->dmi_busy_delay, info->ac_busy_delay); } -#endif uint32_t abstract_register_size(unsigned width) { @@ -1467,30 +1463,26 @@ static int read_memory(struct target *target, target_addr_t address, static int write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { - //RISCV013_INFO(info); + RISCV013_INFO(info); LOG_DEBUG("writing %d words of %d bytes to 0x%08lx", count, size, (long)address); + /* + * s0 holds the next address to write to + * s1 holds the next data value to write + */ + select_dmi(target); - /* This program uses two temporary registers. A word of data and the - * associated address are stored at some location in memory. The - * program stores the word to that address and then increments the - * address. The debugger is expected to feed the memory word-by-word - * into the chip with AUTOEXEC set in order to trigger program - * execution on every word. */ - uint64_t s0 = riscv_get_register(target, GDB_REGNO_S0); - uint64_t s1 = riscv_get_register(target, GDB_REGNO_S1); + uint64_t s0, s1; + if (register_read_direct(target, &s0, GDB_REGNO_S0) != ERROR_OK) + return ERROR_FAIL; + if (register_read_direct(target, &s1, GDB_REGNO_S1) != ERROR_OK) + return ERROR_FAIL; + // Write the program (store, increment) struct riscv_program program; riscv_program_init(&program, target); - assert(0); -#if 0 - riscv_addr_t r_data = riscv_program_alloc_w(&program); - riscv_addr_t r_addr = riscv_program_alloc_x(&program); - riscv_program_fence(&program); - riscv_program_lx(&program, GDB_REGNO_S0, r_addr); - riscv_program_lw(&program, GDB_REGNO_S1, r_data); switch (size) { case 1: @@ -1508,83 +1500,35 @@ static int write_memory(struct target *target, target_addr_t address, } riscv_program_addi(&program, GDB_REGNO_S0, GDB_REGNO_S0, size); - riscv_program_sx(&program, GDB_REGNO_S0, r_addr); - /* The first round through the program's execution we use the regular - * program execution mechanism. */ - uint32_t value; - switch (size) { - case 1: - value = buffer[0]; - break; - case 2: - value = buffer[0] - | ((uint32_t) buffer[1] << 8); - break; - case 4: - value = buffer[0] - | ((uint32_t) buffer[1] << 8) - | ((uint32_t) buffer[2] << 16) - | ((uint32_t) buffer[3] << 24); - break; - default: - LOG_ERROR("unsupported access size: %d", size); - return ERROR_FAIL; - } - - switch (riscv_xlen(target)) { - case 64: - riscv_program_write_ram(&program, r_addr + 4, (uint64_t)address >> 32); - case 32: - riscv_program_write_ram(&program, r_addr, address); - break; - default: - LOG_ERROR("unknown XLEN %d", riscv_xlen(target)); - return ERROR_FAIL; - } - riscv_program_write_ram(&program, r_data, value); - - LOG_DEBUG("M[0x%08lx] writes 0x%08x", (long)address, value); - - if (riscv_program_exec(&program, target) != ERROR_OK) { - uint32_t acs = dmi_read(target, DMI_ABSTRACTCS); - LOG_ERROR("failed to execute program, abstractcs=0x%08x", acs); - riscv013_clear_abstract_error(target); - riscv_set_register(target, GDB_REGNO_S0, s0); - riscv_set_register(target, GDB_REGNO_S1, s1); - LOG_ERROR(" exiting with ERROR_FAIL"); + if (riscv_debug_buffer_leave(target, &program) != ERROR_OK) return ERROR_FAIL; - } - /* The rest of this program is designed to be fast so it reads various - * DMI registers directly. */ - int d_data = (r_data - riscv_debug_buffer_addr(target)) / 4; - int d_addr = (r_addr - riscv_debug_buffer_addr(target)) / 4; + riscv_program_write(&program); - riscv013_set_autoexec(target, d_data, 1); + if (register_write_direct(target, GDB_REGNO_S0, address) != ERROR_OK) + return ERROR_FAIL; - /* Copying memory might fail because we're going too quickly, in which - * case we need to back off a bit and try again. There's two - * termination conditions to this loop: a non-BUSY error message, or - * the data was all copied. */ - riscv_addr_t cur_addr = 0xbadbeef; + riscv_addr_t cur_addr = address; riscv_addr_t fin_addr = address + (count * size); + bool setup_needed = true; LOG_DEBUG("writing until final address 0x%016" PRIx64, fin_addr); - while ((cur_addr = riscv_read_debug_buffer_x(target, d_addr)) < fin_addr) { + while (cur_addr < fin_addr) { LOG_DEBUG("transferring burst starting at address 0x%016" PRIx64, cur_addr); - riscv_addr_t start = (cur_addr - address) / size; - assert (cur_addr > address); + struct riscv_batch *batch = riscv_batch_alloc( target, 32, info->dmi_busy_delay + info->ac_busy_delay); - for (riscv_addr_t i = start; i < count; ++i) { - riscv_addr_t offset = size*i; - riscv_addr_t t_addr = address + offset; + /* To write another word, we put it in S1 and execute the program. */ + unsigned start = (cur_addr - address) / size; + for (unsigned i = start; i < count; ++i) { + unsigned offset = size*i; const uint8_t *t_buffer = buffer + offset; + uint32_t value; switch (size) { case 1: value = t_buffer[0]; @@ -1604,14 +1548,44 @@ static int write_memory(struct target *target, target_addr_t address, return ERROR_FAIL; } - LOG_DEBUG("M[0x%08lx] writes 0x%08x", (long)t_addr, value); + LOG_DEBUG("M[0x%08" PRIx64 "] writes 0x%08x", address + offset, value); - riscv_batch_add_dmi_write( - batch, - riscv013_debug_buffer_register(target, r_data), - value); - if (riscv_batch_full(batch)) - break; + if (setup_needed) { + // Write value. + dmi_write(target, DMI_DATA0, value); + + // Write and execute command that moves value into S0 and + // executes program buffer. + uint32_t command = set_field(0, DMI_COMMAND_CMDTYPE, 0); + switch (size) { + case 32: + command = set_field(command, AC_ACCESS_REGISTER_SIZE, 2); + break; + case 64: + command = set_field(command, AC_ACCESS_REGISTER_SIZE, 3); + break; + default: + LOG_ERROR("Unsupported abstract register read size: %d", size); + return ERROR_FAIL; + } + command = set_field(command, AC_ACCESS_REGISTER_POSTEXEC, 1); + command = set_field(command, AC_ACCESS_REGISTER_TRANSFER, 1); + command = set_field(command, AC_ACCESS_REGISTER_WRITE, 1); + command = set_field(command, AC_ACCESS_REGISTER_REGNO, + 0x1000 + GDB_REGNO_S1 - GDB_REGNO_XPR0); + int result = execute_abstract_command(target, command); + if (result != ERROR_OK) + return result; + + // Turn on autoexec + dmi_write(target, DMI_ABSTRACTAUTO, + 1 << DMI_ABSTRACTAUTO_AUTOEXECDATA_OFFSET); + } else { + riscv_batch_add_dmi_write(batch, DMI_DATA0, value); + if (riscv_batch_full(batch)) + break; + } + cur_addr += size; } riscv_batch_run(batch); @@ -1619,8 +1593,7 @@ static int write_memory(struct target *target, target_addr_t address, // Note that if the scan resulted in a Busy DMI response, it // is this read to abstractcs that will cause the dmi_busy_delay - // to be incremented if necessary. The loop condition above - // catches the case where no writes went through at all. + // to be incremented if necessary. uint32_t abstractcs = dmi_read(target, DMI_ABSTRACTCS); while (get_field(abstractcs, DMI_ABSTRACTCS_BUSY)) @@ -1634,10 +1607,16 @@ static int write_memory(struct target *target, target_addr_t address, LOG_DEBUG("memory write resulted in busy response"); riscv013_clear_abstract_error(target); increase_ac_busy_delay(target); + + dmi_write(target, DMI_ABSTRACTAUTO, 0); + if (register_read_direct(target, &cur_addr, GDB_REGNO_S0) != ERROR_OK) + return ERROR_FAIL; + setup_needed = true; break; + default: LOG_ERROR("error when writing memory, abstractcs=0x%08lx", (long)abstractcs); - riscv013_set_autoexec(target, d_data, 0); + dmi_write(target, DMI_ABSTRACTAUTO, 0); riscv013_clear_abstract_error(target); riscv_set_register(target, GDB_REGNO_S0, s0); riscv_set_register(target, GDB_REGNO_S1, s1); @@ -1645,10 +1624,13 @@ static int write_memory(struct target *target, target_addr_t address, } } - riscv013_set_autoexec(target, d_data, 0); -#endif - riscv_set_register(target, GDB_REGNO_S0, s0); - riscv_set_register(target, GDB_REGNO_S1, s1); + dmi_write(target, DMI_ABSTRACTAUTO, 0); + + if (register_write_direct(target, GDB_REGNO_S1, s1) != ERROR_OK) + return ERROR_FAIL; + if (register_write_direct(target, GDB_REGNO_S0, s0) != ERROR_OK) + return ERROR_FAIL; + return ERROR_OK; } @@ -1990,30 +1972,6 @@ riscv_addr_t riscv013_data_addr(struct target *target) } #endif -#if 0 -void riscv013_set_autoexec(struct target *target, unsigned index, bool enabled) -{ - RISCV013_INFO(info); - if (index >= info->progsize) { - LOG_DEBUG("setting bit %d in AUTOEXECDATA to %d", index, enabled); - uint32_t aa = dmi_read(target, DMI_ABSTRACTAUTO); - uint32_t aa_aed = get_field(aa, DMI_ABSTRACTAUTO_AUTOEXECDATA); - aa_aed &= ~(1 << (index - info->progsize)); - aa_aed |= (enabled << (index - info->progsize)); - aa = set_field(aa, DMI_ABSTRACTAUTO_AUTOEXECDATA, aa_aed); - dmi_write(target, DMI_ABSTRACTAUTO, aa); - } else { - LOG_DEBUG("setting bit %d in AUTOEXECPROGBUF to %d", index, enabled); - uint32_t aa = dmi_read(target, DMI_ABSTRACTAUTO); - uint32_t aa_aed = get_field(aa, DMI_ABSTRACTAUTO_AUTOEXECPROGBUF); - aa_aed &= ~(1 << index); - aa_aed |= (enabled << index); - aa = set_field(aa, DMI_ABSTRACTAUTO_AUTOEXECPROGBUF, aa_aed); - dmi_write(target, DMI_ABSTRACTAUTO, aa); - } -} -#endif - #if 0 int riscv013_debug_buffer_register(struct target *target, riscv_addr_t addr) { From d94b38279a10f7e9d012a225be8d78cd8e5f1e39 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Mon, 16 Oct 2017 20:38:35 -0700 Subject: [PATCH 05/20] Memtest{16,32} pass. Change-Id: I15c2a4fd2bb9a7b30762d07f3b3a74d2f477746b --- src/target/riscv/program.c | 19 +-- src/target/riscv/riscv-013.c | 303 ++++++++++++++--------------------- src/target/riscv/riscv.c | 14 -- src/target/riscv/riscv.h | 5 - 4 files changed, 125 insertions(+), 216 deletions(-) diff --git a/src/target/riscv/program.c b/src/target/riscv/program.c index 8981ea33f..7175fa344 100644 --- a/src/target/riscv/program.c +++ b/src/target/riscv/program.c @@ -32,17 +32,12 @@ int riscv_program_init(struct riscv_program *p, struct target *target) for(size_t i = 0; i < RISCV_MAX_DEBUG_BUFFER_SIZE; ++i) p->debug_buffer[i] = -1; - if (riscv_debug_buffer_enter(target, p) != ERROR_OK) { - LOG_ERROR("unable to write progam buffer enter code"); - return ERROR_FAIL; - } - return ERROR_OK; } int riscv_program_write(struct riscv_program *program) { - for (unsigned i = 0; i < riscv_debug_buffer_size(program->target); ++i) { + for (unsigned i = 0; i < program->instruction_count; ++i) { LOG_DEBUG("%p: debug_buffer[%02x] = DASM(0x%08x)", program, i, program->debug_buffer[i]); if (riscv_write_debug_buffer(program->target, i, program->debug_buffer[i]) != ERROR_OK) @@ -56,11 +51,6 @@ int riscv_program_exec(struct riscv_program *p, struct target *t) { keep_alive(); - if (riscv_debug_buffer_leave(t, p) != ERROR_OK) { - LOG_ERROR("unable to write program buffer exit code"); - return ERROR_FAIL; - } - riscv_reg_t saved_registers[GDB_REGNO_XPR31 + 1]; for (size_t i = GDB_REGNO_XPR0 + 1; i <= GDB_REGNO_XPR31; ++i) { if (p->writes_xreg[i]) { @@ -290,6 +280,11 @@ int riscv_program_fence(struct riscv_program *p) int riscv_program_ebreak(struct riscv_program *p) { + if (p->instruction_count == riscv_debug_buffer_size(p->target)) { + // TODO: Check for impebreak bit. + // There's an implicit ebreak here, so no need for us to add one. + return ERROR_OK; + } return riscv_program_insert(p, ebreak()); } @@ -441,7 +436,7 @@ int riscv_program_insert(struct riscv_program *p, riscv_insn_t i) LOG_ERROR(" instruction_count=%d", (int)p->instruction_count); LOG_ERROR(" data_count =%d", (int)p->data_count); LOG_ERROR(" buffer size =%d", (int)riscv_debug_buffer_size(p->target)); - return ERROR_FAIL; + abort(); } p->debug_buffer[p->instruction_count] = i; diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index ec921dcff..a34bda07b 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -49,8 +49,6 @@ static void riscv013_on_step(struct target *target); static void riscv013_on_resume(struct target *target); static bool riscv013_is_halted(struct target *target); static enum riscv_halt_reason riscv013_halt_reason(struct target *target); -static void riscv013_debug_buffer_enter(struct target *target, struct riscv_program *p); -static void riscv013_debug_buffer_leave(struct target *target, struct riscv_program *p); static void riscv013_write_debug_buffer(struct target *target, unsigned index, riscv_insn_t d); static riscv_insn_t riscv013_read_debug_buffer(struct target *target, unsigned @@ -637,11 +635,12 @@ static int write_abstract_arg(struct target *target, unsigned index, return ERROR_OK; } -static int register_read_abstract(struct target *target, uint64_t *value, - uint32_t number, unsigned size) +/** + * @size in bits + */ +static uint32_t access_register_command(uint32_t number, unsigned size, + uint32_t flags) { - RISCV013_INFO(r); - uint32_t command = set_field(0, DMI_COMMAND_CMDTYPE, 0); switch (size) { case 32: @@ -651,38 +650,50 @@ static int register_read_abstract(struct target *target, uint64_t *value, command = set_field(command, AC_ACCESS_REGISTER_SIZE, 3); break; default: - LOG_ERROR("Unsupported abstract register read size: %d", size); - return ERROR_FAIL; + assert(0); } - command = set_field(command, AC_ACCESS_REGISTER_POSTEXEC, 0); - command = set_field(command, AC_ACCESS_REGISTER_TRANSFER, 1); - command = set_field(command, AC_ACCESS_REGISTER_WRITE, 0); if (number <= GDB_REGNO_XPR31) { command = set_field(command, AC_ACCESS_REGISTER_REGNO, 0x1000 + number - GDB_REGNO_XPR0); } else if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { - if (!r->abstract_read_fpr_supported) - return ERROR_FAIL; command = set_field(command, AC_ACCESS_REGISTER_REGNO, 0x1020 + number - GDB_REGNO_FPR0); } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) { - if (!r->abstract_read_csr_supported) - return ERROR_FAIL; command = set_field(command, AC_ACCESS_REGISTER_REGNO, number - GDB_REGNO_CSR0); } else { - return ERROR_FAIL; + assert(0); } + command |= flags; + + return command; +} + +static int register_read_abstract(struct target *target, uint64_t *value, + uint32_t number, unsigned size) +{ + RISCV013_INFO(info); + + if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31 && + !info->abstract_read_fpr_supported) + return ERROR_FAIL; + if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095 && + !info->abstract_read_csr_supported) + return ERROR_FAIL; + + uint32_t command = access_register_command(number, size, + AC_ACCESS_REGISTER_TRANSFER); + int result = execute_abstract_command(target, command); if (result != ERROR_OK) { - if (r->cmderr == CMDERR_NOT_SUPPORTED) { + if (info->cmderr == CMDERR_NOT_SUPPORTED) { if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { - r->abstract_read_fpr_supported = false; + info->abstract_read_fpr_supported = false; LOG_INFO("Disabling abstract command reads from FPRs."); } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) { - r->abstract_read_csr_supported = false; + info->abstract_read_csr_supported = false; LOG_INFO("Disabling abstract command reads from CSRs."); } } @@ -699,38 +710,16 @@ static int register_write_abstract(struct target *target, uint32_t number, { RISCV013_INFO(info); - uint32_t command = set_field(0, DMI_COMMAND_CMDTYPE, 0); - switch (size) { - case 32: - command = set_field(command, AC_ACCESS_REGISTER_SIZE, 2); - break; - case 64: - command = set_field(command, AC_ACCESS_REGISTER_SIZE, 3); - break; - default: - LOG_ERROR("Unsupported abstract register read size: %d", size); - return ERROR_FAIL; - } - command = set_field(command, AC_ACCESS_REGISTER_POSTEXEC, 0); - command = set_field(command, AC_ACCESS_REGISTER_TRANSFER, 1); - command = set_field(command, AC_ACCESS_REGISTER_WRITE, 1); - - if (number <= GDB_REGNO_XPR31) { - command = set_field(command, AC_ACCESS_REGISTER_REGNO, - 0x1000 + number - GDB_REGNO_XPR0); - } else if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { - if (!info->abstract_read_fpr_supported) - return ERROR_FAIL; - command = set_field(command, AC_ACCESS_REGISTER_REGNO, - 0x1020 + number - GDB_REGNO_FPR0); - } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) { - if (!info->abstract_read_csr_supported) - return ERROR_FAIL; - command = set_field(command, AC_ACCESS_REGISTER_REGNO, - number - GDB_REGNO_CSR0); - } else { + if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31 && + !info->abstract_write_fpr_supported) return ERROR_FAIL; - } + if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095 && + !info->abstract_write_csr_supported) + return ERROR_FAIL; + + uint32_t command = access_register_command(number, size, + AC_ACCESS_REGISTER_TRANSFER | + AC_ACCESS_REGISTER_WRITE); if (write_abstract_arg(target, 0, value) != ERROR_OK) { return ERROR_FAIL; @@ -905,8 +894,6 @@ static int init_target(struct command_context *cmd_ctx, generic_info->on_resume = &riscv013_on_resume; generic_info->on_step = &riscv013_on_step; generic_info->halt_reason = &riscv013_halt_reason; - generic_info->debug_buffer_enter = &riscv013_debug_buffer_enter; - generic_info->debug_buffer_leave = &riscv013_debug_buffer_leave; generic_info->read_debug_buffer = &riscv013_read_debug_buffer; generic_info->write_debug_buffer = &riscv013_write_debug_buffer; generic_info->execute_debug_buffer = &riscv013_execute_debug_buffer; @@ -1249,7 +1236,9 @@ static int deassert_reset(struct target *target) return ERROR_OK; } -#if 0 +/** + * @size in bytes + */ static void write_to_buf(uint8_t *buffer, uint64_t value, unsigned size) { switch (size) { @@ -1270,7 +1259,6 @@ static void write_to_buf(uint8_t *buffer, uint64_t value, unsigned size) assert(false); } } -#endif /** * Read the requested memory, taking care to execute every read exactly once, @@ -1279,30 +1267,27 @@ static void write_to_buf(uint8_t *buffer, uint64_t value, unsigned size) static int read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { - //RISCV013_INFO(info); + RISCV013_INFO(info); LOG_DEBUG("reading %d words of %d bytes from 0x%" TARGET_PRIxADDR, count, size, address); select_dmi(target); - /* This program uses two temporary registers. A word of data and the - * associated address are stored at some location in memory. The - * program loads the word from that address and then increments the - * address. The debugger is expected to pull the memory word-by-word - * from the chip with AUTOEXEC set in order to trigger program - * execution on every word. */ - uint64_t s0 = riscv_get_register(target, GDB_REGNO_S0); - uint64_t s1 = riscv_get_register(target, GDB_REGNO_S1); + /* s0 holds the next address to write to + * s1 holds the next data value to write + */ + uint64_t s0, s1; + if (register_read_direct(target, &s0, GDB_REGNO_S0) != ERROR_OK) + return ERROR_FAIL; + if (register_read_direct(target, &s1, GDB_REGNO_S1) != ERROR_OK) + return ERROR_FAIL; + // Write the program (load, increment) struct riscv_program program; riscv_program_init(&program, target); - assert(0); -#if 0 - riscv_addr_t r_data = riscv_program_alloc_w(&program); - riscv_addr_t r_addr = riscv_program_alloc_x(&program); - riscv_program_fence(&program); - riscv_program_lx(&program, GDB_REGNO_S0, r_addr); + + // TODO: riscv_program_fence(&program); switch (size) { case 1: riscv_program_lbr(&program, GDB_REGNO_S1, GDB_REGNO_S0, 0); @@ -1318,70 +1303,43 @@ static int read_memory(struct target *target, target_addr_t address, return ERROR_FAIL; } riscv_program_addi(&program, GDB_REGNO_S0, GDB_REGNO_S0, size); - riscv_program_sw(&program, GDB_REGNO_S1, r_data); - riscv_program_sx(&program, GDB_REGNO_S0, r_addr); - /* The first round through the program's execution we use the regular - * program execution mechanism. */ - switch (riscv_xlen(target)) { - case 64: - riscv_program_write_ram(&program, r_addr + 4, ((riscv_addr_t) address) >> 32); - case 32: - riscv_program_write_ram(&program, r_addr, (riscv_addr_t) address); - break; - default: - LOG_ERROR("unknown XLEN %d", riscv_xlen(target)); + if (riscv_program_ebreak(&program) != ERROR_OK) return ERROR_FAIL; - } + riscv_program_write(&program); - if (riscv_program_exec(&program, target) != ERROR_OK) { - uint32_t acs = dmi_read(target, DMI_ABSTRACTCS); - LOG_ERROR("failed to execute program, abstractcs=0x%08x", acs); - riscv013_clear_abstract_error(target); - riscv_set_register(target, GDB_REGNO_S0, s0); - riscv_set_register(target, GDB_REGNO_S1, s1); - LOG_ERROR(" exiting with ERROR_FAIL"); + // Write address to S0, and execute buffer. + if (register_write_direct(target, GDB_REGNO_S0, address) != ERROR_OK) + return ERROR_FAIL; + if (execute_abstract_command(target, + access_register_command(GDB_REGNO_S1, riscv_xlen(target), + AC_ACCESS_REGISTER_TRANSFER | + AC_ACCESS_REGISTER_POSTEXEC)) != ERROR_OK) return ERROR_FAIL; - } - // Program has been executed once. d_addr contains address+size, and d_data - // contains *address. - - /* The rest of this program is designed to be fast so it reads various - * DMI registers directly. */ - int d_data = (r_data - riscv_debug_buffer_addr(target)) / 4; - int d_addr = (r_addr - riscv_debug_buffer_addr(target)) / 4; - - riscv013_set_autoexec(target, d_data, 1); + dmi_write(target, DMI_ABSTRACTAUTO, + 1 << DMI_ABSTRACTAUTO_AUTOEXECDATA_OFFSET); /* Copying memory might fail because we're going too quickly, in which - * case we need to back off a bit and try again. There's two - * termination conditions to this loop: a non-BUSY error message, or - * the data was all copied. */ - riscv_addr_t cur_addr = riscv_read_debug_buffer_x(target, d_addr); + * case we need to back off a bit and try again. */ + riscv_addr_t cur_addr = address; riscv_addr_t fin_addr = address + (count * size); LOG_DEBUG("reading until final address 0x%" PRIx64, fin_addr); - while (cur_addr < fin_addr) { + while (cur_addr < fin_addr - size) { // Invariant: - // d_data contains *addr - // d_addr contains addr + size + // s0 contains the next address to read + // s1 contains the data read at the previous address unsigned start = (cur_addr - address) / size; LOG_DEBUG("creating burst to read address 0x%" TARGET_PRIxADDR " up to 0x%" TARGET_PRIxADDR "; start=0x%d", cur_addr, fin_addr, start); assert(cur_addr >= address && cur_addr < fin_addr); - struct riscv_batch *batch = riscv_batch_alloc( - target, - 32, - info->dmi_busy_delay + info->ac_busy_delay); + 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 = cur_addr; addr < fin_addr; addr += size) { - size_t const index = - riscv_batch_add_dmi_read( - batch, - riscv013_debug_buffer_register(target, r_data)); - assert(index == reads); + for (riscv_addr_t addr = cur_addr; addr < fin_addr - size; addr += size) { + riscv_batch_add_dmi_read(batch, DMI_DATA0); reads++; if (riscv_batch_full(batch)) @@ -1397,37 +1355,37 @@ static int read_memory(struct target *target, target_addr_t address, abstractcs = dmi_read(target, DMI_ABSTRACTCS); info->cmderr = get_field(abstractcs, DMI_ABSTRACTCS_CMDERR); + riscv_addr_t next_addr; switch (info->cmderr) { - case CMDERR_NONE: - LOG_DEBUG("successful (partial?) memory read"); - break; - case CMDERR_BUSY: - LOG_DEBUG("memory read resulted in busy response"); - increase_ac_busy_delay(target); - riscv013_clear_abstract_error(target); - break; - default: - LOG_ERROR("error when reading memory, abstractcs=0x%08lx", (long)abstractcs); - riscv013_set_autoexec(target, d_data, 0); - riscv_set_register(target, GDB_REGNO_S0, s0); - riscv_set_register(target, GDB_REGNO_S1, s1); - riscv013_clear_abstract_error(target); - riscv_batch_free(batch); - return ERROR_FAIL; - } + case CMDERR_NONE: + LOG_DEBUG("successful (partial?) memory read"); + next_addr = cur_addr + reads * size; + break; + case CMDERR_BUSY: + LOG_DEBUG("memory read resulted in busy response"); + increase_ac_busy_delay(target); + riscv013_clear_abstract_error(target); - // Figure out how far we managed to read. - riscv_addr_t next_addr = riscv_read_debug_buffer_x(target, d_addr); - LOG_DEBUG("Batch read [0x%" TARGET_PRIxADDR ", 0x%" TARGET_PRIxADDR - "); reads=%d", cur_addr, next_addr, (unsigned) reads); - assert(next_addr >= address && next_addr <= fin_addr); - assert(info->cmderr != CMDERR_NONE || - next_addr == cur_addr + reads * size); + dmi_write(target, DMI_ABSTRACTAUTO, 0); + if (register_read_direct(target, &next_addr, GDB_REGNO_S0) != ERROR_OK) + return ERROR_FAIL; + next_addr -= size; + dmi_write(target, DMI_ABSTRACTAUTO, + 1 << DMI_ABSTRACTAUTO_AUTOEXECDATA_OFFSET); + break; + default: + LOG_ERROR("error when reading memory, abstractcs=0x%08lx", (long)abstractcs); + dmi_write(target, DMI_ABSTRACTAUTO, 0); + riscv_set_register(target, GDB_REGNO_S0, s0); + riscv_set_register(target, GDB_REGNO_S1, s1); + riscv013_clear_abstract_error(target); + riscv_batch_free(batch); + return ERROR_FAIL; + } // Now read whatever we got out of the batch. unsigned rereads = 0; - for (riscv_addr_t addr = cur_addr - size; addr < next_addr - size; - addr += size) { + for (riscv_addr_t addr = cur_addr; addr < next_addr; addr += size) { riscv_addr_t offset = addr - address; uint64_t dmi_out = riscv_batch_get_dmi_read(batch, rereads); @@ -1443,17 +1401,14 @@ static int read_memory(struct target *target, target_addr_t address, cur_addr = next_addr; } - riscv013_set_autoexec(target, d_data, 0); + dmi_write(target, DMI_ABSTRACTAUTO, 0); // Read the last word. - - // Access debug buffer without executing a program. This - // address logic was taken from program.c. - uint32_t value = riscv013_read_debug_buffer(target, d_data); - riscv_addr_t addr = cur_addr - size; - write_to_buf(buffer + addr - address, value, size); - LOG_DEBUG("M[0x%" TARGET_PRIxADDR "] reads 0x%08x", addr, value); -#endif + uint64_t value; + if (register_read_direct(target, &value, GDB_REGNO_S1) != ERROR_OK) + return ERROR_FAIL; + write_to_buf(buffer + cur_addr - address, value, size); + LOG_DEBUG("M[0x%" TARGET_PRIxADDR "] reads 0x%" PRIx64, cur_addr, value); riscv_set_register(target, GDB_REGNO_S0, s0); riscv_set_register(target, GDB_REGNO_S1, s1); @@ -1467,13 +1422,12 @@ static int write_memory(struct target *target, target_addr_t address, LOG_DEBUG("writing %d words of %d bytes to 0x%08lx", count, size, (long)address); - /* - * s0 holds the next address to write to + select_dmi(target); + + /* s0 holds the next address to write to * s1 holds the next data value to write */ - select_dmi(target); - uint64_t s0, s1; if (register_read_direct(target, &s0, GDB_REGNO_S0) != ERROR_OK) return ERROR_FAIL; @@ -1501,14 +1455,10 @@ static int write_memory(struct target *target, target_addr_t address, riscv_program_addi(&program, GDB_REGNO_S0, GDB_REGNO_S0, size); - if (riscv_debug_buffer_leave(target, &program) != ERROR_OK) + if (riscv_program_ebreak(&program) != ERROR_OK) return ERROR_FAIL; - riscv_program_write(&program); - if (register_write_direct(target, GDB_REGNO_S0, address) != ERROR_OK) - return ERROR_FAIL; - riscv_addr_t cur_addr = address; riscv_addr_t fin_addr = address + (count * size); bool setup_needed = true; @@ -1551,28 +1501,19 @@ static int write_memory(struct target *target, target_addr_t address, LOG_DEBUG("M[0x%08" PRIx64 "] writes 0x%08x", address + offset, value); if (setup_needed) { + if (register_write_direct(target, GDB_REGNO_S0, + address + offset) != ERROR_OK) + return ERROR_FAIL; + // Write value. dmi_write(target, DMI_DATA0, value); // Write and execute command that moves value into S0 and // executes program buffer. - uint32_t command = set_field(0, DMI_COMMAND_CMDTYPE, 0); - switch (size) { - case 32: - command = set_field(command, AC_ACCESS_REGISTER_SIZE, 2); - break; - case 64: - command = set_field(command, AC_ACCESS_REGISTER_SIZE, 3); - break; - default: - LOG_ERROR("Unsupported abstract register read size: %d", size); - return ERROR_FAIL; - } - command = set_field(command, AC_ACCESS_REGISTER_POSTEXEC, 1); - command = set_field(command, AC_ACCESS_REGISTER_TRANSFER, 1); - command = set_field(command, AC_ACCESS_REGISTER_WRITE, 1); - command = set_field(command, AC_ACCESS_REGISTER_REGNO, - 0x1000 + GDB_REGNO_S1 - GDB_REGNO_XPR0); + uint32_t command = access_register_command(GDB_REGNO_S1, 32, + AC_ACCESS_REGISTER_POSTEXEC | + AC_ACCESS_REGISTER_TRANSFER | + AC_ACCESS_REGISTER_WRITE); int result = execute_abstract_command(target, command); if (result != ERROR_OK) return result; @@ -1810,14 +1751,6 @@ static enum riscv_halt_reason riscv013_halt_reason(struct target *target) abort(); } -void riscv013_debug_buffer_enter(struct target *target, struct riscv_program *program) -{ -} - -void riscv013_debug_buffer_leave(struct target *target, struct riscv_program *program) -{ -} - void riscv013_write_debug_buffer(struct target *target, unsigned index, riscv_insn_t data) { RISCV013_INFO(info); diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 80ecfff77..820094da3 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -1482,20 +1482,6 @@ size_t riscv_debug_buffer_size(struct target *target) return r->debug_buffer_size[riscv_current_hartid(target)]; } -int riscv_debug_buffer_enter(struct target *target, struct riscv_program *program) -{ - RISCV_INFO(r); - r->debug_buffer_enter(target, program); - return ERROR_OK; -} - -int riscv_debug_buffer_leave(struct target *target, struct riscv_program *program) -{ - RISCV_INFO(r); - r->debug_buffer_leave(target, program); - return ERROR_OK; -} - int riscv_write_debug_buffer(struct target *target, int index, riscv_insn_t insn) { RISCV_INFO(r); diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h index 192d5c9fa..e7b0ea2db 100644 --- a/src/target/riscv/riscv.h +++ b/src/target/riscv/riscv.h @@ -92,8 +92,6 @@ typedef struct { void (*on_resume)(struct target *target); void (*on_step)(struct target *target); enum riscv_halt_reason (*halt_reason)(struct target *target); - void (*debug_buffer_enter)(struct target *target, struct riscv_program *program); - void (*debug_buffer_leave)(struct target *target, struct riscv_program *program); void (*write_debug_buffer)(struct target *target, unsigned index, riscv_insn_t d); riscv_insn_t (*read_debug_buffer)(struct target *target, unsigned index); @@ -211,9 +209,6 @@ int riscv_count_triggers_of_hart(struct target *target, int hartid); * information. */ size_t riscv_debug_buffer_size(struct target *target); -int riscv_debug_buffer_enter(struct target *target, struct riscv_program *program); -int riscv_debug_buffer_leave(struct target *target, struct riscv_program *program); - riscv_insn_t riscv_read_debug_buffer(struct target *target, int index); riscv_addr_t riscv_read_debug_buffer_x(struct target *target, int index); int riscv_write_debug_buffer(struct target *target, int index, riscv_insn_t insn); From fbe2980eb737fa3083ad35c94acdda32579f1929 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Tue, 17 Oct 2017 11:15:51 -0700 Subject: [PATCH 06/20] MemTest64 passes. Change-Id: I75996b71c3f31025c89ef596a08e01d191405336 --- src/target/riscv/batch.c | 3 +-- src/target/riscv/riscv-013.c | 19 +++++++++++++++++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/target/riscv/batch.c b/src/target/riscv/batch.c index 1e6a4be92..1e6db42b8 100644 --- a/src/target/riscv/batch.c +++ b/src/target/riscv/batch.c @@ -49,13 +49,12 @@ void riscv_batch_run(struct riscv_batch *batch) return; } - keep_alive(); + keep_alive(); LOG_DEBUG("running a batch of %ld scans", (long)batch->used_scans); riscv_batch_add_nop(batch); for (size_t i = 0; i < batch->used_scans; ++i) { - dump_field(batch->fields + i); jtag_add_dr_scan(batch->target->tap, 1, batch->fields + i, TAP_IDLE); if (batch->idle_count > 0) jtag_add_runtest(batch->idle_count, TAP_IDLE); diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index a34bda07b..71be76df1 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -1316,6 +1316,7 @@ static int read_memory(struct target *target, target_addr_t address, AC_ACCESS_REGISTER_TRANSFER | AC_ACCESS_REGISTER_POSTEXEC)) != ERROR_OK) return ERROR_FAIL; + // First read has just triggered. Result is in s1. dmi_write(target, DMI_ABSTRACTAUTO, 1 << DMI_ABSTRACTAUTO_AUTOEXECDATA_OFFSET); @@ -1329,6 +1330,7 @@ static int read_memory(struct target *target, target_addr_t address, // Invariant: // s0 contains the next address to read // s1 contains the data read at the previous address + // dmdata0 contains the data read at the previous previous address unsigned start = (cur_addr - address) / size; LOG_DEBUG("creating burst to read address 0x%" TARGET_PRIxADDR @@ -1385,7 +1387,10 @@ static int read_memory(struct target *target, target_addr_t address, // Now read whatever we got out of the batch. unsigned rereads = 0; - for (riscv_addr_t addr = cur_addr; addr < next_addr; addr += size) { + for (riscv_addr_t addr = cur_addr - size; addr < next_addr - size; addr += size) { + if (addr < address) + continue; + riscv_addr_t offset = addr - address; uint64_t dmi_out = riscv_batch_get_dmi_read(batch, rereads); @@ -1403,6 +1408,14 @@ static int read_memory(struct target *target, target_addr_t address, dmi_write(target, DMI_ABSTRACTAUTO, 0); + if (count > 1) { + // Read the penultimate word. + uint64_t value = dmi_read(target, DMI_DATA0); + write_to_buf(buffer + cur_addr - size - address, value, size); + LOG_DEBUG("M[0x%" TARGET_PRIxADDR "] reads 0x%" PRIx64, cur_addr - + size, value); + } + // Read the last word. uint64_t value; if (register_read_direct(target, &value, GDB_REGNO_S1) != ERROR_OK) @@ -1508,7 +1521,7 @@ static int write_memory(struct target *target, target_addr_t address, // Write value. dmi_write(target, DMI_DATA0, value); - // Write and execute command that moves value into S0 and + // Write and execute command that moves value into S1 and // executes program buffer. uint32_t command = access_register_command(GDB_REGNO_S1, 32, AC_ACCESS_REGISTER_POSTEXEC | @@ -1521,6 +1534,8 @@ static int write_memory(struct target *target, target_addr_t address, // Turn on autoexec dmi_write(target, DMI_ABSTRACTAUTO, 1 << DMI_ABSTRACTAUTO_AUTOEXECDATA_OFFSET); + + setup_needed = false; } else { riscv_batch_add_dmi_write(batch, DMI_DATA0, value); if (riscv_batch_full(batch)) From 65be0776d8301daddee9c517e7a7a2c154313dd2 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Tue, 17 Oct 2017 11:52:07 -0700 Subject: [PATCH 07/20] Memory read/write works if the core can keep up. Change-Id: Ieca50ece266fbc9d2ff16a5cc2e6b4b926ad5e6f --- src/target/riscv/riscv-013.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 71be76df1..15102907a 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -1388,18 +1388,15 @@ static int read_memory(struct target *target, target_addr_t address, // Now read whatever we got out of the batch. unsigned rereads = 0; for (riscv_addr_t addr = cur_addr - size; addr < next_addr - size; addr += size) { - if (addr < address) - continue; - - riscv_addr_t offset = addr - address; - - uint64_t dmi_out = riscv_batch_get_dmi_read(batch, rereads); - uint32_t value = get_field(dmi_out, DTM_DMI_DATA); - write_to_buf(buffer + offset, value, size); + if (addr >= address) { + riscv_addr_t offset = addr - address; + uint64_t dmi_out = riscv_batch_get_dmi_read(batch, rereads); + uint32_t value = get_field(dmi_out, DTM_DMI_DATA); + write_to_buf(buffer + offset, value, size); + LOG_DEBUG("M[0x%" TARGET_PRIxADDR "] reads 0x%08x", addr, value); + } rereads++; - - LOG_DEBUG("M[0x%" TARGET_PRIxADDR "] reads 0x%08x", addr, value); } riscv_batch_free(batch); @@ -1512,6 +1509,7 @@ static int write_memory(struct target *target, target_addr_t address, } LOG_DEBUG("M[0x%08" PRIx64 "] writes 0x%08x", address + offset, value); + cur_addr += size; if (setup_needed) { if (register_write_direct(target, GDB_REGNO_S0, @@ -1541,7 +1539,6 @@ static int write_memory(struct target *target, target_addr_t address, if (riscv_batch_full(batch)) break; } - cur_addr += size; } riscv_batch_run(batch); From a0623b2fa83eeeef91b83f193c98a1354d5963f9 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Tue, 17 Oct 2017 11:58:51 -0700 Subject: [PATCH 08/20] Don't crash when encountering RV64. Change-Id: Ie915ce830c3499919e4918ad443a5e225cf8c4d9 --- src/target/riscv/riscv-013.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 15102907a..8e7a2f01c 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -700,7 +700,8 @@ static int register_read_abstract(struct target *target, uint64_t *value, return result; } - *value = read_abstract_arg(target, 0); + if (value) + *value = read_abstract_arg(target, 0); return ERROR_OK; } @@ -1078,11 +1079,7 @@ static int examine(struct target *target) * program buffer. */ r->debug_buffer_size[i] = info->progsize; - /* Guess this is a 32-bit system, we're probing it. */ - // >>> r->xlen[i] = 32; - - uint64_t value; - int result = register_read_abstract(target, &value, GDB_REGNO_S0, 64); + int result = register_read_abstract(target, NULL, GDB_REGNO_S0, 64); if (result == ERROR_OK) { r->xlen[i] = 64; } else { @@ -1371,7 +1368,6 @@ static int read_memory(struct target *target, target_addr_t address, dmi_write(target, DMI_ABSTRACTAUTO, 0); if (register_read_direct(target, &next_addr, GDB_REGNO_S0) != ERROR_OK) return ERROR_FAIL; - next_addr -= size; dmi_write(target, DMI_ABSTRACTAUTO, 1 << DMI_ABSTRACTAUTO_AUTOEXECDATA_OFFSET); break; From 7edd9b17862570352c4c70729f2f141ec06f8325 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Wed, 18 Oct 2017 11:27:28 -0700 Subject: [PATCH 09/20] Fix FPR access. Change-Id: I1379de87904f1cf40b45d1a5490249e3ba90d7d0 --- src/target/riscv/riscv-013.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 8e7a2f01c..70531e9ad 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -767,9 +767,9 @@ static int register_write_direct(struct target *target, unsigned number, if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { if (supports_extension(target, 'D') && riscv_xlen(target) >= 64) { - riscv_program_insert(&program, fmv_x_d(S0, number - GDB_REGNO_FPR0)); + riscv_program_insert(&program, fmv_d_x(number - GDB_REGNO_FPR0, S0)); } else { - riscv_program_insert(&program, fmv_x_s(S0, number - GDB_REGNO_FPR0)); + riscv_program_insert(&program, fmv_s_x(number - GDB_REGNO_FPR0, S0)); } } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) { riscv_program_csrw(&program, S0, number); @@ -811,9 +811,9 @@ static int register_read_direct(struct target *target, uint64_t *value, uint32_t // TODO: Possibly set F in mstatus. // TODO: Fully support D extension on RV32. if (supports_extension(target, 'D') && riscv_xlen(target) >= 64) { - riscv_program_insert(&program, fmv_d_x(number - GDB_REGNO_FPR0, S0)); + riscv_program_insert(&program, fmv_x_d(S0, number - GDB_REGNO_FPR0)); } else { - riscv_program_insert(&program, fmv_s_x(number - GDB_REGNO_FPR0, S0)); + riscv_program_insert(&program, fmv_x_s(S0, number - GDB_REGNO_FPR0)); } } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) { riscv_program_csrr(&program, S0, number); @@ -1086,9 +1086,12 @@ static int examine(struct target *target) r->xlen[i] = 32; } + r->misa = riscv_get_register_on_hart(target, i, GDB_REGNO_MISA); + /* Display this as early as possible to help people who are using * really slow simulators. */ - LOG_DEBUG(" hart %d: XLEN=%d", i, r->xlen[i]); + LOG_DEBUG(" hart %d: XLEN=%d, misa=0x%" PRIx64, i, r->xlen[i], + r->misa); } /* Then we check the number of triggers availiable to each hart. */ From 5d3f5c35d285fe7dc684fcbd94d3c5a8b4e8b8e1 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Wed, 18 Oct 2017 12:32:41 -0700 Subject: [PATCH 10/20] Still restore registers if an access failed. Change-Id: I11571f0926f69a34f95b4929f633fdecd3a4e810 --- src/target/riscv/riscv-013.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 70531e9ad..5495516b0 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -781,14 +781,13 @@ static int register_write_direct(struct target *target, unsigned number, int exec_out = riscv_program_exec(&program, target); if (exec_out != ERROR_OK) { riscv013_clear_abstract_error(target); - return ERROR_FAIL; } // Restore S0. if (register_write_direct(target, GDB_REGNO_S0, s0) != ERROR_OK) return ERROR_FAIL; - return ERROR_OK; + return exec_out; } /** Actually read registers from the target right now. */ @@ -798,6 +797,8 @@ static int register_read_direct(struct target *target, uint64_t *value, uint32_t riscv_xlen(target)); if (result != ERROR_OK) { + result = ERROR_OK; + struct riscv_program program; riscv_program_init(&program, target); assert(number != GDB_REGNO_S0); @@ -823,10 +824,9 @@ static int register_read_direct(struct target *target, uint64_t *value, uint32_t } // Execute program. - int exec_out = riscv_program_exec(&program, target); - if (exec_out != ERROR_OK) { + result = riscv_program_exec(&program, target); + if (result != ERROR_OK) { riscv013_clear_abstract_error(target); - return ERROR_FAIL; } // Read S0 @@ -837,9 +837,12 @@ static int register_read_direct(struct target *target, uint64_t *value, uint32_t return ERROR_FAIL; } - LOG_DEBUG("[%d] reg[0x%x] = 0x%" PRIx64, riscv_current_hartid(target), - number, *value); - return ERROR_OK; + if (result == ERROR_OK) { + LOG_DEBUG("[%d] reg[0x%x] = 0x%" PRIx64, riscv_current_hartid(target), + number, *value); + } + + return result; } /*** OpenOCD target functions. ***/ From 85bfab36ad549aa53e5054bb5b850d11f8f80386 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Wed, 18 Oct 2017 12:43:03 -0700 Subject: [PATCH 11/20] Remove unused functionality. Change-Id: I0c1464e2e6aa12d0cb1025ed0a7c1c483e7403b7 --- src/target/riscv/program.c | 63 ++------------------------------------ src/target/riscv/program.h | 13 +------- 2 files changed, 3 insertions(+), 73 deletions(-) diff --git a/src/target/riscv/program.c b/src/target/riscv/program.c index 7175fa344..b4f2b55ad 100644 --- a/src/target/riscv/program.c +++ b/src/target/riscv/program.c @@ -21,7 +21,6 @@ int riscv_program_init(struct riscv_program *p, struct target *target) memset(p, 0, sizeof(*p)); p->target = target; p->instruction_count = 0; - p->data_count = 0; p->writes_memory = 0; p->target_xlen = riscv_xlen(target); for (size_t i = 0; i < RISCV_REGISTER_COUNT; ++i) { @@ -84,7 +83,7 @@ int riscv_program_exec(struct riscv_program *p, struct target *t) } for (size_t i = 0; i < riscv_debug_buffer_size(p->target); ++i) - if (i >= riscv_debug_buffer_size(p->target) - p->data_count) + if (i >= riscv_debug_buffer_size(p->target)) p->debug_buffer[i] = riscv_read_debug_buffer(t, i); for (size_t i = GDB_REGNO_XPR0; i <= GDB_REGNO_XPR31; ++i) @@ -298,56 +297,6 @@ int riscv_program_addi(struct riscv_program *p, enum gdb_regno d, enum gdb_regno return riscv_program_insert(p, addi(d, s, u)); } -int riscv_program_fsx(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr) -{ - assert(d >= GDB_REGNO_FPR0); - assert(d <= GDB_REGNO_FPR31); - enum gdb_regno t = riscv_program_gah(p, addr) == 0 - ? GDB_REGNO_X0 - : riscv_program_gettemp(p); - if (riscv_program_lah(p, t, addr) != ERROR_OK) - return ERROR_FAIL; - uint32_t instruction; - switch (p->target->reg_cache->reg_list[GDB_REGNO_FPR0].size) { - case 64: - instruction = fsd(d - GDB_REGNO_FPR0, t, riscv_program_gal(p, addr)); - break; - case 32: - instruction = fsw(d - GDB_REGNO_FPR0, t, riscv_program_gal(p, addr)); - break; - default: - return ERROR_FAIL; - } - if (riscv_program_insert(p, instruction) != ERROR_OK) - return ERROR_FAIL; - riscv_program_puttemp(p, t); - p->writes_memory = true; - return ERROR_OK; -} - -int riscv_program_flx(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr) -{ - assert(d >= GDB_REGNO_FPR0); - assert(d <= GDB_REGNO_FPR31); - enum gdb_regno t = riscv_program_gah(p, addr) == 0 ? GDB_REGNO_X0 : d; - if (riscv_program_lah(p, t, addr) != ERROR_OK) - return ERROR_FAIL; - uint32_t instruction; - switch (p->target->reg_cache->reg_list[GDB_REGNO_FPR0].size) { - case 64: - instruction = fld(d - GDB_REGNO_FPR0, t, riscv_program_gal(p, addr)); - break; - case 32: - instruction = flw(d - GDB_REGNO_FPR0, t, riscv_program_gal(p, addr)); - break; - default: - return ERROR_FAIL; - } - if (riscv_program_insert(p, instruction) != ERROR_OK) - return ERROR_FAIL; - return ERROR_OK; -} - int riscv_program_li(struct riscv_program *p, enum gdb_regno d, riscv_reg_t c) { if (riscv_program_lui(p, d, c >> 12) != ERROR_OK) @@ -371,13 +320,6 @@ int riscv_program_do_restore_register(struct riscv_program *p, enum gdb_regno r) return ERROR_OK; } -void riscv_program_reserve_register(struct riscv_program *p, enum gdb_regno r) -{ - assert(r < RISCV_REGISTER_COUNT); - assert(p->in_use[r] == 0); - p->in_use[r] = 1; -} - enum gdb_regno riscv_program_gettemp(struct riscv_program *p) { for (size_t i = GDB_REGNO_S0; i <= GDB_REGNO_XPR31; ++i) { @@ -431,10 +373,9 @@ int riscv_program_lal(struct riscv_program *p, enum gdb_regno d, riscv_addr_t ad int riscv_program_insert(struct riscv_program *p, riscv_insn_t i) { - if (p->instruction_count + p->data_count + 1 > riscv_debug_buffer_size(p->target)) { + if (p->instruction_count >= riscv_debug_buffer_size(p->target)) { LOG_ERROR("Unable to insert instruction:"); LOG_ERROR(" instruction_count=%d", (int)p->instruction_count); - LOG_ERROR(" data_count =%d", (int)p->data_count); LOG_ERROR(" buffer size =%d", (int)riscv_debug_buffer_size(p->target)); abort(); } diff --git a/src/target/riscv/program.h b/src/target/riscv/program.h index e5f6c29e2..56a1a9a0a 100644 --- a/src/target/riscv/program.h +++ b/src/target/riscv/program.h @@ -15,11 +15,8 @@ struct riscv_program { uint32_t debug_buffer[RISCV_MAX_DEBUG_BUFFER_SIZE]; - /* The debug buffer is allocated in two directions: instructions go at - * the start, while data goes at the end. When they meet in the middle - * this blows up. */ + /* Number of 32-bit instructions in the program. */ size_t instruction_count; - size_t data_count; /* Side effects of executing this program. These must be accounted for * in order to maintain correct executing of the target system. */ @@ -29,10 +26,6 @@ struct riscv_program { /* When a register is used it will be set in this array. */ bool in_use[RISCV_REGISTER_COUNT]; - /* Remembers the registers that have been saved into dscratch - * registers. These are restored */ - enum gdb_regno dscratch_saved[RISCV_DSCRATCH_COUNT]; - /* XLEN on the target. */ int target_xlen; }; @@ -101,9 +94,6 @@ int riscv_program_ebreak(struct riscv_program *p); int riscv_program_lui(struct riscv_program *p, enum gdb_regno d, int32_t u); int riscv_program_addi(struct riscv_program *p, enum gdb_regno d, enum gdb_regno s, int16_t i); -int riscv_program_fsx(struct riscv_program *p, enum gdb_regno s, riscv_addr_t addr); -int riscv_program_flx(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr); - /* Assembler macros. */ int riscv_program_li(struct riscv_program *p, enum gdb_regno d, riscv_reg_t c); int riscv_program_la(struct riscv_program *p, enum gdb_regno d, riscv_addr_t a); @@ -113,7 +103,6 @@ int riscv_program_la(struct riscv_program *p, enum gdb_regno d, riscv_addr_t a); * reserving registers -- it's expected that this has been called as the first * thing in the program's execution to reserve registers that can't be touched * by the program's execution. */ -void riscv_program_reserve_register(struct riscv_program *p, enum gdb_regno r); enum gdb_regno riscv_program_gettemp(struct riscv_program *p); void riscv_program_puttemp(struct riscv_program *p, enum gdb_regno r); From a3a137062d518308bbb9bdbae291cfd3d28d1bc6 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Wed, 18 Oct 2017 14:21:23 -0700 Subject: [PATCH 12/20] Pay attention to impebreak. This required updating debug_defines.h, which caused a few other small cleanups as well. Change-Id: I3c2cb418d7eff3093d7664c5563b2af5e8b530eb --- src/target/riscv/debug_defines.h | 127 ++++++++++++++++++------------- src/target/riscv/program.c | 7 +- src/target/riscv/riscv-013.c | 22 +++--- src/target/riscv/riscv.h | 3 + 4 files changed, 95 insertions(+), 64 deletions(-) diff --git a/src/target/riscv/debug_defines.h b/src/target/riscv/debug_defines.h index 6e88a55ec..6067dbec0 100644 --- a/src/target/riscv/debug_defines.h +++ b/src/target/riscv/debug_defines.h @@ -173,12 +173,6 @@ #define CSR_DCSR_EBREAKM_LENGTH 1 #define CSR_DCSR_EBREAKM (0x1U << CSR_DCSR_EBREAKM_OFFSET) /* -* When 1, {\tt ebreak} instructions in Hypervisor Mode enter Debug Mode. - */ -#define CSR_DCSR_EBREAKH_OFFSET 14 -#define CSR_DCSR_EBREAKH_LENGTH 1 -#define CSR_DCSR_EBREAKH (0x1U << CSR_DCSR_EBREAKH_OFFSET) -/* * When 1, {\tt ebreak} instructions in Supervisor Mode enter Debug Mode. */ #define CSR_DCSR_EBREAKS_OFFSET 13 @@ -207,9 +201,10 @@ /* * 0: Increment counters as usual. * -* 1: Don't increment any counters while in Debug Mode. This includes -* the {\tt cycle} and {\tt instret} CSRs. This is preferred for most -* debugging scenarios. +* 1: Don't increment any counters while in Debug Mode or on {\tt +* ebreak} instructions that cause entry into Debug Mode. These +* counters include the {\tt cycle} and {\tt instret} CSRs. This is +* preferred for most debugging scenarios. * * An implementation may choose not to support writing to this bit. * The debugger must read back the value it writes to check whether @@ -312,9 +307,9 @@ * * This bit is only writable from Debug Mode. */ -#define CSR_TDATA1_HMODE_OFFSET XLEN-5 -#define CSR_TDATA1_HMODE_LENGTH 1 -#define CSR_TDATA1_HMODE (0x1ULL << CSR_TDATA1_HMODE_OFFSET) +#define CSR_TDATA1_DMODE_OFFSET XLEN-5 +#define CSR_TDATA1_DMODE_LENGTH 1 +#define CSR_TDATA1_DMODE (0x1ULL << CSR_TDATA1_DMODE_OFFSET) /* * Trigger-specific data. */ @@ -390,7 +385,7 @@ * 0: Raise a breakpoint exception. (Used when software wants to use * the trigger module without an external debugger attached.) * -* 1: Enter Debug Mode. (Only supported when \Fhmode is 1.) +* 1: Enter Debug Mode. (Only supported when \Fdmode is 1.) * * 2: Start tracing. * @@ -532,7 +527,7 @@ * 0: Raise a breakpoint exception. (Used when software wants to use the * trigger module without an external debugger attached.) * -* 1: Enter Debug Mode. (Only supported when \Fhmode is 1.) +* 1: Enter Debug Mode. (Only supported when \Fdmode is 1.) * * 2: Start tracing. * @@ -549,6 +544,30 @@ #define CSR_ICOUNT_ACTION (0x3fULL << CSR_ICOUNT_ACTION_OFFSET) #define DMI_DMSTATUS 0x11 /* +* If 1, then there is an implicit {\tt ebreak} instruction at the +* non-existent word immediately after the Program Buffer. This saves +* the debugger from having to write the {\tt ebreak} itself, and +* allows the Program Buffer to be one word smaller. +* +* This must be 1 when \Fprogbufsize is 1. + */ +#define DMI_DMSTATUS_IMPEBREAK_OFFSET 22 +#define DMI_DMSTATUS_IMPEBREAK_LENGTH 1 +#define DMI_DMSTATUS_IMPEBREAK (0x1U << DMI_DMSTATUS_IMPEBREAK_OFFSET) +/* +* Gets set if the Debug Module was accessed incorrectly. +* +* 0 (none): No error. +* +* 1 (badaddr): There was an access to an unimplemented Debug Module +* address. +* +* 7 (other): An access failed for another reason. + */ +#define DMI_DMSTATUS_DMERR_OFFSET 18 +#define DMI_DMSTATUS_DMERR_LENGTH 3 +#define DMI_DMSTATUS_DMERR (0x7U << DMI_DMSTATUS_DMERR_OFFSET) +/* * This field is 1 when all currently selected harts have acknowledged the previous \Fresumereq. */ #define DMI_DMSTATUS_ALLRESUMEACK_OFFSET 17 @@ -629,6 +648,13 @@ #define DMI_DMSTATUS_AUTHBUSY_OFFSET 6 #define DMI_DMSTATUS_AUTHBUSY_LENGTH 1 #define DMI_DMSTATUS_AUTHBUSY (0x1U << DMI_DMSTATUS_AUTHBUSY_OFFSET) +/* +* 0: \Rdevtreeaddrzero--\Rdevtreeaddrthree hold information which +* is not relevant to the Device Tree. +* +* 1: \Rdevtreeaddrzero--\Rdevtreeaddrthree registers hold the address of the +* Device Tree. + */ #define DMI_DMSTATUS_DEVTREEVALID_OFFSET 4 #define DMI_DMSTATUS_DEVTREEVALID_LENGTH 1 #define DMI_DMSTATUS_DEVTREEVALID (0x1U << DMI_DMSTATUS_DEVTREEVALID_OFFSET) @@ -654,7 +680,6 @@ * * Writing 1 or 0 has no effect on a hart which is already halted, but * the bit should be cleared to 0 before the hart is resumed. -* Setting both \Fhaltreq and \Fresumereq leads to undefined behavior. * * Writes apply to the new value of \Fhartsel and \Fhasel. */ @@ -664,7 +689,8 @@ /* * Resume request signal for all currently selected harts. When set to 1, * each selected hart will resume if it is currently halted. -* Setting both \Fhaltreq and \Fresumereq leads to undefined behavior. +* +* This bit is ignored while \Fhaltreq is set. * * Writes apply to the new value of \Fhartsel and \Fhasel. */ @@ -710,11 +736,12 @@ #define DMI_DMCONTROL_HARTSEL (0x3ffU << DMI_DMCONTROL_HARTSEL_OFFSET) /* * This bit controls the reset signal from the DM to the rest of the -* system. To perform a system reset the debugger writes 1, +* system. The signal should reset every part of the system, including +* every hart, except for the DM and any logic required to access the +* DM. +* To perform a system reset the debugger writes 1, * and then writes 0 -* to deassert the reset. This bit must not reset the Debug Module -* registers. What it does reset is platform-specific (it may -* reset nothing). +* to deassert the reset. */ #define DMI_DMCONTROL_NDMRESET_OFFSET 1 #define DMI_DMCONTROL_NDMRESET_LENGTH 1 @@ -778,7 +805,7 @@ * shadowing the {\tt data} registers. * * If \Fdataaccess is 1: Signed address of RAM where the {\tt data} -* registers are shadowed. +* registers are shadowed, to be used to access relative to \Rzero. */ #define DMI_HARTINFO_DATAADDR_OFFSET 0 #define DMI_HARTINFO_DATAADDR_LENGTH 12 @@ -891,13 +918,10 @@ #define DMI_ABSTRACTCS 0x16 /* * Size of the Program Buffer, in 32-bit words. Valid sizes are 0 - 16. -* -* TODO: Explain what can be done with each size of the buffer, to suggest -* why you would want more or less words. */ -#define DMI_ABSTRACTCS_PROGSIZE_OFFSET 24 -#define DMI_ABSTRACTCS_PROGSIZE_LENGTH 5 -#define DMI_ABSTRACTCS_PROGSIZE (0x1fU << DMI_ABSTRACTCS_PROGSIZE_OFFSET) +#define DMI_ABSTRACTCS_PROGBUFSIZE_OFFSET 24 +#define DMI_ABSTRACTCS_PROGBUFSIZE_LENGTH 5 +#define DMI_ABSTRACTCS_PROGBUFSIZE (0x1fU << DMI_ABSTRACTCS_PROGBUFSIZE_OFFSET) /* * 1: An abstract command is currently being executed. * @@ -1013,24 +1037,22 @@ * * 4: 128-bit * -* If an unsupported system bus access size is written here, -* the DM may not perform the access, or may perform the access -* with any access size. +* If an unsupported system bus access size is written here, the DM +* does not perform the access and sberror is set to 3. */ #define DMI_SBCS_SBACCESS_OFFSET 17 #define DMI_SBCS_SBACCESS_LENGTH 3 #define DMI_SBCS_SBACCESS (0x7U << DMI_SBCS_SBACCESS_OFFSET) /* -* When 1, the internal address value (used by the system bus master) -* is incremented by the access size (in bytes) selected in \Fsbaccess -* after every system bus access. +* When 1, {\tt sbaddress} is incremented by the access size (in +* bytes) selected in \Fsbaccess after every system bus access. */ #define DMI_SBCS_SBAUTOINCREMENT_OFFSET 16 #define DMI_SBCS_SBAUTOINCREMENT_LENGTH 1 #define DMI_SBCS_SBAUTOINCREMENT (0x1U << DMI_SBCS_SBAUTOINCREMENT_OFFSET) /* -* When 1, every read from \Rsbdatazero automatically triggers a system -* bus read at the new address. +* When 1, every read from \Rsbdatazero automatically triggers a +* system bus read at the (possibly auto-incremented) address. */ #define DMI_SBCS_SBAUTOREAD_OFFSET 15 #define DMI_SBCS_SBAUTOREAD_LENGTH 1 @@ -1052,8 +1074,7 @@ * * 4: The system bus master was busy when one of the * {\tt sbaddress} or {\tt sbdata} registers was written, -* or the {\tt sbdata} register was read when it had -* stale data. +* or \Rsbdatazero was read when it had stale data. */ #define DMI_SBCS_SBERROR_OFFSET 12 #define DMI_SBCS_SBERROR_LENGTH 3 @@ -1097,54 +1118,54 @@ #define DMI_SBCS_SBACCESS8 (0x1U << DMI_SBCS_SBACCESS8_OFFSET) #define DMI_SBADDRESS0 0x39 /* -* Accesses bits 31:0 of the internal address. +* Accesses bits 31:0 of the physical address in {\tt sbaddress}. */ #define DMI_SBADDRESS0_ADDRESS_OFFSET 0 #define DMI_SBADDRESS0_ADDRESS_LENGTH 32 #define DMI_SBADDRESS0_ADDRESS (0xffffffffU << DMI_SBADDRESS0_ADDRESS_OFFSET) #define DMI_SBADDRESS1 0x3a /* -* Accesses bits 63:32 of the internal address (if the system address -* bus is that wide). +* Accesses bits 63:32 of the physical address in {\tt sbaddress} (if +* the system address bus is that wide). */ #define DMI_SBADDRESS1_ADDRESS_OFFSET 0 #define DMI_SBADDRESS1_ADDRESS_LENGTH 32 #define DMI_SBADDRESS1_ADDRESS (0xffffffffU << DMI_SBADDRESS1_ADDRESS_OFFSET) #define DMI_SBADDRESS2 0x3b /* -* Accesses bits 95:64 of the internal address (if the system address -* bus is that wide). +* Accesses bits 95:64 of the physical address in {\tt sbaddress} (if +* the system address bus is that wide). */ #define DMI_SBADDRESS2_ADDRESS_OFFSET 0 #define DMI_SBADDRESS2_ADDRESS_LENGTH 32 #define DMI_SBADDRESS2_ADDRESS (0xffffffffU << DMI_SBADDRESS2_ADDRESS_OFFSET) #define DMI_SBDATA0 0x3c /* -* Accesses bits 31:0 of the internal data. +* Accesses bits 31:0 of {\tt sbdata}. */ #define DMI_SBDATA0_DATA_OFFSET 0 #define DMI_SBDATA0_DATA_LENGTH 32 #define DMI_SBDATA0_DATA (0xffffffffU << DMI_SBDATA0_DATA_OFFSET) #define DMI_SBDATA1 0x3d /* -* Accesses bits 63:32 of the internal data (if the system bus is -* that wide). +* Accesses bits 63:32 of {\tt sbdata} (if the system bus is that +* wide). */ #define DMI_SBDATA1_DATA_OFFSET 0 #define DMI_SBDATA1_DATA_LENGTH 32 #define DMI_SBDATA1_DATA (0xffffffffU << DMI_SBDATA1_DATA_OFFSET) #define DMI_SBDATA2 0x3e /* -* Accesses bits 95:64 of the internal data (if the system bus is -* that wide). +* Accesses bits 95:64 of {\tt sbdata} (if the system bus is that +* wide). */ #define DMI_SBDATA2_DATA_OFFSET 0 #define DMI_SBDATA2_DATA_LENGTH 32 #define DMI_SBDATA2_DATA (0xffffffffU << DMI_SBDATA2_DATA_OFFSET) #define DMI_SBDATA3 0x3f /* -* Accesses bits 127:96 of the internal data (if the system bus is -* that wide). +* Accesses bits 127:96 of {\tt sbdata} (if the system bus is that +* wide). */ #define DMI_SBDATA3_DATA_OFFSET 0 #define DMI_SBDATA3_DATA_LENGTH 32 @@ -1188,6 +1209,9 @@ * 0: Don't do the operation specified by \Fwrite. * * 1: Do the operation specified by \Fwrite. +* +* This bit can be used to just execute the Program Buffer without +* having to worry about placing valid values into \Fsize or \Fregno. */ #define AC_ACCESS_REGISTER_TRANSFER_OFFSET 17 #define AC_ACCESS_REGISTER_TRANSFER_LENGTH 1 @@ -1223,8 +1247,9 @@ /* * Contains the privilege level the hart was operating in when Debug * Mode was entered. The encoding is described in Table -* \ref{tab:privlevel}. A user can write this value to change the -* hart's privilege level when exiting Debug Mode. +* \ref{tab:privlevel}, and matches the privilege level encoding from +* the RISC-V Privileged ISA Specification. A user can write this +* value to change the hart's privilege level when exiting Debug Mode. */ #define VIRT_PRIV_PRV_OFFSET 0 #define VIRT_PRIV_PRV_LENGTH 2 diff --git a/src/target/riscv/program.c b/src/target/riscv/program.c index b4f2b55ad..f02e4ea58 100644 --- a/src/target/riscv/program.c +++ b/src/target/riscv/program.c @@ -279,9 +279,10 @@ int riscv_program_fence(struct riscv_program *p) int riscv_program_ebreak(struct riscv_program *p) { - if (p->instruction_count == riscv_debug_buffer_size(p->target)) { - // TODO: Check for impebreak bit. - // There's an implicit ebreak here, so no need for us to add one. + struct target *target = p->target; + RISCV_INFO(r); + if (p->instruction_count == riscv_debug_buffer_size(p->target) && + r->impebreak) { return ERROR_OK; } return riscv_program_insert(p, ebreak()); diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 5495516b0..b05110cd3 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -137,7 +137,7 @@ typedef struct { /* Number of abstract command data registers. */ unsigned datacount; /* Number of words in the Program Buffer. */ - unsigned progsize; + unsigned progbufsize; /* Number of Program Buffer registers. */ /* Number of words in Debug RAM. */ uint64_t tselect; @@ -200,6 +200,7 @@ static void decode_dmi(char *text, unsigned address, unsigned data) { DMI_DMCONTROL, DMI_DMCONTROL_NDMRESET, "ndmreset" }, { DMI_DMCONTROL, DMI_DMCONTROL_DMACTIVE, "dmactive" }, + { DMI_DMSTATUS, DMI_DMSTATUS_IMPEBREAK, "impebreak" }, { DMI_DMSTATUS, DMI_DMSTATUS_ALLRESUMEACK, "allresumeack" }, { DMI_DMSTATUS, DMI_DMSTATUS_ANYRESUMEACK, "anyresumeack" }, { DMI_DMSTATUS, DMI_DMSTATUS_ALLNONEXISTENT, "allnonexistent" }, @@ -215,7 +216,7 @@ static void decode_dmi(char *text, unsigned address, unsigned data) { DMI_DMSTATUS, DMI_DMSTATUS_DEVTREEVALID, "devtreevalid" }, { DMI_DMSTATUS, DMI_DMSTATUS_VERSION, "version" }, - { DMI_ABSTRACTCS, DMI_ABSTRACTCS_PROGSIZE, "progsize" }, + { DMI_ABSTRACTCS, DMI_ABSTRACTCS_PROGBUFSIZE, "progbufsize" }, { DMI_ABSTRACTCS, DMI_ABSTRACTCS_BUSY, "busy" }, { DMI_ABSTRACTCS, DMI_ABSTRACTCS_CMDERR, "cmderr" }, { DMI_ABSTRACTCS, DMI_ABSTRACTCS_DATACOUNT, "datacount" }, @@ -910,7 +911,7 @@ static int init_target(struct command_context *cmd_ctx, return ERROR_FAIL; riscv013_info_t *info = get_info(target); - info->progsize = -1; + info->progbufsize = -1; info->progbuf_addr = -1; info->data_size = -1; info->data_addr = -1; @@ -1043,10 +1044,12 @@ static int examine(struct target *target) // Check that abstract data registers are accessible. uint32_t abstractcs = dmi_read(target, DMI_ABSTRACTCS); info->datacount = get_field(abstractcs, DMI_ABSTRACTCS_DATACOUNT); - info->progsize = get_field(abstractcs, DMI_ABSTRACTCS_PROGSIZE); + info->progbufsize = get_field(abstractcs, DMI_ABSTRACTCS_PROGBUFSIZE); /* Before doing anything else we must first enumerate the harts. */ RISCV_INFO(r); + r->impebreak = get_field(dmstatus, DMI_DMSTATUS_IMPEBREAK); + int original_coreid = target->coreid; for (int i = 0; i < RISCV_MAX_HARTS; ++i) { /* Fake being a non-RTOS targeted to this core so we can see if @@ -1080,7 +1083,7 @@ static int examine(struct target *target) /* Without knowing anything else we can at least mess with the * program buffer. */ - r->debug_buffer_size[i] = info->progsize; + r->debug_buffer_size[i] = info->progbufsize; int result = register_read_abstract(target, NULL, GDB_REGNO_S0, 64); if (result == ERROR_OK) { @@ -1768,16 +1771,16 @@ static enum riscv_halt_reason riscv013_halt_reason(struct target *target) void riscv013_write_debug_buffer(struct target *target, unsigned index, riscv_insn_t data) { RISCV013_INFO(info); - if (index >= info->progsize) - return dmi_write(target, DMI_DATA0 + index - info->progsize, data); + if (index >= info->progbufsize) + return dmi_write(target, DMI_DATA0 + index - info->progbufsize, data); return dmi_write(target, DMI_PROGBUF0 + index, data); } riscv_insn_t riscv013_read_debug_buffer(struct target *target, unsigned index) { RISCV013_INFO(info); - if (index >= info->progsize) - return dmi_read(target, DMI_DATA0 + index - info->progsize); + if (index >= info->progbufsize) + return dmi_read(target, DMI_DATA0 + index - info->progbufsize); return dmi_read(target, DMI_PROGBUF0 + index); } @@ -1835,7 +1838,6 @@ static void riscv013_on_step_or_resume(struct target *target, bool step) uint64_t dcsr = riscv_get_register(target, GDB_REGNO_DCSR); dcsr = set_field(dcsr, CSR_DCSR_STEP, step); dcsr = set_field(dcsr, CSR_DCSR_EBREAKM, 1); - dcsr = set_field(dcsr, CSR_DCSR_EBREAKH, 1); dcsr = set_field(dcsr, CSR_DCSR_EBREAKS, 1); dcsr = set_field(dcsr, CSR_DCSR_EBREAKU, 1); riscv_set_register(target, GDB_REGNO_DCSR, dcsr); diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h index e7b0ea2db..f19f06c4c 100644 --- a/src/target/riscv/riscv.h +++ b/src/target/riscv/riscv.h @@ -78,6 +78,9 @@ typedef struct { /* This avoids invalidating the register cache too often. */ bool registers_initialized; + /* This hart contains an implicit ebreak at the end of the program buffer. */ + bool impebreak; + /* Helper functions that target the various RISC-V debug spec * implementations. */ riscv_reg_t (*get_register)(struct target *, int hartid, int regid); From 5425c871c97b5a80c8552a0bc3dca963761a2f03 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Mon, 23 Oct 2017 14:13:46 -0700 Subject: [PATCH 13/20] Properly fix memory read when encountering busy. Change-Id: I377054495e860076edc2f38d1cc0f11c23f98d3b --- src/target/riscv/riscv-013.c | 135 ++++++++++++++++++++++++++--------- 1 file changed, 100 insertions(+), 35 deletions(-) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index b05110cd3..5c81c5512 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -1317,36 +1317,42 @@ static int read_memory(struct target *target, target_addr_t address, // Write address to S0, and execute buffer. if (register_write_direct(target, GDB_REGNO_S0, address) != ERROR_OK) return ERROR_FAIL; - if (execute_abstract_command(target, - access_register_command(GDB_REGNO_S1, riscv_xlen(target), + uint32_t command = access_register_command(GDB_REGNO_S1, riscv_xlen(target), AC_ACCESS_REGISTER_TRANSFER | - AC_ACCESS_REGISTER_POSTEXEC)) != ERROR_OK) + AC_ACCESS_REGISTER_POSTEXEC); + if (execute_abstract_command(target, command) != ERROR_OK) return ERROR_FAIL; + // First read has just triggered. Result is in s1. dmi_write(target, DMI_ABSTRACTAUTO, 1 << DMI_ABSTRACTAUTO_AUTOEXECDATA_OFFSET); - /* Copying memory might fail because we're going too quickly, in which - * case we need to back off a bit and try again. */ - riscv_addr_t cur_addr = address; + // read_addr is the next address that the hart will read from, which is the + // value in s0. + riscv_addr_t read_addr = address + size; + // The next address that we need to receive data for. + riscv_addr_t receive_addr = address; riscv_addr_t fin_addr = address + (count * size); - LOG_DEBUG("reading until final address 0x%" PRIx64, fin_addr); - while (cur_addr < fin_addr - size) { - // Invariant: - // s0 contains the next address to read - // s1 contains the data read at the previous address - // dmdata0 contains the data read at the previous previous address + unsigned skip = 1; + while (read_addr < fin_addr) { + LOG_DEBUG("read_addr=0x%" PRIx64 ", receive_addr=0x%" PRIx64 + ", fin_addr=0x%" PRIx64, read_addr, receive_addr, fin_addr); + // The pipeline looks like this: + // memory -> s1 -> dm_data0 -> debugger + // It advances every time the debugger reads dmdata0. + // So at any time the debugger has just read mem[s0 - 3*size], + // dm_data0 contains mem[s0 - 2*size] + // s1 contains mem[s0-size] - unsigned start = (cur_addr - address) / size; - LOG_DEBUG("creating burst to read address 0x%" TARGET_PRIxADDR - " up to 0x%" TARGET_PRIxADDR "; start=0x%d", cur_addr, fin_addr, start); - assert(cur_addr >= address && cur_addr < fin_addr); + LOG_DEBUG("creating burst to read from 0x%" TARGET_PRIxADDR + " up to 0x%" TARGET_PRIxADDR, 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 = cur_addr; addr < fin_addr - size; addr += size) { + for (riscv_addr_t addr = read_addr; addr < fin_addr; addr += size) { riscv_batch_add_dmi_read(batch, DMI_DATA0); reads++; @@ -1363,20 +1369,62 @@ static int read_memory(struct target *target, target_addr_t address, abstractcs = dmi_read(target, DMI_ABSTRACTCS); info->cmderr = get_field(abstractcs, DMI_ABSTRACTCS_CMDERR); - riscv_addr_t next_addr; + unsigned cmderr = info->cmderr; + riscv_addr_t next_read_addr; + uint32_t dmi_data0 = -1; switch (info->cmderr) { case CMDERR_NONE: LOG_DEBUG("successful (partial?) memory read"); - next_addr = cur_addr + reads * size; + next_read_addr = read_addr + reads * size; break; case CMDERR_BUSY: LOG_DEBUG("memory read resulted in busy response"); + + /* + * If you want to exercise this code path, apply the following patch to spike: +--- a/riscv/debug_module.cc ++++ b/riscv/debug_module.cc +@@ -1,3 +1,5 @@ ++#include ++ + #include + + #include "debug_module.h" +@@ -398,6 +400,15 @@ bool debug_module_t::perform_abstract_command() + // Since the next instruction is what we will use, just use nother NOP + // to get there. + write32(debug_abstract, 1, addi(ZERO, ZERO, 0)); ++ ++ if (abstractauto.autoexecdata && ++ program_buffer[0] == 0x83 && ++ program_buffer[1] == 0x24 && ++ program_buffer[2] == 0x04 && ++ program_buffer[3] == 0 && ++ rand() < RAND_MAX / 10) { ++ usleep(1000000); ++ } + } else { + write32(debug_abstract, 1, ebreak()); + } + */ increase_ac_busy_delay(target); riscv013_clear_abstract_error(target); dmi_write(target, DMI_ABSTRACTAUTO, 0); - if (register_read_direct(target, &next_addr, GDB_REGNO_S0) != ERROR_OK) + + // This is definitely a good version of the value that we + // attempted to read when we discovered that the target was + // busy. + dmi_data0 = dmi_read(target, DMI_DATA0); + + // Clobbers DMI_DATA0. + if (register_read_direct(target, &next_read_addr, GDB_REGNO_S0) != ERROR_OK) return ERROR_FAIL; + // Restore the command, and execute it. + // Now DMI_DATA0 contains the next value just as it would if no + // error had occurred. + dmi_write(target, DMI_COMMAND, command); + dmi_write(target, DMI_ABSTRACTAUTO, 1 << DMI_ABSTRACTAUTO_AUTOEXECDATA_OFFSET); break; @@ -1391,21 +1439,37 @@ static int read_memory(struct target *target, target_addr_t address, } // Now read whatever we got out of the batch. - unsigned rereads = 0; - for (riscv_addr_t addr = cur_addr - size; addr < next_addr - size; addr += size) { - if (addr >= address) { - riscv_addr_t offset = addr - address; - uint64_t dmi_out = riscv_batch_get_dmi_read(batch, rereads); - uint32_t value = get_field(dmi_out, DTM_DMI_DATA); - write_to_buf(buffer + offset, value, size); - LOG_DEBUG("M[0x%" TARGET_PRIxADDR "] reads 0x%08x", addr, value); + for (size_t i = 0; i < reads; i++) { + if (read_addr >= next_read_addr) { + break; } - rereads++; + read_addr += size; + + if (skip > 0) { + skip--; + continue; + } + + riscv_addr_t offset = receive_addr - address; + uint64_t dmi_out = riscv_batch_get_dmi_read(batch, i); + uint32_t value = get_field(dmi_out, DTM_DMI_DATA); + write_to_buf(buffer + offset, value, size); + LOG_DEBUG("M[0x%" TARGET_PRIxADDR "] reads 0x%08x", receive_addr, + value); + + receive_addr += size; } riscv_batch_free(batch); - cur_addr = next_addr; + if (cmderr == CMDERR_BUSY) { + riscv_addr_t offset = receive_addr - address; + write_to_buf(buffer + offset, dmi_data0, size); + LOG_DEBUG("M[0x%" TARGET_PRIxADDR "] reads 0x%08x", receive_addr, + dmi_data0); + read_addr += size; + receive_addr += size; + } } dmi_write(target, DMI_ABSTRACTAUTO, 0); @@ -1413,17 +1477,18 @@ static int read_memory(struct target *target, target_addr_t address, if (count > 1) { // Read the penultimate word. uint64_t value = dmi_read(target, DMI_DATA0); - write_to_buf(buffer + cur_addr - size - address, value, size); - LOG_DEBUG("M[0x%" TARGET_PRIxADDR "] reads 0x%" PRIx64, cur_addr - - size, value); + write_to_buf(buffer + receive_addr - address, value, size); + LOG_DEBUG("M[0x%" TARGET_PRIxADDR "] reads 0x%" PRIx64, receive_addr, value); + receive_addr += size; } // Read the last word. uint64_t value; if (register_read_direct(target, &value, GDB_REGNO_S1) != ERROR_OK) return ERROR_FAIL; - write_to_buf(buffer + cur_addr - address, value, size); - LOG_DEBUG("M[0x%" TARGET_PRIxADDR "] reads 0x%" PRIx64, cur_addr, value); + write_to_buf(buffer + receive_addr - address, value, size); + LOG_DEBUG("M[0x%" TARGET_PRIxADDR "] reads 0x%" PRIx64, receive_addr, value); + receive_addr += size; riscv_set_register(target, GDB_REGNO_S0, s0); riscv_set_register(target, GDB_REGNO_S1, s1); From 3ba6d46fc29c4ee7b6b5f90423a3cf734f0a04e3 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Mon, 23 Oct 2017 14:18:09 -0700 Subject: [PATCH 14/20] Remove unused functionality. Change-Id: Ic70cebd62bbd04f7ae5566504fbb279a11de57f0 --- src/target/riscv/program.c | 225 ------------------------------------- src/target/riscv/program.h | 43 ------- 2 files changed, 268 deletions(-) diff --git a/src/target/riscv/program.c b/src/target/riscv/program.c index f02e4ea58..e7238ddce 100644 --- a/src/target/riscv/program.c +++ b/src/target/riscv/program.c @@ -11,21 +11,15 @@ #include "asm.h" #include "encoding.h" -riscv_addr_t riscv_program_gal(struct riscv_program *p, riscv_addr_t addr); -int riscv_program_lah(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr); -int riscv_program_lal(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr); - /* Program interface. */ int riscv_program_init(struct riscv_program *p, struct target *target) { memset(p, 0, sizeof(*p)); p->target = target; p->instruction_count = 0; - p->writes_memory = 0; p->target_xlen = riscv_xlen(target); for (size_t i = 0; i < RISCV_REGISTER_COUNT; ++i) { p->writes_xreg[i] = 0; - p->in_use[i] = 0; } for(size_t i = 0; i < RISCV_MAX_DEBUG_BUFFER_SIZE; ++i) @@ -58,14 +52,6 @@ int riscv_program_exec(struct riscv_program *p, struct target *t) } } - if (p->writes_memory && (riscv_program_fence(p) != ERROR_OK)) { - LOG_ERROR("Unable to write fence"); - for(size_t i = 0; i < riscv_debug_buffer_size(p->target); ++i) - LOG_ERROR("ram[%02x]: DASM(0x%08lx) [0x%08lx]", (int)i, (long)p->debug_buffer[i], (long)p->debug_buffer[i]); - abort(); - return ERROR_FAIL; - } - if (riscv_program_ebreak(p) != ERROR_OK) { LOG_ERROR("Unable to write ebreak"); for(size_t i = 0; i < riscv_debug_buffer_size(p->target); ++i) @@ -95,160 +81,34 @@ int riscv_program_exec(struct riscv_program *p, struct target *t) int riscv_program_swr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int offset) { - p->writes_memory = 1; return riscv_program_insert(p, sw(d, b, offset)); } int riscv_program_shr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int offset) { - p->writes_memory = 1; return riscv_program_insert(p, sh(d, b, offset)); } int riscv_program_sbr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int offset) { - p->writes_memory = 1; return riscv_program_insert(p, sb(d, b, offset)); } int riscv_program_lwr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int offset) { - p->writes_memory = 1; return riscv_program_insert(p, lw(d, b, offset)); } int riscv_program_lhr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int offset) { - p->writes_memory = 1; return riscv_program_insert(p, lh(d, b, offset)); } int riscv_program_lbr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int offset) { - p->writes_memory = 1; return riscv_program_insert(p, lb(d, b, offset)); } -int riscv_program_lx(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr) -{ - switch (p->target_xlen) { - case 64: return riscv_program_ld(p, d, addr); - case 32: return riscv_program_lw(p, d, addr); - } - - LOG_ERROR("unknown xlen %d", p->target_xlen); - abort(); - return -1; -} - -int riscv_program_ld(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr) -{ - enum gdb_regno t = riscv_program_gah(p, addr) == 0 ? GDB_REGNO_X0 : d; - if (riscv_program_lah(p, d, addr) != ERROR_OK) - return ERROR_FAIL; - if (riscv_program_insert(p, ld(d, t, riscv_program_gal(p, addr))) != ERROR_OK) - return ERROR_FAIL; - return ERROR_OK; -} - -int riscv_program_lw(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr) -{ - enum gdb_regno t = riscv_program_gah(p, addr) == 0 ? GDB_REGNO_X0 : d; - if (riscv_program_lah(p, d, addr) != ERROR_OK) - return ERROR_FAIL; - if (riscv_program_insert(p, lw(d, t, riscv_program_gal(p, addr))) != ERROR_OK) - return ERROR_FAIL; - return ERROR_OK; -} - -int riscv_program_lh(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr) -{ - enum gdb_regno t = riscv_program_gah(p, addr) == 0 ? GDB_REGNO_X0 : d; - if (riscv_program_lah(p, d, addr) != ERROR_OK) - return ERROR_FAIL; - if (riscv_program_insert(p, lh(d, t, riscv_program_gal(p, addr))) != ERROR_OK) - return ERROR_FAIL; - return ERROR_OK; -} - -int riscv_program_lb(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr) -{ - enum gdb_regno t = riscv_program_gah(p, addr) == 0 ? GDB_REGNO_X0 : d; - if (riscv_program_lah(p, t, addr) != ERROR_OK) - return ERROR_FAIL; - if (riscv_program_insert(p, lb(d, t, riscv_program_gal(p, addr))) != ERROR_OK) - return ERROR_FAIL; - return ERROR_OK; -} - -int riscv_program_sx(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr) -{ - switch (p->target_xlen) { - case 64: return riscv_program_sd(p, d, addr); - case 32: return riscv_program_sw(p, d, addr); - } - - LOG_ERROR("unknown xlen %d", p->target_xlen); - abort(); - return -1; -} - -int riscv_program_sd(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr) -{ - enum gdb_regno t = riscv_program_gah(p, addr) == 0 - ? GDB_REGNO_X0 - : riscv_program_gettemp(p); - if (riscv_program_lah(p, t, addr) != ERROR_OK) - return ERROR_FAIL; - if (riscv_program_insert(p, sd(d, t, riscv_program_gal(p, addr))) != ERROR_OK) - return ERROR_FAIL; - riscv_program_puttemp(p, t); - p->writes_memory = true; - return ERROR_OK; -} - -int riscv_program_sw(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr) -{ - enum gdb_regno t = riscv_program_gah(p, addr) == 0 - ? GDB_REGNO_X0 - : riscv_program_gettemp(p); - if (riscv_program_lah(p, t, addr) != ERROR_OK) - return ERROR_FAIL; - if (riscv_program_insert(p, sw(d, t, riscv_program_gal(p, addr))) != ERROR_OK) - return ERROR_FAIL; - riscv_program_puttemp(p, t); - p->writes_memory = true; - return ERROR_OK; -} - -int riscv_program_sh(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr) -{ - enum gdb_regno t = riscv_program_gah(p, addr) == 0 - ? GDB_REGNO_X0 - : riscv_program_gettemp(p); - if (riscv_program_lah(p, t, addr) != ERROR_OK) - return ERROR_FAIL; - if (riscv_program_insert(p, sh(d, t, riscv_program_gal(p, addr))) != ERROR_OK) - return ERROR_FAIL; - riscv_program_puttemp(p, t); - p->writes_memory = true; - return ERROR_OK; -} - -int riscv_program_sb(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr) -{ - enum gdb_regno t = riscv_program_gah(p, addr) == 0 - ? GDB_REGNO_X0 - : riscv_program_gettemp(p); - if (riscv_program_lah(p, t, addr) != ERROR_OK) - return ERROR_FAIL; - if (riscv_program_insert(p, sb(d, t, riscv_program_gal(p, addr))) != ERROR_OK) - return ERROR_FAIL; - riscv_program_puttemp(p, t); - p->writes_memory = true; - return ERROR_OK; -} - int riscv_program_csrr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno csr) { assert(csr >= GDB_REGNO_CSR0 && csr <= GDB_REGNO_CSR4095); @@ -261,12 +121,6 @@ int riscv_program_csrw(struct riscv_program *p, enum gdb_regno s, enum gdb_regno return riscv_program_insert(p, csrrw(GDB_REGNO_X0, s, csr - GDB_REGNO_CSR0)); } -int riscv_program_csrrw(struct riscv_program *p, enum gdb_regno d, enum gdb_regno s, enum gdb_regno csr) -{ - assert(csr >= GDB_REGNO_CSR0); - return riscv_program_insert(p, csrrw(d, s, csr - GDB_REGNO_CSR0)); -} - int riscv_program_fence_i(struct riscv_program *p) { return riscv_program_insert(p, fence_i()); @@ -288,90 +142,11 @@ int riscv_program_ebreak(struct riscv_program *p) return riscv_program_insert(p, ebreak()); } -int riscv_program_lui(struct riscv_program *p, enum gdb_regno d, int32_t u) -{ - return riscv_program_insert(p, lui(d, u)); -} - int riscv_program_addi(struct riscv_program *p, enum gdb_regno d, enum gdb_regno s, int16_t u) { return riscv_program_insert(p, addi(d, s, u)); } -int riscv_program_li(struct riscv_program *p, enum gdb_regno d, riscv_reg_t c) -{ - if (riscv_program_lui(p, d, c >> 12) != ERROR_OK) - return ERROR_FAIL; - if (riscv_program_addi(p, d, d, c & 0xFFF) != ERROR_OK) - return ERROR_FAIL; - return ERROR_OK; -} - -int riscv_program_dont_restore_register(struct riscv_program *p, enum gdb_regno r) -{ - assert(r < RISCV_REGISTER_COUNT); - p->writes_xreg[r] = 0; - return ERROR_OK; -} - -int riscv_program_do_restore_register(struct riscv_program *p, enum gdb_regno r) -{ - assert(r < RISCV_REGISTER_COUNT); - p->writes_xreg[r] = 1; - return ERROR_OK; -} - -enum gdb_regno riscv_program_gettemp(struct riscv_program *p) -{ - for (size_t i = GDB_REGNO_S0; i <= GDB_REGNO_XPR31; ++i) { - if (p->in_use[i]) continue; - - riscv_program_do_restore_register(p, i); - p->in_use[i] = 1; - return i; - } - - LOG_ERROR("You've run out of temporary registers. This is impossible."); - abort(); -} - -void riscv_program_puttemp(struct riscv_program *p, enum gdb_regno r) -{ - assert(r < RISCV_REGISTER_COUNT); - p->in_use[r] = 0; -} - -/* Helper functions. */ -riscv_addr_t riscv_program_gah(struct riscv_program *p, riscv_addr_t addr) -{ - return addr >> 12; -} - -riscv_addr_t riscv_program_gal(struct riscv_program *p, riscv_addr_t addr) -{ - if (addr > 0) { - return (addr & 0x7FF); - } else { - return 0; - } -} - -int riscv_program_lah(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr) -{ - riscv_addr_t ah = riscv_program_gah(p, addr); - if (ah == 0) - return ERROR_OK; - return riscv_program_lui(p, d, ah); -} - -int riscv_program_lal(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr) -{ - riscv_addr_t al = riscv_program_gal(p, addr); - if (al == 0) - return ERROR_OK; - return riscv_program_addi(p, d, d, al); -} - int riscv_program_insert(struct riscv_program *p, riscv_insn_t i) { if (p->instruction_count >= riscv_debug_buffer_size(p->target)) { diff --git a/src/target/riscv/program.h b/src/target/riscv/program.h index 56a1a9a0a..d641be1be 100644 --- a/src/target/riscv/program.h +++ b/src/target/riscv/program.h @@ -21,10 +21,6 @@ struct riscv_program { /* Side effects of executing this program. These must be accounted for * in order to maintain correct executing of the target system. */ bool writes_xreg[RISCV_REGISTER_COUNT]; - bool writes_memory; - - /* When a register is used it will be set in this array. */ - bool in_use[RISCV_REGISTER_COUNT]; /* XLEN on the target. */ int target_xlen; @@ -59,60 +55,21 @@ int riscv_program_save_to_dscratch(struct riscv_program *p, enum gdb_regno to_sa /* Helpers to assembly various instructions. Return 0 on success. These might * assembly into a multi-instruction sequence that overwrites some other * register, but those will be properly saved and restored. */ -int riscv_program_lx(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr); -int riscv_program_ld(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr); -int riscv_program_lw(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr); -int riscv_program_lh(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr); -int riscv_program_lb(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr); - -int riscv_program_sx(struct riscv_program *p, enum gdb_regno s, riscv_addr_t addr); -int riscv_program_sd(struct riscv_program *p, enum gdb_regno s, riscv_addr_t addr); -int riscv_program_sw(struct riscv_program *p, enum gdb_regno s, riscv_addr_t addr); -int riscv_program_sh(struct riscv_program *p, enum gdb_regno s, riscv_addr_t addr); -int riscv_program_sb(struct riscv_program *p, enum gdb_regno s, riscv_addr_t addr); - -int riscv_program_lxr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno a, int o); -int riscv_program_ldr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno a, int o); int riscv_program_lwr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno a, int o); int riscv_program_lhr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno a, int o); int riscv_program_lbr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno a, int o); -int riscv_program_sxr(struct riscv_program *p, enum gdb_regno s, enum gdb_regno a, int o); -int riscv_program_sdr(struct riscv_program *p, enum gdb_regno s, enum gdb_regno a, int o); int riscv_program_swr(struct riscv_program *p, enum gdb_regno s, enum gdb_regno a, int o); int riscv_program_shr(struct riscv_program *p, enum gdb_regno s, enum gdb_regno a, int o); int riscv_program_sbr(struct riscv_program *p, enum gdb_regno s, enum gdb_regno a, int o); int riscv_program_csrr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno csr); int riscv_program_csrw(struct riscv_program *p, enum gdb_regno s, enum gdb_regno csr); -int riscv_program_csrrw(struct riscv_program *p, enum gdb_regno d, enum gdb_regno s, enum gdb_regno csr); int riscv_program_fence_i(struct riscv_program *p); int riscv_program_fence(struct riscv_program *p); int riscv_program_ebreak(struct riscv_program *p); -int riscv_program_lui(struct riscv_program *p, enum gdb_regno d, int32_t u); int riscv_program_addi(struct riscv_program *p, enum gdb_regno d, enum gdb_regno s, int16_t i); -/* Assembler macros. */ -int riscv_program_li(struct riscv_program *p, enum gdb_regno d, riscv_reg_t c); -int riscv_program_la(struct riscv_program *p, enum gdb_regno d, riscv_addr_t a); - -/* Register allocation. The user is expected to have obtained temporary - * registers using these fuctions. Additionally, there is an interface for - * reserving registers -- it's expected that this has been called as the first - * thing in the program's execution to reserve registers that can't be touched - * by the program's execution. */ -enum gdb_regno riscv_program_gettemp(struct riscv_program *p); -void riscv_program_puttemp(struct riscv_program *p, enum gdb_regno r); - -/* Executing a program usually causes the registers that get overwritten to be - * saved and restored. Calling this prevents the given register from actually - * being restored as a result of all activity in this program. */ -int riscv_program_dont_restore_register(struct riscv_program *p, enum gdb_regno r); -int riscv_program_do_restore_register(struct riscv_program *p, enum gdb_regno r); - -/* Addressing functions. */ -riscv_addr_t riscv_program_gah(struct riscv_program *p, riscv_addr_t addr); - #endif From 8432b7cf3da8cf6862d8c86d46812f8b24af8bdf Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Tue, 24 Oct 2017 11:34:48 -0700 Subject: [PATCH 15/20] Remove more unused code. Change-Id: Id91237c163d86e8f4d039503ca33b4ad7571ecd1 --- src/target/riscv/riscv-013.c | 54 ++++-------------------------------- 1 file changed, 6 insertions(+), 48 deletions(-) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 5c81c5512..d536a2dcc 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -31,10 +31,6 @@ static void riscv013_on_step_or_resume(struct target *target, bool step); static void riscv013_step_or_resume_current_hart(struct target *target, bool step); -//static riscv_addr_t riscv013_progbuf_addr(struct target *target); -//static riscv_addr_t riscv013_data_size(struct target *target); -//static riscv_addr_t riscv013_data_addr(struct target *target); -//static int riscv013_debug_buffer_register(struct target *target, riscv_addr_t addr); static void riscv013_clear_abstract_error(struct target *target); /* Implementations of the functions in riscv_info_t. */ @@ -1293,7 +1289,12 @@ static int read_memory(struct target *target, target_addr_t address, struct riscv_program program; riscv_program_init(&program, target); - // TODO: riscv_program_fence(&program); + riscv_program_fence(&program); + if (riscv_program_exec(&program, target) != ERROR_OK) + LOG_ERROR("Unable to execute fence"); + + // New program. + riscv_program_init(&program, target); switch (size) { case 1: riscv_program_lbr(&program, GDB_REGNO_S1, GDB_REGNO_S0, 0); @@ -1953,49 +1954,6 @@ static void riscv013_step_or_resume_current_hart(struct target *target, bool ste abort(); } -#if 0 -riscv_addr_t riscv013_progbuf_addr(struct target *target) -{ - RISCV013_INFO(info); - assert(info->progbuf_addr != -1); - return info->progbuf_addr; -} -#endif - -#if 0 -riscv_addr_t riscv013_data_size(struct target *target) -{ - RISCV013_INFO(info); - if (info->data_size == -1) { - uint32_t acs = dmi_read(target, DMI_HARTINFO); - info->data_size = get_field(acs, DMI_HARTINFO_DATASIZE); - } - return info->data_size; -} -#endif - -#if 0 -riscv_addr_t riscv013_data_addr(struct target *target) -{ - RISCV013_INFO(info); - if (info->data_addr == -1) { - uint32_t acs = dmi_read(target, DMI_HARTINFO); - info->data_addr = get_field(acs, DMI_HARTINFO_DATAACCESS) ? get_field(acs, DMI_HARTINFO_DATAADDR) : 0; - } - return info->data_addr; -} -#endif - -#if 0 -int riscv013_debug_buffer_register(struct target *target, riscv_addr_t addr) -{ - if (addr >= riscv013_data_addr(target)) - return DMI_DATA0 + (addr - riscv013_data_addr(target)) / 4; - else - return DMI_PROGBUF0 + (addr - riscv013_progbuf_addr(target)) / 4; -} -#endif - void riscv013_clear_abstract_error(struct target *target) { // Wait for busy to go away. From 59a03402610bb92c1298586fcef212c17c5d0644 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Tue, 24 Oct 2017 11:38:39 -0700 Subject: [PATCH 16/20] Remove more unused code. Change-Id: I962660f58d948f85df6e073065e15e5d8f4a02b6 --- src/target/riscv/riscv-013.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index d536a2dcc..e9c545878 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -167,9 +167,6 @@ typedef struct { bool need_strict_step; - // Some memoized values - int progbuf_addr, data_addr, data_size; - bool abstract_read_csr_supported; bool abstract_write_csr_supported; bool abstract_read_fpr_supported; @@ -908,9 +905,6 @@ static int init_target(struct command_context *cmd_ctx, riscv013_info_t *info = get_info(target); info->progbufsize = -1; - info->progbuf_addr = -1; - info->data_size = -1; - info->data_addr = -1; info->dmi_busy_delay = 0; info->ac_busy_delay = 0; From dbecbfee997bf7d5aa2daef17f0ef7f30ebdaa6b Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Tue, 24 Oct 2017 12:15:25 -0700 Subject: [PATCH 17/20] Add a fence after memory writes. Change-Id: I5137479b685f735aa573cec5d40170016c40f597 --- src/target/riscv/riscv-013.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index e9c545878..f47428a6b 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -1256,6 +1256,16 @@ static void write_to_buf(uint8_t *buffer, uint64_t value, unsigned size) } } +static int execute_fence(struct target *target) { + struct riscv_program program; + riscv_program_init(&program, target); + riscv_program_fence(&program); + int result = riscv_program_exec(&program, target); + if (result != ERROR_OK) + LOG_ERROR("Unable to execute fence"); + return result; +} + /** * Read the requested memory, taking care to execute every read exactly once, * even if cmderr=busy is encountered. @@ -1279,16 +1289,12 @@ static int read_memory(struct target *target, target_addr_t address, if (register_read_direct(target, &s1, GDB_REGNO_S1) != ERROR_OK) return ERROR_FAIL; + if (execute_fence(target) != ERROR_OK) + return ERROR_FAIL; + // Write the program (load, increment) struct riscv_program program; riscv_program_init(&program, target); - - riscv_program_fence(&program); - if (riscv_program_exec(&program, target) != ERROR_OK) - LOG_ERROR("Unable to execute fence"); - - // New program. - riscv_program_init(&program, target); switch (size) { case 1: riscv_program_lbr(&program, GDB_REGNO_S1, GDB_REGNO_S0, 0); @@ -1649,6 +1655,9 @@ static int write_memory(struct target *target, target_addr_t address, if (register_write_direct(target, GDB_REGNO_S0, s0) != ERROR_OK) return ERROR_FAIL; + if (execute_fence(target) != ERROR_OK) + return ERROR_FAIL; + return ERROR_OK; } From 23bd6d08c9444ef36789f0355e78833dc45fc3f5 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Tue, 24 Oct 2017 15:11:33 -0700 Subject: [PATCH 18/20] Remove more unused functionality. Change-Id: I43283b9556c959f891a587fb39bdd1ab9206e8af --- src/target/riscv/riscv-013.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index f47428a6b..5ff4a6ffe 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -1839,17 +1839,11 @@ static enum riscv_halt_reason riscv013_halt_reason(struct target *target) void riscv013_write_debug_buffer(struct target *target, unsigned index, riscv_insn_t data) { - RISCV013_INFO(info); - if (index >= info->progbufsize) - return dmi_write(target, DMI_DATA0 + index - info->progbufsize, data); return dmi_write(target, DMI_PROGBUF0 + index, data); } riscv_insn_t riscv013_read_debug_buffer(struct target *target, unsigned index) { - RISCV013_INFO(info); - if (index >= info->progbufsize) - return dmi_read(target, DMI_DATA0 + index - info->progbufsize); return dmi_read(target, DMI_PROGBUF0 + index); } From db754536e8f4fe2edd92c5c0961c8346e2b8882d Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Fri, 27 Oct 2017 13:15:22 -0700 Subject: [PATCH 19/20] Support 64-bit FPRs on RV32. Because there is no instruction that moves just half of a 64-bit FPR to/from a GPR, we need to use scratch memory for this operation. This code can theoretically use: 1. DMI_DATA, if it is memory mapped in the target. 2. DMI_PROGBUF, if it is writable in the target. 3. A user-configured address. I have only tested this code very lightly. One reason is that gdb thinks that on RV32 harts every register is 32 bits wide. Another is that this is mostly proof-of-concept to satisfy the small program buffer code review, which I don't want to drag out forever. Existing tests don't realize that floating support was broken with RV32D, and don't realize that it still doesn't work because of the gdb problem mentioned above. This change improves Issue #110 but there's more work to be done. Change-Id: I99b8a36e5fea26f1d9e16e36cf99adc7be26b944 --- src/target/riscv/riscv-013.c | 312 ++++++++++++++++++++++++++++++++--- src/target/riscv/riscv.c | 49 +++++- src/target/riscv/riscv.h | 3 + 3 files changed, 329 insertions(+), 35 deletions(-) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 5ff4a6ffe..efcc89520 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -28,6 +28,7 @@ #include "batch.h" #define DMI_DATA1 (DMI_DATA0 + 1) +#define DMI_PROGBUF1 (DMI_PROGBUF0 + 1) static void riscv013_on_step_or_resume(struct target *target, bool step); static void riscv013_step_or_resume_current_hart(struct target *target, bool step); @@ -55,6 +56,12 @@ static void riscv013_fill_dmi_read_u64(struct target *target, char *buf, int a); static int riscv013_dmi_write_u64_bits(struct target *target); static void riscv013_fill_dmi_nop_u64(struct target *target, char *buf); static int register_read_direct(struct target *target, uint64_t *value, uint32_t number); +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); +static int write_memory(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, const uint8_t *buffer); /** * Since almost everything can be accomplish by scanning the dbus register, all @@ -127,6 +134,12 @@ struct memory_cache_line { bool dirty; }; +typedef enum { + YNM_MAYBE, + YNM_YES, + YNM_NO +} yes_no_maybe_t; + typedef struct { /* Number of address bits in the dbus register. */ unsigned abits; @@ -143,6 +156,10 @@ typedef struct { * reg_cache. */ uint64_t mstatus_actual; + yes_no_maybe_t progbuf_writable; + /* We only need the address so that we know the alignment of the buffer. */ + riscv_addr_t progbuf_address; + /* Single buffer that contains all register names, instead of calling * malloc for each register. Needs to be freed when reg_list is freed. */ char *reg_names; @@ -175,7 +192,12 @@ typedef struct { // When a function returns some error due to a failure indicated by the // target in cmderr, the caller can look here to see what that error was. // (Compare with errno.) - unsigned cmderr; + uint8_t cmderr; + + // Some fields from hartinfo. + uint8_t datasize; + uint8_t dataaccess; + int16_t dataaddr; } riscv013_info_t; static void decode_dmi(char *text, unsigned address, unsigned data) @@ -737,6 +759,200 @@ static int register_write_abstract(struct target *target, uint32_t number, return ERROR_OK; } +static int examine_progbuf(struct target *target) +{ + riscv013_info_t *info = get_info(target); + + if (info->progbuf_writable != YNM_MAYBE) + return ERROR_OK; + + // Figure out if progbuf is writable. + + if (info->progbufsize < 1) { + info->progbuf_writable = YNM_NO; + LOG_INFO("No program buffer present."); + return ERROR_OK; + } + + uint64_t s0; + if (register_read_direct(target, &s0, GDB_REGNO_S0) != ERROR_OK) + return ERROR_FAIL; + + struct riscv_program program; + riscv_program_init(&program, target); + riscv_program_insert(&program, auipc(S0)); + if (riscv_program_exec(&program, target) != ERROR_OK) + return ERROR_FAIL; + + if (register_read_direct(target, &info->progbuf_address, GDB_REGNO_S0) != ERROR_OK) + return ERROR_FAIL; + + riscv_program_init(&program, target); + riscv_program_insert(&program, sw(S0, S0, 0)); + int result = riscv_program_exec(&program, target); + + if (register_write_direct(target, GDB_REGNO_S0, s0) != ERROR_OK) + return ERROR_FAIL; + + if (result != ERROR_OK) { + // This program might have failed if the program buffer is not + // writable. + info->progbuf_writable = YNM_NO; + return ERROR_OK; + } + + uint32_t written = dmi_read(target, DMI_PROGBUF0); + if (written == (uint32_t) info->progbuf_address) { + LOG_INFO("progbuf is writable at 0x%" TARGET_PRIxADDR, + info->progbuf_address); + info->progbuf_writable = YNM_YES; + + } else { + LOG_INFO("progbuf is not writeable at 0x%" TARGET_PRIxADDR, + info->progbuf_address); + info->progbuf_writable = YNM_NO; + } + + return ERROR_OK; +} + +typedef enum { + SPACE_DMI_DATA, + SPACE_DMI_PROGBUF, + SPACE_DMI_RAM +} memory_space_t; + +typedef struct { + // How can the debugger access this memory? + memory_space_t memory_space; + // Memory address to access the scratch memory from the hart. + riscv_addr_t hart_address; + // Memory address to access the scratch memory from the debugger. + riscv_addr_t debug_address; +} scratch_mem_t; + +/** + * Find some scratch memory to be used with the given program. + */ +static int scratch_find(struct target *target, + scratch_mem_t *scratch, + struct riscv_program *program, + unsigned size_bytes) +{ + riscv013_info_t *info = get_info(target); + + riscv_addr_t alignment = 1; + while (alignment < size_bytes) + alignment *= 2; + + if (info->dataaccess == 1) { + // Sign extend dataaddr. + scratch->hart_address = info->dataaddr; + if (info->dataaddr & (1<<11)) { + scratch->hart_address |= 0xfffffffffffff000ULL; + } + // Align. + scratch->hart_address = (scratch->hart_address + alignment - 1) & ~(alignment - 1); + + if ((size_bytes + scratch->hart_address - info->dataaddr + 3) / 4 >= + info->datasize) { + scratch->memory_space = SPACE_DMI_DATA; + scratch->debug_address = (scratch->hart_address - info->dataaddr) / 4; + return ERROR_OK; + } + } + + if (examine_progbuf(target) != ERROR_OK) + return ERROR_FAIL; + + // Allow for ebreak at the end of the program. + unsigned program_size = (program->instruction_count + 1 ) * 4; + scratch->hart_address = (info->progbuf_address + program_size + alignment - 1) & + ~(alignment - 1); + if ((size_bytes + scratch->hart_address - info->progbuf_address + 3) / 4 >= + info->progbufsize) { + scratch->memory_space = SPACE_DMI_PROGBUF; + scratch->debug_address = (scratch->hart_address - info->progbuf_address) / 4; + return ERROR_OK; + } + + if (riscv_use_scratch_ram) { + scratch->hart_address = (riscv_use_scratch_ram + alignment - 1) & + ~(alignment - 1); + scratch->memory_space = SPACE_DMI_RAM; + scratch->debug_address = scratch->hart_address; + } + + LOG_ERROR("Couldn't find %d bytes of scratch RAM to use. Please configure " + "an address with 'riscv set_scratch_ram'.", size_bytes); + return ERROR_FAIL; +} + +static int scratch_read64(struct target *target, scratch_mem_t *scratch, + uint64_t *value) +{ + switch (scratch->memory_space) { + case SPACE_DMI_DATA: + *value = dmi_read(target, DMI_DATA0 + scratch->debug_address); + *value |= ((uint64_t) dmi_read(target, DMI_DATA1 + + scratch->debug_address)) << 32; + break; + case SPACE_DMI_PROGBUF: + *value = dmi_read(target, DMI_PROGBUF0 + scratch->debug_address); + *value |= ((uint64_t) dmi_read(target, DMI_PROGBUF1 + + scratch->debug_address)) << 32; + break; + case SPACE_DMI_RAM: + { + uint8_t buffer[8]; + if (read_memory(target, scratch->debug_address, 4, 2, buffer) != ERROR_OK) + return ERROR_FAIL; + *value = buffer[0] | + (((uint64_t) buffer[1]) << 8) | + (((uint64_t) buffer[2]) << 16) | + (((uint64_t) buffer[3]) << 24) | + (((uint64_t) buffer[4]) << 32) | + (((uint64_t) buffer[5]) << 40) | + (((uint64_t) buffer[6]) << 48) | + (((uint64_t) buffer[7]) << 56); + } + break; + } + return ERROR_OK; +} + +static int scratch_write64(struct target *target, scratch_mem_t *scratch, + uint64_t value) +{ + switch (scratch->memory_space) { + case SPACE_DMI_DATA: + dmi_write(target, DMI_DATA0 + scratch->debug_address, value); + dmi_write(target, DMI_DATA1 + scratch->debug_address, value >> 32); + break; + case SPACE_DMI_PROGBUF: + dmi_write(target, DMI_PROGBUF0 + scratch->debug_address, value); + dmi_write(target, DMI_PROGBUF1 + scratch->debug_address, value >> 32); + break; + case SPACE_DMI_RAM: + { + uint8_t buffer[8] = { + value, + value >> 8, + value >> 16, + value >> 24, + value >> 32, + value >> 40, + value >> 48, + value >> 56 + }; + if (write_memory(target, scratch->debug_address, 4, 2, buffer) != ERROR_OK) + return ERROR_FAIL; + } + break; + } + return ERROR_OK; +} + static int register_write_direct(struct target *target, unsigned number, uint64_t value) { @@ -749,33 +965,49 @@ static int register_write_direct(struct target *target, unsigned number, return ERROR_OK; struct riscv_program program; - riscv_program_init(&program, target); uint64_t s0; if (register_read_direct(target, &s0, GDB_REGNO_S0) != ERROR_OK) return ERROR_FAIL; - if (register_write_direct(target, GDB_REGNO_S0, value) != ERROR_OK) - return ERROR_FAIL; + if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31 && + supports_extension(target, 'D') && + riscv_xlen(target) < 64) { + /* There are no instructions to move all the bits from a register, so + * we need to use some scratch RAM. */ + riscv_program_insert(&program, fld(number - GDB_REGNO_FPR0, S0, 0)); + + scratch_mem_t scratch; + if (scratch_find(target, &scratch, &program, 8) != ERROR_OK) + return ERROR_FAIL; + + if (register_write_direct(target, GDB_REGNO_S0, scratch.hart_address) + != ERROR_OK) + return ERROR_FAIL; + + if (scratch_write64(target, &scratch, value) != ERROR_OK) + return ERROR_FAIL; - if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { - if (supports_extension(target, 'D') && riscv_xlen(target) >= 64) { - riscv_program_insert(&program, fmv_d_x(number - GDB_REGNO_FPR0, S0)); - } else { - riscv_program_insert(&program, fmv_s_x(number - GDB_REGNO_FPR0, S0)); - } - } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) { - riscv_program_csrw(&program, S0, number); } else { - LOG_ERROR("Unsupported register (enum gdb_regno)(%d)", number); - abort(); + if (register_write_direct(target, GDB_REGNO_S0, value) != ERROR_OK) + return ERROR_FAIL; + + if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { + if (supports_extension(target, 'D')) { + riscv_program_insert(&program, fmv_d_x(number - GDB_REGNO_FPR0, S0)); + } else { + riscv_program_insert(&program, fmv_s_x(number - GDB_REGNO_FPR0, S0)); + } + } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) { + riscv_program_csrw(&program, S0, number); + } else { + LOG_ERROR("Unsupported register (enum gdb_regno)(%d)", number); + abort(); + } } int exec_out = riscv_program_exec(&program, target); - if (exec_out != ERROR_OK) { - riscv013_clear_abstract_error(target); - } // Restore S0. if (register_write_direct(target, GDB_REGNO_S0, s0) != ERROR_OK) @@ -791,21 +1023,38 @@ static int register_read_direct(struct target *target, uint64_t *value, uint32_t riscv_xlen(target)); if (result != ERROR_OK) { + assert(number != GDB_REGNO_S0); + result = ERROR_OK; struct riscv_program program; riscv_program_init(&program, target); - assert(number != GDB_REGNO_S0); + + scratch_mem_t scratch; + bool use_scratch = false; uint64_t s0; if (register_read_direct(target, &s0, GDB_REGNO_S0) != ERROR_OK) return ERROR_FAIL; // Write program to move data into s0. + if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { // TODO: Possibly set F in mstatus. - // TODO: Fully support D extension on RV32. - if (supports_extension(target, 'D') && riscv_xlen(target) >= 64) { + if (supports_extension(target, 'D') && riscv_xlen(target) < 64) { + /* There are no instructions to move all the bits from a + * register, so we need to use some scratch RAM. */ + riscv_program_insert(&program, fsd(number - GDB_REGNO_FPR0, S0, + 0)); + + if (scratch_find(target, &scratch, &program, 8) != ERROR_OK) + return ERROR_FAIL; + use_scratch = true; + + if (register_write_direct(target, GDB_REGNO_S0, + scratch.hart_address) != ERROR_OK) + return ERROR_FAIL; + } else if (supports_extension(target, 'D')) { riscv_program_insert(&program, fmv_x_d(S0, number - GDB_REGNO_FPR0)); } else { riscv_program_insert(&program, fmv_x_s(S0, number - GDB_REGNO_FPR0)); @@ -819,13 +1068,16 @@ static int register_read_direct(struct target *target, uint64_t *value, uint32_t // Execute program. result = riscv_program_exec(&program, target); - if (result != ERROR_OK) { - riscv013_clear_abstract_error(target); + + if (use_scratch) { + if (scratch_read64(target, &scratch, value) != ERROR_OK) + return ERROR_FAIL; + } else { + // Read S0 + if (register_read_direct(target, value, GDB_REGNO_S0) != ERROR_OK) + return ERROR_FAIL; } - // Read S0 - if (register_read_direct(target, value, GDB_REGNO_S0) != ERROR_OK) - return ERROR_FAIL; // Restore S0. if (register_write_direct(target, GDB_REGNO_S0, s0) != ERROR_OK) return ERROR_FAIL; @@ -993,7 +1245,6 @@ static int examine(struct target *target) info->abits = get_field(dtmcontrol, DTM_DTMCS_ABITS); info->dtmcontrol_idle = get_field(dtmcontrol, DTM_DTMCS_IDLE); - uint32_t dmcontrol = dmi_read(target, DMI_DMCONTROL); uint32_t dmstatus = dmi_read(target, DMI_DMSTATUS); if (get_field(dmstatus, DMI_DMSTATUS_VERSION) != 2) { LOG_ERROR("OpenOCD only supports Debug Module version 2, not %d " @@ -1004,10 +1255,17 @@ static int examine(struct target *target) // Reset the Debug Module. dmi_write(target, DMI_DMCONTROL, 0); dmi_write(target, DMI_DMCONTROL, DMI_DMCONTROL_DMACTIVE); - dmcontrol = dmi_read(target, DMI_DMCONTROL); + uint32_t dmcontrol = dmi_read(target, DMI_DMCONTROL); + + uint32_t hartinfo = dmi_read(target, DMI_HARTINFO); LOG_DEBUG("dmcontrol: 0x%08x", dmcontrol); LOG_DEBUG("dmstatus: 0x%08x", dmstatus); + LOG_DEBUG("hartinfo: 0x%08x", hartinfo); + + info->datasize = get_field(hartinfo, DMI_HARTINFO_DATASIZE); + info->dataaccess = get_field(hartinfo, DMI_HARTINFO_DATAACCESS); + info->dataaddr = get_field(hartinfo, DMI_HARTINFO_DATAADDR); if (!get_field(dmcontrol, DMI_DMCONTROL_DMACTIVE)) { LOG_ERROR("Debug Module did not become active. dmcontrol=0x%x", diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 820094da3..b9be133f3 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -200,6 +200,9 @@ int riscv_command_timeout_sec = DEFAULT_COMMAND_TIMEOUT_SEC; /* Wall-clock timeout after reset. Settable via RISC-V Target commands.*/ int riscv_reset_timeout_sec = DEFAULT_RESET_TIMEOUT_SEC; +bool riscv_use_scratch_ram = false; +uint64_t riscv_scratch_ram_address = 0; + static uint32_t dtmcontrol_scan(struct target *target, uint32_t out) { struct scan_field field; @@ -1120,8 +1123,8 @@ int riscv_openocd_step( } /* Command Handlers */ -COMMAND_HANDLER(riscv_set_command_timeout_sec) { - +COMMAND_HANDLER(riscv_set_command_timeout_sec) +{ if (CMD_ARGC != 1) { LOG_ERROR("Command takes exactly 1 parameter"); return ERROR_COMMAND_SYNTAX_ERROR; @@ -1137,11 +1140,11 @@ COMMAND_HANDLER(riscv_set_command_timeout_sec) { return ERROR_OK; } -COMMAND_HANDLER(riscv_set_reset_timeout_sec) { - +COMMAND_HANDLER(riscv_set_reset_timeout_sec) +{ if (CMD_ARGC != 1) { - LOG_ERROR("Command takes exactly 1 parameter"); - return ERROR_COMMAND_SYNTAX_ERROR; + LOG_ERROR("Command takes exactly 1 parameter"); + return ERROR_COMMAND_SYNTAX_ERROR; } int timeout = atoi(CMD_ARGV[0]); if (timeout <= 0){ @@ -1153,6 +1156,29 @@ COMMAND_HANDLER(riscv_set_reset_timeout_sec) { return ERROR_OK; } +COMMAND_HANDLER(riscv_set_scratch_ram) +{ + if (CMD_ARGC != 1) { + LOG_ERROR("Command takes exactly 1 parameter"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + if (!strcmp(CMD_ARGV[0], "none")) { + riscv_use_scratch_ram = false; + return ERROR_OK; + } + + long long unsigned int address; + int result = sscanf(CMD_ARGV[0], "%Lx", &address); + if (result != (int) strlen(CMD_ARGV[0])) { + LOG_ERROR("%s is not a valid address for command.", CMD_ARGV[0]); + riscv_use_scratch_ram = false; + return ERROR_FAIL; + } + + riscv_scratch_ram_address = address; + riscv_use_scratch_ram = true; + return ERROR_OK; +} static const struct command_registration riscv_exec_command_handlers[] = { { @@ -1161,14 +1187,21 @@ static const struct command_registration riscv_exec_command_handlers[] = { .mode = COMMAND_ANY, .usage = "riscv set_command_timeout_sec [sec]", .help = "Set the wall-clock timeout (in seconds) for individual commands" - }, - { + }, + { .name = "set_reset_timeout_sec", .handler = riscv_set_reset_timeout_sec, .mode = COMMAND_ANY, .usage = "riscv set_reset_timeout_sec [sec]", .help = "Set the wall-clock timeout (in seconds) after reset is deasserted" }, + { + .name = "set_scratch_ram", + .handler = riscv_set_scratch_ram, + .mode = COMMAND_ANY, + .usage = "riscv set_scratch_ram none|[address]", + .help = "Set address of 16 bytes of scratch RAM the debugger can use, or 'none'." + }, COMMAND_REGISTRATION_DONE }; diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h index f19f06c4c..4ff61270f 100644 --- a/src/target/riscv/riscv.h +++ b/src/target/riscv/riscv.h @@ -111,6 +111,9 @@ extern int riscv_command_timeout_sec; /* Wall-clock timeout after reset. Settable via RISC-V Target commands.*/ extern int riscv_reset_timeout_sec; +extern bool riscv_use_scratch_ram; +extern uint64_t riscv_scratch_ram_address; + /* Everything needs the RISC-V specific info structure, so here's a nice macro * that provides that. */ static inline riscv_info_t *riscv_info(const struct target *target) __attribute__((unused)); From 52cdf286cae5bf31b1d55730c5020b8920f79db2 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Thu, 16 Nov 2017 15:58:08 -0800 Subject: [PATCH 20/20] Add missing return. Change-Id: Ida32482903cdfd8eeb043088e84bb1f4f5ac673c --- src/target/riscv/riscv-013.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 8f7dc6adf..1768b6220 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -877,6 +877,7 @@ static int scratch_find(struct target *target, ~(alignment - 1); scratch->memory_space = SPACE_DMI_RAM; scratch->debug_address = scratch->hart_address; + return ERROR_OK; } LOG_ERROR("Couldn't find %d bytes of scratch RAM to use. Please configure "