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); 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_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", LOG_DEBUG("write scan=%d result=%d data=%09lx address=%02x",
scan, 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); 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_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++; 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); 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_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++; scan++;
@ -685,6 +685,17 @@ static int write_csr(struct target *target, uint32_t csr, uint32_t value)
return ERROR_OK; 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, static int resume(struct target *target, int current, uint32_t address,
int handle_breakpoints, int debug_execution, bool step) 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; return ERROR_OK;
} }
#if 1 static void add_dbus_scan(struct target *target, struct scan_field *field,
static int riscv_write_memory(struct target *target, uint32_t address, uint8_t *out_value, uint8_t *in_value, dbus_op_t op, uint16_t address,
uint32_t size, uint32_t count, const uint8_t *buffer) 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. LOG_DEBUG("op=%d address=0x%02x data=0x%09lx", op, address, data);
cache_set(target, 0, sw(T0, ZERO, DEBUG_RAM_START + 20));
cache_set(target, 1, lw(T0, ZERO, DEBUG_RAM_START + 16)); field->num_bits = info->addrbits + DBUS_OP_SIZE + DBUS_DATA_SIZE;
cache_set_jump(target, 2); field->in_value = in_value;
cache_set(target, 4, address); field->out_value = out_value;
if (cache_write(target, 5, true) != ERROR_OK) {
return ERROR_FAIL; 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) { switch (size) {
case 1: case 1:
cache_set(target, 0, lb(S0, ZERO, DEBUG_RAM_START + 16)); cache_set(target, 0, lb(S0, ZERO, DEBUG_RAM_START + 16));
@ -1438,46 +1462,137 @@ static int riscv_write_memory(struct target *target, uint32_t address,
cache_set_jump(target, 3); cache_set_jump(target, 3);
cache_write(target, 4, false); 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; uint32_t i = 0;
while (i < count) { while (i < count + 1) {
// Write the next value and set interrupt. unsigned int batch_size = MIN(count + 1 - i, MAX_BATCH_SIZE);
uint32_t value;
uint32_t offset = size * i; for (unsigned int j = 0; j < batch_size; j++) {
switch (size) { if (i + j == count) {
case 1: // Just insert a read so we can confirm that the last scan
value = buffer[offset]; // succeeded.
break;
case 2: add_dbus_scan(target, &field[j], out + 8*j, in + 8*j,
value = buffer[offset] | DBUS_OP_READ, info->dramsize-1, DMCONTROL_HALTNOT | 0);
(buffer[offset+1] << 8); } else {
break; // Write the next value and set interrupt.
case 4: uint32_t value;
value = buffer[offset] | uint32_t offset = size * (i + j);
((uint32_t) buffer[offset+1] << 8) | switch (size) {
((uint32_t) buffer[offset+2] << 16) | case 1:
((uint32_t) buffer[offset+3] << 24); value = buffer[offset];
break; break;
default: case 2:
return ERROR_FAIL; value = buffer[offset] |
(buffer[offset+1] << 8);
break;
case 4:
value = buffer[offset] |
((uint32_t) buffer[offset+1] << 8) |
((uint32_t) buffer[offset+2] << 16) |
((uint32_t) buffer[offset+3] << 24);
break;
default:
goto error;
}
add_dbus_scan(target, &field[j], out + 8*j, in + 8*j,
DBUS_OP_CONDITIONAL_WRITE, 4, DMCONTROL_HALTNOT | DMCONTROL_INTERRUPT | value);
}
} }
dbus_status_t status = dbus_scan(target, NULL, NULL, int retval = jtag_execute_queue();
DBUS_OP_CONDITIONAL_WRITE, 4, if (retval != ERROR_OK) {
DMCONTROL_HALTNOT | DMCONTROL_INTERRUPT | value); LOG_ERROR("JTAG execute failed: %d", retval);
if (status == DBUS_STATUS_SUCCESS) { goto error;
i++; }
} else if (status == DBUS_STATUS_NO_WRITE) {
// Need to retry the access that failed, which was the previous one. int dbus_busy = 0;
i--; int execute_busy = 0;
} else if (status == DBUS_STATUS_BUSY) { for (unsigned int j = 0; j < batch_size; j++) {
// This operation may still complete. Retry the current access. dbus_status_t status = buf_get_u32(in + 8*j, DBUS_OP_START, DBUS_OP_SIZE);
} else if (status == DBUS_STATUS_FAILED) { switch (status) {
LOG_ERROR("dbus write failed!"); case DBUS_STATUS_SUCCESS:
return ERROR_FAIL; 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); return register_write(target, T0, t0);
error:
free(in);
free(out);
free(field);
return ERROR_FAIL;
} }
#else #else
/** Inefficient implementation that doesn't require conditional writes. */ /** Inefficient implementation that doesn't require conditional writes. */