Single memory reads/writes work.

This commit is contained in:
Tim Newsome 2016-06-09 09:23:49 -07:00
parent 39788e5e6b
commit dce4a992a3
2 changed files with 139 additions and 94 deletions

View File

@ -119,6 +119,7 @@ static uint32_t flw(unsigned int src, unsigned int base, uint16_t offset)
MATCH_FLW; MATCH_FLW;
} }
/*
static uint32_t li(unsigned int dest, uint16_t imm) static uint32_t li(unsigned int dest, uint16_t imm)
{ {
return addi(dest, 0, imm); return addi(dest, 0, imm);
@ -131,7 +132,6 @@ static uint32_t lui(unsigned int dest, uint32_t imm)
MATCH_LUI; MATCH_LUI;
} }
/*
static uint32_t fence_i(void) static uint32_t fence_i(void)
{ {
return MATCH_FENCE_I; return MATCH_FENCE_I;
@ -179,6 +179,7 @@ static uint32_t ori(unsigned int dest, unsigned int src, uint16_t imm)
(dest << 7) | (dest << 7) |
MATCH_ORI; MATCH_ORI;
} }
*/
static uint32_t xori(unsigned int dest, unsigned int src, uint16_t imm) static uint32_t xori(unsigned int dest, unsigned int src, uint16_t imm)
{ {
@ -187,7 +188,6 @@ static uint32_t xori(unsigned int dest, unsigned int src, uint16_t imm)
(dest << 7) | (dest << 7) |
MATCH_XORI; MATCH_XORI;
} }
*/
static uint32_t srli(unsigned int dest, unsigned int src, uint8_t shamt) static uint32_t srli(unsigned int dest, unsigned int src, uint8_t shamt)
{ {

View File

@ -1,4 +1,5 @@
#include <assert.h> #include <assert.h>
#include <stdlib.h>
#include <time.h> #include <time.h>
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
@ -146,6 +147,12 @@ static struct scan_field select_dbus = {
.in_value = NULL, .in_value = NULL,
.out_value = ir_dbus .out_value = ir_dbus
}; };
static uint8_t ir_debug[1] = {0x5};
static struct scan_field select_debug = {
.in_value = NULL,
.out_value = ir_debug
};
#define DEBUG_LENGTH 264
static uint16_t dram_address(unsigned int index) static uint16_t dram_address(unsigned int index)
{ {
@ -155,19 +162,52 @@ static uint16_t dram_address(unsigned int index)
return 0x40 + index - 0x10; return 0x40 + index - 0x10;
} }
#if 0
static int debug_scan(struct target *target)
{
uint8_t in[DIV_ROUND_UP(DEBUG_LENGTH, 8)];
jtag_add_ir_scan(target->tap, &select_debug, TAP_IDLE);
struct scan_field field;
field.num_bits = DEBUG_LENGTH;
field.out_value = NULL;
field.check_value = NULL;
field.check_mask = NULL;
field.in_value = in;
jtag_add_dr_scan(target->tap, 1, &field, TAP_IDLE);
/* Always return to dbus. */
jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE);
jtag_execute_queue();
LOG_DEBUG(" debug_pc=0x%x", buf_get_u32(in, 0, 32));
LOG_DEBUG(" last_returned_data=0x%x", buf_get_u32(in, 32, 32));
LOG_DEBUG(" last_returned_pc=0x%x", buf_get_u32(in, 64, 32));
LOG_DEBUG(" last_requested_pc=0x%x", buf_get_u32(in, 96, 32));
LOG_DEBUG(" last_committed_instruction=0x%x", buf_get_u32(in, 128, 32));
LOG_DEBUG(" last_committed_pc=0x%x", buf_get_u32(in, 160, 32));
LOG_DEBUG(" last_committed_time=0x%lx", buf_get_u64(in, 192, 64));
LOG_DEBUG(" 3bits=0x%x", buf_get_u32(in, 256, 3));
return 0;
}
#endif
static dbus_status_t dbus_scan(struct target *target, uint64_t *data_in, static dbus_status_t dbus_scan(struct target *target, uint64_t *data_in,
dbus_op_t op, uint16_t address, uint64_t data_out) dbus_op_t op, uint16_t address, uint64_t data_out)
{ {
riscv_info_t *info = (riscv_info_t *) target->arch_info; riscv_info_t *info = (riscv_info_t *) target->arch_info;
struct scan_field field;
uint8_t in[8] = {0}; uint8_t in[8] = {0};
uint8_t out[8]; uint8_t out[8];
struct scan_field field = {
.num_bits = info->addrbits + DBUS_OP_SIZE + DBUS_DATA_SIZE,
.out_value = out,
.in_value = in
};
assert(info->addrbits != 0); assert(info->addrbits != 0);
field.num_bits = info->addrbits + DBUS_OP_SIZE + DBUS_DATA_SIZE;
field.out_value = out;
field.in_value = in;
buf_set_u64(out, DBUS_OP_START, DBUS_OP_SIZE, op); buf_set_u64(out, DBUS_OP_START, DBUS_OP_SIZE, op);
buf_set_u64(out, DBUS_DATA_START, DBUS_DATA_SIZE, data_out); buf_set_u64(out, DBUS_DATA_START, DBUS_DATA_SIZE, data_out);
buf_set_u64(out, DBUS_ADDRESS_START, info->addrbits, address); buf_set_u64(out, DBUS_ADDRESS_START, info->addrbits, address);
@ -190,6 +230,15 @@ static dbus_status_t dbus_scan(struct target *target, uint64_t *data_in,
static const char *op_string[] = {"nop", "r", "w", "cw"}; static const char *op_string[] = {"nop", "r", "w", "cw"};
static const char *status_string[] = {"+", "nw", "F", "b"}; static const char *status_string[] = {"+", "nw", "F", "b"};
LOG_DEBUG("vvv $display(\"hardware: dbus scan %db %s %01x:%08x @%02x -> %s %01x:%08x @%02x\");",
field.num_bits,
op_string[buf_get_u32(out, 0, 2)],
buf_get_u32(out, 34, 2), buf_get_u32(out, 2, 32),
buf_get_u32(out, 36, info->addrbits),
status_string[buf_get_u32(in, 0, 2)],
buf_get_u32(in, 34, 2), buf_get_u32(in, 2, 32),
buf_get_u32(in, 36, info->addrbits));
/*
LOG_DEBUG("dbus scan %db %s %01x:%08x @%02x -> %s %01x:%08x @%02x", LOG_DEBUG("dbus scan %db %s %01x:%08x @%02x -> %s %01x:%08x @%02x",
field.num_bits, field.num_bits,
op_string[buf_get_u32(out, 0, 2)], op_string[buf_get_u32(out, 0, 2)],
@ -198,6 +247,10 @@ static dbus_status_t dbus_scan(struct target *target, uint64_t *data_in,
status_string[buf_get_u32(in, 0, 2)], status_string[buf_get_u32(in, 0, 2)],
buf_get_u32(in, 34, 2), buf_get_u32(in, 2, 32), buf_get_u32(in, 34, 2), buf_get_u32(in, 2, 32),
buf_get_u32(in, 36, info->addrbits)); buf_get_u32(in, 36, info->addrbits));
*/
//debug_scan(target);
return buf_get_u64(in, DBUS_OP_START, DBUS_OP_SIZE); return buf_get_u64(in, DBUS_OP_START, DBUS_OP_SIZE);
} }
@ -277,7 +330,7 @@ static void dram_write32(struct target *target, unsigned int index, uint32_t val
info->dram_valid |= (1<<index); info->dram_valid |= (1<<index);
} }
#if 0 #if 1
static int dram_check32(struct target *target, unsigned int index, static int dram_check32(struct target *target, unsigned int index,
uint32_t expected) uint32_t expected)
{ {
@ -515,11 +568,12 @@ static int riscv_init_target(struct command_context *cmd_ctx,
select_dtminfo.num_bits = target->tap->ir_length; select_dtminfo.num_bits = target->tap->ir_length;
select_dbus.num_bits = target->tap->ir_length; select_dbus.num_bits = target->tap->ir_length;
select_debug.num_bits = target->tap->ir_length;
const unsigned int max_reg_name_len = 12; const unsigned int max_reg_name_len = 12;
info->reg_list = calloc(REG_COUNT, sizeof(struct reg)); info->reg_list = calloc(REG_COUNT, sizeof(struct reg));
info->reg_names = malloc(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;
@ -655,6 +709,26 @@ static void megan_sequence(struct target *target)
} }
#endif #endif
#if 0
static void dram_test(struct target *target)
{
uint32_t shadow[16];
for (int j = 0; j < 100; j++) {
LOG_DEBUG("Round %d", j);
for (int i = 0; i < 16; i++) {
shadow[i] = random();
dram_write32(target, i, shadow[i], false);
}
for (int i = 0; i < 16; i++) {
if (dram_check32(target, i, shadow[i]) != ERROR_OK) {
LOG_ERROR("Mismatch! j=%d i=%d", j, i);
}
}
}
}
#endif
static int riscv_examine(struct target *target) static int riscv_examine(struct target *target)
{ {
LOG_DEBUG("riscv_examine()"); LOG_DEBUG("riscv_examine()");
@ -703,7 +777,8 @@ static int riscv_examine(struct target *target)
return ERROR_FAIL; return ERROR_FAIL;
} }
#if 0 //dram_test(target);
// Figure out XLEN. // Figure out XLEN.
dram_write32(target, 0, xori(S1, ZERO, -1), false); dram_write32(target, 0, xori(S1, ZERO, -1), false);
// 0xffffffff 0xffffffff:ffffffff 0xffffffff:ffffffff:ffffffff:ffffffff // 0xffffffff 0xffffffff:ffffffff 0xffffffff:ffffffff:ffffffff:ffffffff
@ -734,66 +809,13 @@ static int riscv_examine(struct target *target)
dram_write_jump(target, 5, true); dram_write_jump(target, 5, true);
#endif #endif
dram_write32(target, info->dramsize - 1, 0xdeadbeef, false);
if (wait_for_debugint_clear(target) != ERROR_OK) { if (wait_for_debugint_clear(target) != ERROR_OK) {
LOG_ERROR("Debug interrupt didn't clear."); LOG_ERROR("Debug interrupt didn't clear.");
return ERROR_FAIL; return ERROR_FAIL;
} }
#else
#if 1
// Blue blue red
dram_write32(target, 1, nop(), false);
dram_write32(target, 4, sw(S1, ZERO, DEBUG_RAM_START + 4), false);
dram_write_jump(target, 0, true);
if (wait_for_debugint_clear(target) != ERROR_OK) {
LOG_ERROR("Debug interrupt didn't clear.");
return ERROR_FAIL;
}
#endif
#if 0
// no effect
dram_write32(target, 1, ~nop(), false);
dram_write32(target, 4, sw(S1, ZERO, DEBUG_RAM_START + 4), false);
dram_write_jump(target, 0, true);
if (wait_for_debugint_clear(target) != ERROR_OK) {
LOG_ERROR("Debug interrupt didn't clear.");
return ERROR_FAIL;
}
#endif
srli(0,0,0);nop(); // TODO
#if 0
// Blue blue red red
dram_write32(target, 0, nop(), false);
dram_write32(target, 1, nop(), false);
dram_write32(target, 2, sw(S1, ZERO, DEBUG_RAM_START), false);
dram_write32(target, 3, srli(S1, S1, 31), false);
dram_write32(target, 4, sw(S1, ZERO, DEBUG_RAM_START + 4), false);
dram_write_jump(target, 5, true);
if (wait_for_debugint_clear(target) != ERROR_OK) {
LOG_ERROR("Debug interrupt didn't clear.");
return ERROR_FAIL;
}
#endif
#if 0
// Blue off red red
dram_write32(target, 0, nop(), false);
dram_write32(target, 1, sw(S1, ZERO, DEBUG_RAM_START), false);
dram_write32(target, 2, srli(S1, S1, 31), false);
dram_write32(target, 3, sw(S1, ZERO, DEBUG_RAM_START + 4), false);
dram_write_jump(target, 4, true);
if (wait_for_debugint_clear(target) != ERROR_OK) {
LOG_ERROR("Debug interrupt didn't clear.");
return ERROR_FAIL;
}
#endif
#endif
#if 0
uint32_t word0 = dram_read32(target, 0); uint32_t word0 = dram_read32(target, 0);
uint32_t word1 = dram_read32(target, 1); uint32_t word1 = dram_read32(target, 1);
if (word0 == 1 && word1 == 0) { if (word0 == 1 && word1 == 0) {
@ -803,43 +825,16 @@ static int riscv_examine(struct target *target)
} else if (word0 == 0xffffffff && word1 == 0xffffffff) { } else if (word0 == 0xffffffff && word1 == 0xffffffff) {
info->xlen = 128; info->xlen = 128;
} else { } else {
LOG_ERROR("Failed to discover xlen; word0=0x%x, word1=0x%x", uint32_t exception = dram_read32(target, info->dramsize-1);
word0, word1); LOG_ERROR("Failed to discover xlen; word0=0x%x, word1=0x%x, exception=0x%x",
word0, word1, exception);
return ERROR_FAIL; return ERROR_FAIL;
} }
LOG_DEBUG("Discovered XLEN is %d", info->xlen); LOG_DEBUG("Discovered XLEN is %d", info->xlen);
#else
info->xlen = 32;
#endif
// Update register list to match discovered XLEN. // Update register list to match discovered XLEN.
update_reg_list(target); update_reg_list(target);
// TODO
// smoke test
//dram_write32(target, 4, 0x700020a0, false);
//dram_write32(target, 0, lw(S0, ZERO, DEBUG_RAM_START + 16), false);
//dram_write32(target, 1, sw(ZERO, S0, 0), false);
//dram_write32(target, 2, jal(ZERO, 0), true);
//dram_write_jump(target, 2, true);
li(0,0); // TODO: remove
dram_write32(target, 0, lui(S0, 0x70002), false);
dram_write32(target, 1, lui(S1, 0xccccc), false);
dram_write32(target, 2, sw(S1, S0, 0xa0), false);
dram_write32(target, 3, jal(ZERO, 0), true);
// 400: 70002437 lui s0,0x70002
// 404: 0a000493 li s1,160
// 408: 0a942023 sw s1,160(s0) # 700020a0 <debug_ram+0x70001ca0>
// 40c: 0000006f j 40c <debug_ram+0xc>
if (wait_for_debugint_clear(target) != ERROR_OK) {
LOG_ERROR("Debug interrupt didn't clear.");
return ERROR_FAIL;
}
dram_read32(target, 4);
target_set_examined(target); target_set_examined(target);
return ERROR_OK; return ERROR_OK;
@ -938,6 +933,8 @@ static int riscv_read_memory(struct target *target, uint32_t address,
uint32_t size, uint32_t count, uint8_t *buffer) uint32_t size, uint32_t count, uint8_t *buffer)
{ {
jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE); jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE);
#if 0
// Plain implementation, where we write the address each time. // Plain implementation, where we write the address each time.
dram_write32(target, 0, lw(S0, ZERO, DEBUG_RAM_START + 16), false); dram_write32(target, 0, lw(S0, ZERO, DEBUG_RAM_START + 16), false);
switch (size) { switch (size) {
@ -996,6 +993,54 @@ static int riscv_read_memory(struct target *target, uint32_t address,
return ERROR_FAIL; return ERROR_FAIL;
} }
} }
#else
dram_write32(target, 0, lw(S0, ZERO, DEBUG_RAM_START + 16), false);
switch (size) {
case 1:
dram_write32(target, 1, lb(S1, S0, 0), false);
dram_write32(target, 2, sw(S1, ZERO, DEBUG_RAM_START + 16), false);
break;
case 2:
dram_write32(target, 1, lh(S1, S0, 0), false);
dram_write32(target, 2, sw(S1, ZERO, DEBUG_RAM_START + 16), false);
break;
case 4:
dram_write32(target, 1, lw(S1, S0, 0), false);
dram_write32(target, 2, sw(S1, ZERO, DEBUG_RAM_START + 16), false);
break;
default:
LOG_ERROR("Unsupported size: %d", size);
return ERROR_FAIL;
}
dram_write_jump(target, 3, false);
for (unsigned int i = 0; i < count; i++) {
dram_write32(target, 4, address + i * size, true);
if (wait_for_debugint_clear(target) != ERROR_OK) {
LOG_ERROR("Debug interrupt didn't clear.");
return ERROR_FAIL;
}
uint32_t value = dram_read32(target, 4);
unsigned int offset = i * size;
switch (size) {
case 1:
buffer[offset] = value & 0xff;
break;
case 2:
buffer[offset] = value & 0xff;
buffer[offset + 1] = (value >> 8) & 0xff;
break;
case 4:
buffer[offset] = value & 0xff;
buffer[offset + 1] = (value >> 8) & 0xff;
buffer[offset + 2] = (value >> 16) & 0xff;
buffer[offset + 3] = (value >> 24) & 0xff;
break;
}
}
#endif
return ERROR_OK; return ERROR_OK;
} }