Use reg_cache structure, to make reg command work.

Change-Id: I9f1d1f2eab66822c3c47284aa91b52cc34998381
This commit is contained in:
Tim Newsome 2016-10-20 10:42:28 -07:00
parent 4eba841bfe
commit 9b0be80d1e
1 changed files with 78 additions and 64 deletions

View File

@ -160,7 +160,6 @@ typedef struct {
struct memory_cache_line dram_cache[DRAM_CACHE_SIZE]; struct memory_cache_line dram_cache[DRAM_CACHE_SIZE];
struct reg *reg_list;
/* Single buffer that contains all register names, instead of calling /* Single buffer that contains all register names, instead of calling
* malloc for each register. Needs to be freed when reg_list is freed. */ * malloc for each register. Needs to be freed when reg_list is freed. */
char *reg_names; char *reg_names;
@ -188,9 +187,6 @@ typedef struct {
// before the interrupt is cleared. // before the interrupt is cleared.
unsigned int interrupt_high_delay; unsigned int interrupt_high_delay;
// This cache is write-through, and always valid when the target is halted.
uint64_t gpr_cache[32];
bool need_strict_step; bool need_strict_step;
bool never_halted; bool never_halted;
} riscv_info_t; } riscv_info_t;
@ -1123,9 +1119,7 @@ static int execute_resume(struct target *target, bool step)
} }
target->state = TARGET_RUNNING; target->state = TARGET_RUNNING;
for (unsigned int i = 0; i < 32; i++) { register_cache_invalidate(target->reg_cache);
info->gpr_cache[i] = 0xbadbad;
}
return ERROR_OK; return ERROR_OK;
} }
@ -1188,7 +1182,7 @@ static void update_reg_list(struct target *target)
info->reg_values = malloc(REG_COUNT * info->xlen / 4); info->reg_values = malloc(REG_COUNT * info->xlen / 4);
for (unsigned int i = 0; i < REG_COUNT; i++) { for (unsigned int i = 0; i < REG_COUNT; i++) {
struct reg *r = &info->reg_list[i]; struct reg *r = &target->reg_cache->reg_list[i];
r->value = info->reg_values + i * info->xlen / 4; r->value = info->reg_values + i * info->xlen / 4;
if (r->dirty) { if (r->dirty) {
LOG_ERROR("Register %d was dirty. Its value is lost.", i); LOG_ERROR("Register %d was dirty. Its value is lost.", i);
@ -1202,6 +1196,24 @@ static void update_reg_list(struct target *target)
} }
} }
static uint64_t reg_cache_get(struct target *target, unsigned int number)
{
struct reg *r = &target->reg_cache->reg_list[number];
assert(r->valid);
uint64_t value = buf_get_u64(r->value, 0, r->size);
LOG_DEBUG("%s = 0x%" PRIx64, r->name, value);
return value;
}
static void reg_cache_set(struct target *target, unsigned int number,
uint64_t value)
{
struct reg *r = &target->reg_cache->reg_list[number];
LOG_DEBUG("%s <= 0x%" PRIx64, r->name, value);
r->valid = true;
buf_set_u64(r->value, 0, r->size, value);
}
/*** OpenOCD target functions. ***/ /*** OpenOCD target functions. ***/
static int register_get(struct reg *reg) static int register_get(struct reg *reg)
@ -1212,8 +1224,8 @@ static int register_get(struct reg *reg)
maybe_write_tselect(target); maybe_write_tselect(target);
if (reg->number <= REG_XPR31) { if (reg->number <= REG_XPR31) {
buf_set_u64(reg->value, 0, info->xlen, info->gpr_cache[reg->number]); buf_set_u64(reg->value, 0, info->xlen, reg_cache_get(target, reg->number));
LOG_DEBUG("%s=0x%" PRIx64, reg->name, info->gpr_cache[reg->number]); LOG_DEBUG("%s=0x%" PRIx64, reg->name, reg_cache_get(target, reg->number));
return ERROR_OK; return ERROR_OK;
} else if (reg->number == REG_PC) { } else if (reg->number == REG_PC) {
buf_set_u32(reg->value, 0, 32, info->dpc); buf_set_u32(reg->value, 0, 32, info->dpc);
@ -1240,13 +1252,6 @@ static int register_get(struct reg *reg)
return ERROR_FAIL; return ERROR_FAIL;
} }
uint64_t value = cache_get(target, SLOT0);
if (reg->number < 32 && info->gpr_cache[reg->number] != value) {
LOG_ERROR("cached value for %s is 0x%" PRIx64 " but just read 0x%" PRIx64,
reg->name, info->gpr_cache[reg->number], value);
assert(info->gpr_cache[reg->number] == value);
}
uint32_t exception = cache_get32(target, info->dramsize-1); uint32_t exception = cache_get32(target, info->dramsize-1);
if (exception) { if (exception) {
LOG_ERROR("Got exception 0x%x when reading register %d", exception, LOG_ERROR("Got exception 0x%x when reading register %d", exception,
@ -1254,6 +1259,7 @@ static int register_get(struct reg *reg)
return ERROR_FAIL; return ERROR_FAIL;
} }
uint64_t value = cache_get(target, SLOT0);
LOG_DEBUG("%s=0x%" PRIx64, reg->name, value); LOG_DEBUG("%s=0x%" PRIx64, reg->name, value);
buf_set_u64(reg->value, 0, info->xlen, value); buf_set_u64(reg->value, 0, info->xlen, value);
@ -1313,9 +1319,9 @@ static int register_set(struct reg *reg, uint8_t *buf)
uint64_t value = buf_get_u64(buf, 0, info->xlen); uint64_t value = buf_get_u64(buf, 0, info->xlen);
LOG_DEBUG("write 0x%" PRIx64 " to %s", value, reg->name); LOG_DEBUG("write 0x%" PRIx64 " to %s", value, reg->name);
if (reg->number <= REG_XPR31) { struct reg *r = &target->reg_cache->reg_list[reg->number];
info->gpr_cache[reg->number] = value; r->valid = true;
} memcpy(r->value, buf, (r->size + 7) / 8);
return register_write(target, reg->number, value); return register_write(target, reg->number, value);
} }
@ -1338,15 +1344,19 @@ static int riscv_init_target(struct command_context *cmd_ctx,
select_dbus.num_bits = target->tap->ir_length; select_dbus.num_bits = target->tap->ir_length;
select_idcode.num_bits = target->tap->ir_length; select_idcode.num_bits = target->tap->ir_length;
const unsigned int max_reg_name_len = 12; target->reg_cache = calloc(1, sizeof(*target->reg_cache));
info->reg_list = calloc(REG_COUNT, sizeof(struct reg)); target->reg_cache->name = "RISC-V registers";
target->reg_cache->num_regs = REG_COUNT;
target->reg_cache->reg_list = calloc(REG_COUNT, sizeof(struct reg));
const unsigned int max_reg_name_len = 12;
info->reg_names = calloc(1, REG_COUNT * max_reg_name_len); info->reg_names = calloc(1, REG_COUNT * max_reg_name_len);
char *reg_name = info->reg_names; char *reg_name = info->reg_names;
info->reg_values = NULL; info->reg_values = NULL;
for (unsigned int i = 0; i < REG_COUNT; i++) { for (unsigned int i = 0; i < REG_COUNT; i++) {
struct reg *r = &info->reg_list[i]; struct reg *r = &target->reg_cache->reg_list[i];
r->number = i; r->number = i;
r->caller_save = true; r->caller_save = true;
r->dirty = false; r->dirty = false;
@ -1866,7 +1876,8 @@ static riscv_error_t handle_halt_routine(struct target *target)
unsigned int dbus_busy = 0; unsigned int dbus_busy = 0;
unsigned int interrupt_set = 0; unsigned int interrupt_set = 0;
unsigned result = 0; unsigned result = 0;
info->gpr_cache[0] = 0; uint64_t value = 0;
reg_cache_set(target, 0, 0);
// The first scan result is the result from something old we don't care // The first scan result is the result from something old we don't care
// about. // about.
for (unsigned int i = 1; i < scans->next_scan && dbus_busy == 0; i++) { for (unsigned int i = 1; i < scans->next_scan && dbus_busy == 0; i++) {
@ -1893,60 +1904,65 @@ static riscv_error_t handle_halt_routine(struct target *target)
break; break;
} }
if (address == 4 || address == 5) { if (address == 4 || address == 5) {
uint64_t *vptr = NULL; unsigned int reg;
switch (result) { switch (result) {
case 0: vptr = &info->gpr_cache[1]; break; case 0: reg = 1; break;
case 1: vptr = &info->gpr_cache[2]; break; case 1: reg = 2; break;
case 2: vptr = &info->gpr_cache[3]; break; case 2: reg = 3; break;
case 3: vptr = &info->gpr_cache[4]; break; case 3: reg = 4; break;
case 4: vptr = &info->gpr_cache[5]; break; case 4: reg = 5; break;
case 5: vptr = &info->gpr_cache[6]; break; case 5: reg = 6; break;
case 6: vptr = &info->gpr_cache[7]; break; case 6: reg = 7; break;
// S0 // S0
// S1 // S1
case 7: vptr = &info->gpr_cache[10]; break; case 7: reg = 10; break;
case 8: vptr = &info->gpr_cache[11]; break; case 8: reg = 11; break;
case 9: vptr = &info->gpr_cache[12]; break; case 9: reg = 12; break;
case 10: vptr = &info->gpr_cache[13]; break; case 10: reg = 13; break;
case 11: vptr = &info->gpr_cache[14]; break; case 11: reg = 14; break;
case 12: vptr = &info->gpr_cache[15]; break; case 12: reg = 15; break;
case 13: vptr = &info->gpr_cache[16]; break; case 13: reg = 16; break;
case 14: vptr = &info->gpr_cache[17]; break; case 14: reg = 17; break;
case 15: vptr = &info->gpr_cache[18]; break; case 15: reg = 18; break;
case 16: vptr = &info->gpr_cache[19]; break; case 16: reg = 19; break;
case 17: vptr = &info->gpr_cache[20]; break; case 17: reg = 20; break;
case 18: vptr = &info->gpr_cache[21]; break; case 18: reg = 21; break;
case 19: vptr = &info->gpr_cache[22]; break; case 19: reg = 22; break;
case 20: vptr = &info->gpr_cache[23]; break; case 20: reg = 23; break;
case 21: vptr = &info->gpr_cache[24]; break; case 21: reg = 24; break;
case 22: vptr = &info->gpr_cache[25]; break; case 22: reg = 25; break;
case 23: vptr = &info->gpr_cache[26]; break; case 23: reg = 26; break;
case 24: vptr = &info->gpr_cache[27]; break; case 24: reg = 27; break;
case 25: vptr = &info->gpr_cache[28]; break; case 25: reg = 28; break;
case 26: vptr = &info->gpr_cache[29]; break; case 26: reg = 29; break;
case 27: vptr = &info->gpr_cache[30]; break; case 27: reg = 30; break;
case 28: vptr = &info->gpr_cache[31]; break; case 28: reg = 31; break;
case 29: vptr = &info->gpr_cache[S1]; break; case 29: reg = S1; break;
case 30: vptr = &info->gpr_cache[S0]; break; case 30: reg = S0; break;
case 31: vptr = &info->dpc; break; case 31: reg = CSR_DPC; break;
case 32: vptr = &info->dcsr; break; case 32: reg = CSR_DCSR; break;
default: default:
assert(0); assert(0);
} }
if (info->xlen == 32) { if (info->xlen == 32) {
*vptr = data & 0xffffffff; reg_cache_set(target, reg, data & 0xffffffff);
result++; result++;
} else if (info->xlen == 64) { } else if (info->xlen == 64) {
if (address == 4) { if (address == 4) {
*vptr = data & 0xffffffff; value = data & 0xffffffff;
} else if (address == 5) { } else if (address == 5) {
*vptr |= (data & 0xffffffff) << 32; reg_cache_set(target, reg, ((data & 0xffffffff) << 32) | value);
value = 0;
result++; result++;
} }
} }
} }
} }
// TODO: get rid of those 2 variables and talk to the cache directly.
info->dpc = reg_cache_get(target, CSR_DPC);
info->dcsr = reg_cache_get(target, CSR_DCSR);
scans = scans_delete(scans); scans = scans_delete(scans);
cache_invalidate(target); cache_invalidate(target);
@ -2458,8 +2474,6 @@ static int riscv_get_gdb_reg_list(struct target *target,
struct reg **reg_list[], int *reg_list_size, struct reg **reg_list[], int *reg_list_size,
enum target_register_class reg_class) enum target_register_class reg_class)
{ {
riscv_info_t *info = (riscv_info_t *) target->arch_info;
LOG_DEBUG("reg_class=%d", reg_class); LOG_DEBUG("reg_class=%d", reg_class);
switch (reg_class) { switch (reg_class) {
@ -2479,7 +2493,7 @@ static int riscv_get_gdb_reg_list(struct target *target,
return ERROR_FAIL; return ERROR_FAIL;
} }
for (int i = 0; i < *reg_list_size; i++) { for (int i = 0; i < *reg_list_size; i++) {
(*reg_list)[i] = &info->reg_list[i]; (*reg_list)[i] = &target->reg_cache->reg_list[i];
} }
return ERROR_OK; return ERROR_OK;