Attempt to discover XLEN with abstract reg reads

Change-Id: I7ce9c8c0c34bd875dba11596e6f6268320b2fb3a
This commit is contained in:
Tim Newsome 2017-02-10 19:08:44 -08:00
parent 5e3d9803ab
commit e6221e75c9
4 changed files with 118 additions and 108 deletions

View File

@ -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) |

View File

@ -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.

View File

@ -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;

View File

@ -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;