Faster download.

16K testcase:
Transfer rate: 53 KB/sec, 2222 bytes/write.
This commit is contained in:
Tim Newsome 2016-06-20 16:02:13 -07:00
parent 9aab0aa068
commit 668070cc45
1 changed files with 163 additions and 48 deletions

View File

@ -468,7 +468,7 @@ static int cache_write(struct target *target, unsigned int address, bool run)
buf_set_u64(out + 8*scan, DBUS_ADDRESS_START, info->addrbits, i);
jtag_add_dr_scan(target->tap, 1, &field[scan], TAP_IDLE);
jtag_add_runtest(1 + info->dbus_busy_count / 10, TAP_IDLE);
jtag_add_runtest(1 + info->dbus_busy_count, TAP_IDLE);
LOG_DEBUG("write scan=%d result=%d data=%09lx address=%02x",
scan,
@ -492,7 +492,7 @@ static int cache_write(struct target *target, unsigned int address, bool run)
buf_set_u64(out + 8*scan, DBUS_ADDRESS_START, info->addrbits, address);
jtag_add_dr_scan(target->tap, 1, &field[scan], TAP_IDLE);
jtag_add_runtest(1 + info->dbus_busy_count / 10 + info->interrupt_high_count / 10, TAP_IDLE);
jtag_add_runtest(1 + info->dbus_busy_count + info->interrupt_high_count, TAP_IDLE);
scan++;
@ -507,7 +507,7 @@ static int cache_write(struct target *target, unsigned int address, bool run)
buf_set_u64(out + 8*scan, DBUS_ADDRESS_START, info->addrbits, address);
jtag_add_dr_scan(target->tap, 1, &field[scan], TAP_IDLE);
jtag_add_runtest(1 + info->dbus_busy_count / 10, TAP_IDLE);
jtag_add_runtest(1 + info->dbus_busy_count, TAP_IDLE);
scan++;
@ -685,6 +685,17 @@ static int write_csr(struct target *target, uint32_t csr, uint32_t value)
return ERROR_OK;
}
static int write_gpr(struct target *target, unsigned int gpr, uint32_t value)
{
cache_set(target, 0, lw(gpr, ZERO, DEBUG_RAM_START + 16));
cache_set_jump(target, 1);
cache_set(target, 4, value);
if (cache_write(target, 4, true) != ERROR_OK) {
return ERROR_FAIL;
}
return ERROR_OK;
}
static int resume(struct target *target, int current, uint32_t address,
int handle_breakpoints, int debug_execution, bool step)
{
@ -1400,23 +1411,36 @@ static int riscv_read_memory(struct target *target, uint32_t address,
return ERROR_OK;
}
#if 1
static int riscv_write_memory(struct target *target, uint32_t address,
uint32_t size, uint32_t count, const uint8_t *buffer)
static void add_dbus_scan(struct target *target, struct scan_field *field,
uint8_t *out_value, uint8_t *in_value, dbus_op_t op, uint16_t address,
uint64_t data)
{
jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE);
riscv_info_t *info = (riscv_info_t *) target->arch_info;
// Set up the address.
cache_set(target, 0, sw(T0, ZERO, DEBUG_RAM_START + 20));
cache_set(target, 1, lw(T0, ZERO, DEBUG_RAM_START + 16));
cache_set_jump(target, 2);
cache_set(target, 4, address);
if (cache_write(target, 5, true) != ERROR_OK) {
return ERROR_FAIL;
LOG_DEBUG("op=%d address=0x%02x data=0x%09lx", op, address, data);
field->num_bits = info->addrbits + DBUS_OP_SIZE + DBUS_DATA_SIZE;
field->in_value = in_value;
field->out_value = out_value;
buf_set_u64(out_value, DBUS_OP_START, DBUS_OP_SIZE, op);
buf_set_u64(out_value, DBUS_DATA_START, DBUS_DATA_SIZE, data);
buf_set_u64(out_value, DBUS_ADDRESS_START, info->addrbits, address);
jtag_add_dr_scan(target->tap, 1, field, TAP_IDLE);
// TODO: 1 should come from the dtminfo register
int idle_count = 1 + info->dbus_busy_count;
if (data & DMCONTROL_INTERRUPT) {
idle_count += info->interrupt_high_count;
}
uint32_t t0 = dram_read32(target, 5);
jtag_add_runtest(idle_count, TAP_IDLE);
}
#if 1
static int setup_write_memory(struct target *target, uint32_t size)
{
switch (size) {
case 1:
cache_set(target, 0, lb(S0, ZERO, DEBUG_RAM_START + 16));
@ -1438,11 +1462,50 @@ static int riscv_write_memory(struct target *target, uint32_t address,
cache_set_jump(target, 3);
cache_write(target, 4, false);
return ERROR_OK;
}
static int riscv_write_memory(struct target *target, uint32_t address,
uint32_t size, uint32_t count, const uint8_t *buffer)
{
riscv_info_t *info = (riscv_info_t *) target->arch_info;
jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE);
// Set up the address.
cache_set(target, 0, sw(T0, ZERO, DEBUG_RAM_START + 20));
cache_set(target, 1, lw(T0, ZERO, DEBUG_RAM_START + 16));
cache_set_jump(target, 2);
cache_set(target, 4, address);
if (cache_write(target, 5, true) != ERROR_OK) {
return ERROR_FAIL;
}
uint32_t t0 = dram_read32(target, 5);
if (setup_write_memory(target, size) != ERROR_OK) {
return ERROR_FAIL;
}
#define MAX_BATCH_SIZE 256
uint8_t *in = malloc(MAX_BATCH_SIZE * 8);
uint8_t *out = malloc(MAX_BATCH_SIZE * 8);
struct scan_field *field = calloc(MAX_BATCH_SIZE, sizeof(struct scan_field));
uint32_t i = 0;
while (i < count) {
while (i < count + 1) {
unsigned int batch_size = MIN(count + 1 - i, MAX_BATCH_SIZE);
for (unsigned int j = 0; j < batch_size; j++) {
if (i + j == count) {
// Just insert a read so we can confirm that the last scan
// succeeded.
add_dbus_scan(target, &field[j], out + 8*j, in + 8*j,
DBUS_OP_READ, info->dramsize-1, DMCONTROL_HALTNOT | 0);
} else {
// Write the next value and set interrupt.
uint32_t value;
uint32_t offset = size * i;
uint32_t offset = size * (i + j);
switch (size) {
case 1:
value = buffer[offset];
@ -1458,26 +1521,78 @@ static int riscv_write_memory(struct target *target, uint32_t address,
((uint32_t) buffer[offset+3] << 24);
break;
default:
return ERROR_FAIL;
goto error;
}
dbus_status_t status = dbus_scan(target, NULL, NULL,
DBUS_OP_CONDITIONAL_WRITE, 4,
DMCONTROL_HALTNOT | DMCONTROL_INTERRUPT | value);
if (status == DBUS_STATUS_SUCCESS) {
i++;
} else if (status == DBUS_STATUS_NO_WRITE) {
// Need to retry the access that failed, which was the previous one.
i--;
} else if (status == DBUS_STATUS_BUSY) {
// This operation may still complete. Retry the current access.
} else if (status == DBUS_STATUS_FAILED) {
LOG_ERROR("dbus write failed!");
return ERROR_FAIL;
add_dbus_scan(target, &field[j], out + 8*j, in + 8*j,
DBUS_OP_CONDITIONAL_WRITE, 4, DMCONTROL_HALTNOT | DMCONTROL_INTERRUPT | value);
}
}
int retval = jtag_execute_queue();
if (retval != ERROR_OK) {
LOG_ERROR("JTAG execute failed: %d", retval);
goto error;
}
int dbus_busy = 0;
int execute_busy = 0;
for (unsigned int j = 0; j < batch_size; j++) {
dbus_status_t status = buf_get_u32(in + 8*j, DBUS_OP_START, DBUS_OP_SIZE);
switch (status) {
case DBUS_STATUS_SUCCESS:
break;
case DBUS_STATUS_NO_WRITE:
execute_busy++;
break;
case DBUS_STATUS_FAILED:
LOG_ERROR("Debug RAM write failed. Hardware error?");
goto error;
case DBUS_STATUS_BUSY:
dbus_busy++;
break;
}
LOG_DEBUG("j=%d data=%09lx", j, buf_get_u64(in + 8*j, DBUS_DATA_START, DBUS_DATA_SIZE));
}
if (dbus_busy) {
info->dbus_busy_count++;
LOG_INFO("Increment dbus_busy_count to %d", info->dbus_busy_count);
}
if (execute_busy) {
info->interrupt_high_count++;
LOG_INFO("Increment interrupt_high_count to %d", info->interrupt_high_count);
}
if (dbus_busy || execute_busy) {
wait_for_debugint_clear(target, false);
// Retry.
// Set t0 back to what it should have been at the beginning of this
// batch.
LOG_INFO("Retrying memory write starting from 0x%x with more delays", address + size * i);
if (write_gpr(target, T0, address + size * i) != ERROR_OK) {
goto error;
}
if (setup_write_memory(target, size) != ERROR_OK) {
goto error;
}
} else {
i += batch_size;
}
}
free(in);
free(out);
free(field);
return register_write(target, T0, t0);
error:
free(in);
free(out);
free(field);
return ERROR_FAIL;
}
#else
/** Inefficient implementation that doesn't require conditional writes. */