Faster download.
16K testcase: Transfer rate: 53 KB/sec, 2222 bytes/write.
This commit is contained in:
parent
9aab0aa068
commit
668070cc45
|
@ -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. */
|
||||||
|
|
Loading…
Reference in New Issue