From e6221e75c9c0daaa7a8cc6dcc25e3731b1b9779d Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Fri, 10 Feb 2017 19:08:44 -0800 Subject: [PATCH] Attempt to discover XLEN with abstract reg reads Change-Id: I7ce9c8c0c34bd875dba11596e6f6268320b2fb3a --- src/target/riscv/opcodes.h | 35 ++++++-- src/target/riscv/riscv-013.c | 159 +++++++++++++++++++---------------- src/target/riscv/riscv.c | 27 ------ src/target/riscv/riscv.h | 5 ++ 4 files changed, 118 insertions(+), 108 deletions(-) diff --git a/src/target/riscv/opcodes.h b/src/target/riscv/opcodes.h index 07eb8537e..eb76455c3 100644 --- a/src/target/riscv/opcodes.h +++ b/src/target/riscv/opcodes.h @@ -5,13 +5,6 @@ #define S0 8 #define S1 9 -/* - * Disabling the warning we get when some opcodes functions aren't used. Not - * every user of this file uses every function, and it doesn't make sense to - * make them global. I suppose they could be macros. - */ -#pragma GCC diagnostic ignored "-Wunused-function" - static uint32_t bits(uint32_t value, unsigned int hi, unsigned int lo) { return (value >> lo) & ((1 << (hi+1-lo)) - 1); } @@ -20,6 +13,7 @@ static uint32_t bit(uint32_t value, unsigned int b) { return (value >> b) & 1; } +static uint32_t jal(unsigned int rd, uint32_t imm) __attribute__ ((unused)); static uint32_t jal(unsigned int rd, uint32_t imm) { return (bit(imm, 20) << 31) | (bits(imm, 10, 1) << 21) | @@ -29,12 +23,14 @@ static uint32_t jal(unsigned int rd, uint32_t imm) { MATCH_JAL; } +static uint32_t csrsi(unsigned int csr, uint16_t imm) __attribute__ ((unused)); static uint32_t csrsi(unsigned int csr, uint16_t imm) { return (csr << 20) | (bits(imm, 4, 0) << 15) | MATCH_CSRRSI; } +static uint32_t sw(unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused)); static uint32_t sw(unsigned int src, unsigned int base, uint16_t offset) { return (bits(offset, 11, 5) << 25) | @@ -44,6 +40,7 @@ static uint32_t sw(unsigned int src, unsigned int base, uint16_t offset) MATCH_SW; } +static uint32_t sd(unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused)); static uint32_t sd(unsigned int src, unsigned int base, uint16_t offset) { return (bits(offset, 11, 5) << 25) | @@ -53,6 +50,7 @@ static uint32_t sd(unsigned int src, unsigned int base, uint16_t offset) MATCH_SD; } +static uint32_t sh(unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused)); static uint32_t sh(unsigned int src, unsigned int base, uint16_t offset) { return (bits(offset, 11, 5) << 25) | @@ -62,6 +60,7 @@ static uint32_t sh(unsigned int src, unsigned int base, uint16_t offset) MATCH_SH; } +static uint32_t sb(unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused)); static uint32_t sb(unsigned int src, unsigned int base, uint16_t offset) { return (bits(offset, 11, 5) << 25) | @@ -71,6 +70,7 @@ static uint32_t sb(unsigned int src, unsigned int base, uint16_t offset) MATCH_SB; } +static uint32_t ld(unsigned int rd, unsigned int base, uint16_t offset) __attribute__ ((unused)); static uint32_t ld(unsigned int rd, unsigned int base, uint16_t offset) { return (bits(offset, 11, 0) << 20) | @@ -79,6 +79,7 @@ static uint32_t ld(unsigned int rd, unsigned int base, uint16_t offset) MATCH_LD; } +static uint32_t lw(unsigned int rd, unsigned int base, uint16_t offset) __attribute__ ((unused)); static uint32_t lw(unsigned int rd, unsigned int base, uint16_t offset) { return (bits(offset, 11, 0) << 20) | @@ -87,6 +88,7 @@ static uint32_t lw(unsigned int rd, unsigned int base, uint16_t offset) MATCH_LW; } +static uint32_t lh(unsigned int rd, unsigned int base, uint16_t offset) __attribute__ ((unused)); static uint32_t lh(unsigned int rd, unsigned int base, uint16_t offset) { return (bits(offset, 11, 0) << 20) | @@ -95,6 +97,7 @@ static uint32_t lh(unsigned int rd, unsigned int base, uint16_t offset) MATCH_LH; } +static uint32_t lb(unsigned int rd, unsigned int base, uint16_t offset) __attribute__ ((unused)); static uint32_t lb(unsigned int rd, unsigned int base, uint16_t offset) { return (bits(offset, 11, 0) << 20) | @@ -103,10 +106,12 @@ static uint32_t lb(unsigned int rd, unsigned int base, uint16_t offset) MATCH_LB; } +static uint32_t csrw(unsigned int source, unsigned int csr) __attribute__ ((unused)); static uint32_t csrw(unsigned int source, unsigned int csr) { return (csr << 20) | (source << 15) | MATCH_CSRRW; } +static uint32_t addi(unsigned int dest, unsigned int src, uint16_t imm) __attribute__ ((unused)); static uint32_t addi(unsigned int dest, unsigned int src, uint16_t imm) { return (bits(imm, 11, 0) << 20) | @@ -115,10 +120,12 @@ static uint32_t addi(unsigned int dest, unsigned int src, uint16_t imm) MATCH_ADDI; } +static uint32_t csrr(unsigned int rd, unsigned int csr) __attribute__ ((unused)); static uint32_t csrr(unsigned int rd, unsigned int csr) { return (csr << 20) | (rd << 7) | MATCH_CSRRS; } +static uint32_t fsw(unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused)); static uint32_t fsw(unsigned int src, unsigned int base, uint16_t offset) { return (bits(offset, 11, 5) << 25) | @@ -128,6 +135,7 @@ static uint32_t fsw(unsigned int src, unsigned int base, uint16_t offset) MATCH_FSW; } +static uint32_t fsd(unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused)); static uint32_t fsd(unsigned int src, unsigned int base, uint16_t offset) { return (bits(offset, 11, 5) << 25) | @@ -137,6 +145,7 @@ static uint32_t fsd(unsigned int src, unsigned int base, uint16_t offset) MATCH_FSD; } +static uint32_t flw(unsigned int dest, unsigned int base, uint16_t offset) __attribute__ ((unused)); static uint32_t flw(unsigned int dest, unsigned int base, uint16_t offset) { return (bits(offset, 11, 0) << 20) | @@ -145,6 +154,7 @@ static uint32_t flw(unsigned int dest, unsigned int base, uint16_t offset) MATCH_FLW; } +static uint32_t fld(unsigned int dest, unsigned int base, uint16_t offset) __attribute__ ((unused)); static uint32_t fld(unsigned int dest, unsigned int base, uint16_t offset) { return (bits(offset, 11, 0) << 20) | @@ -153,15 +163,19 @@ static uint32_t fld(unsigned int dest, unsigned int base, uint16_t offset) MATCH_FLD; } +static uint32_t ebreak(void) __attribute__ ((unused)); static uint32_t ebreak(void) { return MATCH_EBREAK; } +static uint32_t ebreak_c(void) __attribute__ ((unused)); static uint32_t ebreak_c(void) { return MATCH_C_EBREAK; } +static uint32_t fence_i(void) __attribute__ ((unused)); static uint32_t fence_i(void) { return MATCH_FENCE_I; } /* +static uint32_t lui(unsigned int dest, uint32_t imm) __attribute__ ((unused)); static uint32_t lui(unsigned int dest, uint32_t imm) { return (bits(imm, 19, 0) << 12) | @@ -169,17 +183,20 @@ static uint32_t lui(unsigned int dest, uint32_t imm) MATCH_LUI; } +static uint32_t csrci(unsigned int csr, uint16_t imm) __attribute__ ((unused)); static uint32_t csrci(unsigned int csr, uint16_t imm) { return (csr << 20) | (bits(imm, 4, 0) << 15) | MATCH_CSRRCI; } +static uint32_t li(unsigned int dest, uint16_t imm) __attribute__ ((unused)); static uint32_t li(unsigned int dest, uint16_t imm) { return addi(dest, 0, imm); } +static uint32_t fsd(unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused)); static uint32_t fsd(unsigned int src, unsigned int base, uint16_t offset) { return (bits(offset, 11, 5) << 25) | @@ -189,6 +206,7 @@ static uint32_t fsd(unsigned int src, unsigned int base, uint16_t offset) MATCH_FSD; } +static uint32_t ori(unsigned int dest, unsigned int src, uint16_t imm) __attribute__ ((unused)); static uint32_t ori(unsigned int dest, unsigned int src, uint16_t imm) { return (bits(imm, 11, 0) << 20) | @@ -197,12 +215,14 @@ static uint32_t ori(unsigned int dest, unsigned int src, uint16_t imm) MATCH_ORI; } +static uint32_t nop(void) __attribute__ ((unused)); static uint32_t nop(void) { return addi(0, 0, 0); } */ +static uint32_t xori(unsigned int dest, unsigned int src, uint16_t imm) __attribute__ ((unused)); static uint32_t xori(unsigned int dest, unsigned int src, uint16_t imm) { return (bits(imm, 11, 0) << 20) | @@ -211,6 +231,7 @@ static uint32_t xori(unsigned int dest, unsigned int src, uint16_t imm) MATCH_XORI; } +static uint32_t srli(unsigned int dest, unsigned int src, uint8_t shamt) __attribute__ ((unused)); static uint32_t srli(unsigned int dest, unsigned int src, uint8_t shamt) { return (bits(shamt, 4, 0) << 20) | diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 62edf9a57..f63f28d4f 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -468,6 +468,7 @@ static uint64_t dbus_read(struct target *target, uint16_t address) uint16_t address_in; unsigned i = 0; + dbus_scan(target, &address_in, &value, DBUS_OP_READ, address, 0); do { status = dbus_scan(target, &address_in, &value, DBUS_OP_READ, address, 0); if (status == DBUS_STATUS_BUSY) { @@ -725,19 +726,6 @@ static int wait_for_debugint_clear(struct target *target, bool ignore_first) } } -static int dram_check32(struct target *target, unsigned int index, - uint32_t expected) -{ - uint16_t address = dram_address(index); - uint32_t actual = dbus_read(target, address); - if (expected != actual) { - LOG_ERROR("Wrote 0x%x to Debug RAM at %d, but read back 0x%x", - expected, index, actual); - return ERROR_FAIL; - } - return ERROR_OK; -} - static void cache_set32(struct target *target, unsigned int index, uint32_t data) { riscv013_info_t *info = get_info(target); @@ -813,27 +801,6 @@ static void cache_clean(struct target *target) } } -static int cache_check(struct target *target) -{ - riscv013_info_t *info = get_info(target); - int error = 0; - - for (unsigned int i = 0; i < info->dramsize; i++) { - if (info->dram_cache[i].valid && !info->dram_cache[i].dirty) { - if (dram_check32(target, i, info->dram_cache[i].data) != ERROR_OK) { - error++; - } - } - } - - if (error) { - dump_debug_ram(target); - return ERROR_FAIL; - } - - return ERROR_OK; -} - /** Write cache to the target, and optionally run the program. * Then read the value at address into the cache, assuming address < 128. */ #define CACHE_NO_READ 128 @@ -1770,6 +1737,70 @@ static int step(struct target *target, int current, uint32_t address, return ERROR_OK; } +static int abstract_read_register(struct target *target, + unsigned reg_number, + unsigned width, + uint64_t *result) +{ + uint32_t command = 0; + switch (width) { + case 32: + command = set_field(command, AC_ACCESS_REGISTER_SIZE, 2); + break; + case 64: + command = set_field(command, AC_ACCESS_REGISTER_SIZE, 3); + break; + case 128: + command = set_field(command, AC_ACCESS_REGISTER_SIZE, 4); + break; + default: + LOG_ERROR("Unsupported register width: %d", width); + return ERROR_FAIL; + } + + if (reg_number <= REG_XPR31) { + command |= reg_number + 0x1000 - REG_XPR0; + } else if (reg_number >= REG_CSR0 && reg_number <= REG_CSR4095) { + command |= reg_number - REG_CSR0; + } else if (reg_number >= REG_FPR0 && reg_number <= REG_FPR31) { + command |= reg_number + 0x1020 - REG_FPR0; + } + + dbus_write(target, DMI_COMMAND, command); + + uint32_t abstractcs; + for (unsigned i = 0; i < 256; i++) { + abstractcs = dbus_read(target, DMI_ABSTRACTCS); + if (get_field(abstractcs, DMI_ABSTRACTCS_BUSY) == 0) + break; + } + if (get_field(abstractcs, DMI_ABSTRACTCS_BUSY)) { + LOG_ERROR("Abstract command 0x%x never completed (abstractcs=0x%x)", + command, abstractcs); + return ERROR_FAIL; + } + if (get_field(abstractcs, DMI_ABSTRACTCS_CMDERR)) { + LOG_DEBUG("Abstract command 0x%x ended in error (abstractcs=0x%x)", + command, abstractcs); + return ERROR_FAIL; + } + + if (result) { + *result = 0; + switch (width) { + case 128: + LOG_WARNING("Ignoring top 64 bits from 128-bit register read."); + case 64: + *result |= ((uint64_t) dbus_read(target, DMI_DATA0)) << 32; + case 32: + *result |= dbus_read(target, DMI_DATA0); + break; + } + } + + return ERROR_OK; +} + static int examine(struct target *target) { // Don't need to select dbus, since the first thing we do is read dtmcontrol. @@ -1802,6 +1833,17 @@ static int examine(struct target *target) } uint32_t dmcontrol = dbus_read(target, DMI_DMCONTROL); + if (get_field(dmcontrol, DMI_DMCONTROL_VERSION) != 1) { + LOG_ERROR("OpenOCD only supports Debug Module version 1, not %d " + "(dmcontrol=0x%x)", get_field(dmcontrol, DMI_DMCONTROL_VERSION), dmcontrol); + return ERROR_FAIL; + } + + // Reset the Debug Module. + dbus_write(target, DMI_DMCONTROL, 0); + dbus_write(target, DMI_DMCONTROL, DMI_DMCONTROL_DMACTIVE); + dmcontrol = dbus_read(target, DMI_DMCONTROL); + LOG_DEBUG("dmcontrol: 0x%08x", dmcontrol); LOG_DEBUG(" haltreq=%d", get_field(dmcontrol, DMI_DMCONTROL_HALTREQ)); LOG_DEBUG(" reset=%d", get_field(dmcontrol, DMI_DMCONTROL_RESET)); @@ -1813,9 +1855,9 @@ static int examine(struct target *target) LOG_DEBUG(" authtype=%d", get_field(dmcontrol, DMI_DMCONTROL_AUTHTYPE)); LOG_DEBUG(" version=%d", get_field(dmcontrol, DMI_DMCONTROL_VERSION)); - if (get_field(dmcontrol, DMI_DMCONTROL_VERSION) != 1) { - LOG_ERROR("OpenOCD only supports Debug Module version 1, not %d " - "(dmcontrol=0x%x)", get_field(dmcontrol, DMI_DMCONTROL_VERSION), dmcontrol); + if (!get_field(dmcontrol, DMI_DMCONTROL_DMACTIVE)) { + LOG_ERROR("Debug Module did not become active. dmcontrol=0x%x", + dmcontrol); return ERROR_FAIL; } @@ -1878,46 +1920,15 @@ static int examine(struct target *target) return ERROR_FAIL; } - // Figure out XLEN, and test writing all of Debug RAM while we're at it. - cache_set32(target, 0, xori(S1, ZERO, -1)); - // 0xffffffff 0xffffffff:ffffffff 0xffffffff:ffffffff:ffffffff:ffffffff - cache_set32(target, 1, srli(S1, S1, 31)); - // 0x00000001 0x00000001:ffffffff 0x00000001:ffffffff:ffffffff:ffffffff - cache_set32(target, 2, sw(S1, ZERO, DEBUG_RAM_START)); - cache_set32(target, 3, srli(S1, S1, 31)); - // 0x00000000 0x00000000:00000003 0x00000000:00000003:ffffffff:ffffffff - cache_set32(target, 4, sw(S1, ZERO, DEBUG_RAM_START + 4)); - cache_set_jump(target, 5); - for (unsigned i = 6; i < info->dramsize; i++) { - cache_set32(target, i, i * 0x01020304); - } - - cache_write(target, 0, false); - - // Check that we can actually read/write dram. - if (cache_check(target) != ERROR_OK) { - return ERROR_FAIL; - } - - cache_write(target, 0, true); - cache_invalidate(target); - - uint32_t word0 = cache_get32(target, 0); - uint32_t word1 = cache_get32(target, 1); riscv_info_t *generic_info = (riscv_info_t *) target->arch_info; - if (word0 == 1 && word1 == 0) { - generic_info->xlen = 32; - } else if (word0 == 0xffffffff && word1 == 3) { - generic_info->xlen = 64; - } else if (word0 == 0xffffffff && word1 == 0xffffffff) { + if (abstract_read_register(target, 15, 128, NULL) == ERROR_OK) { generic_info->xlen = 128; - } else { - uint32_t exception = cache_get32(target, info->dramsize-1); - LOG_ERROR("Failed to discover xlen; word0=0x%x, word1=0x%x, exception=0x%x", - word0, word1, exception); - dump_debug_ram(target); - return ERROR_FAIL; + } else if (abstract_read_register(target, 15, 64, NULL) == ERROR_OK) { + generic_info->xlen = 64; + } else if (abstract_read_register(target, 15, 32, NULL) == ERROR_OK) { + generic_info->xlen = 32; } + LOG_DEBUG("Discovered XLEN is %d", xlen(target)); // Update register list to match discovered XLEN. diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 3118e5293..87c808e5c 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -223,33 +223,6 @@ static uint32_t dtmcontrol_scan(struct target *target, uint32_t out) return in; } -static uint32_t idcode_scan(struct target *target) -{ - struct scan_field field; - uint8_t in_value[4]; - - jtag_add_ir_scan(target->tap, &select_idcode, TAP_IDLE); - - field.num_bits = 32; - field.out_value = NULL; - field.in_value = in_value; - jtag_add_dr_scan(target->tap, 1, &field, TAP_IDLE); - - int retval = jtag_execute_queue(); - if (retval != ERROR_OK) { - LOG_ERROR("failed jtag scan: %d", retval); - return retval; - } - - /* Always return to dbus. */ - jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE); - - uint32_t in = buf_get_u32(field.in_value, 0, 32); - LOG_DEBUG("IDCODE: 0x0 -> 0x%x", in); - - return in; -} - static struct target_type *get_target_type(struct target *target) { riscv_info_t *info = (riscv_info_t *) target->arch_info; diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h index 3439a56ea..2589b642b 100644 --- a/src/target/riscv/riscv.h +++ b/src/target/riscv/riscv.h @@ -27,6 +27,8 @@ extern struct scan_field select_idcode; /*** Version-independent functions that we don't want in the main address space. ***/ +static uint32_t load(const struct target *target, unsigned int rd, + unsigned int base, uint16_t offset) __attribute__ ((unused)); static uint32_t load(const struct target *target, unsigned int rd, unsigned int base, uint16_t offset) { @@ -40,6 +42,8 @@ static uint32_t load(const struct target *target, unsigned int rd, assert(0); } +static uint32_t store(const struct target *target, unsigned int src, + unsigned int base, uint16_t offset) __attribute__ ((unused)); static uint32_t store(const struct target *target, unsigned int src, unsigned int base, uint16_t offset) { @@ -53,6 +57,7 @@ static uint32_t store(const struct target *target, unsigned int src, assert(0); } +static unsigned xlen(const struct target *target) __attribute__ ((unused)); static unsigned xlen(const struct target *target) { riscv_info_t *info = (riscv_info_t *) target->arch_info;