target/riscv: Don't always read on DMI batch write (#768)
Indicate to the JTAG driver that it does not need to read and return the DR register value after scanning the JTAG chain. riscv_batch_run(), calls jtag_add_dr_scan() to schedule a DR scan operation. Eventually, this will result in the JTAG driver performing a JTAG scan to write to or read from DR. The decision on whether to write to and/or read from DR register is determined by the second parameter to jtag_add_dr_scan(), i.e. a "struct scan_field". Of particular interest here is if batch->fields[i]->in_value is not NULL, the JTAG developer must return the DR value collected from the JTAG scan operation. When creating the DR scan operation instruction with riscv_batch_add_dmi_write(), batch->fields[i]->in_value points to a location in batch->data_in buffer, meaning batch->field[i]->in_value is not NULL, and the JTAG developer must therefore read and return the DR value collected. The returning of the DR value is redundant in a write operation. This patch set batch->fields[i]->in_value to NULL to indicate the DR value need not be returned. This allows the JTAG developer to optimize away any code associated with returning the DR value. Normally, the extra work to return the DR value is negligible. However, in one usecase it introduces significant delays In this use case a JTAG driver forwards all JTAG scan to a server on a network. If the server has to return the DR value, it has to perform the JTAG scan before replying to the JTAG driver, and only then the JTAG driver can send the next JTAG scan operation. However, if there is no need to return the DR value, the server can acknowledge the JTAG operation request immediately,thus signalling to the JTAG driver that it is free to send the next JTAG scan operation. At the same time of receiving the second JTAG operation the server will process the original JTAG scan. This saves time and mitigates network delay. Also, not having to include the DR value in resulting in smaller reply packet from server to JTAG driver and save on network traffic. This doubles download speeds to spike using remote bitbang. Change-Id: Ibb37c3e32af0cc7006b22b8c4e1f31ed29c21d0f Signed-off-by: Ooi, Cinly <cinly.ooi@intel.com> Signed-off-by: Tim Newsome <tim@sifive.com> Signed-off-by: Ooi, Cinly <cinly.ooi@intel.com> Signed-off-by: Tim Newsome <tim@sifive.com> Co-authored-by: Ooi, Cinly <cinly.ooi@intel.com>
This commit is contained in:
parent
8ae41e86e1
commit
bec0fe2236
|
@ -125,15 +125,20 @@ int riscv_batch_run(struct riscv_batch *batch)
|
|||
return ERROR_OK;
|
||||
}
|
||||
|
||||
void riscv_batch_add_dmi_write(struct riscv_batch *batch, unsigned address, uint64_t data)
|
||||
void riscv_batch_add_dmi_write(struct riscv_batch *batch, unsigned address, uint64_t data,
|
||||
bool read_back)
|
||||
{
|
||||
assert(batch->used_scans < batch->allocated_scans);
|
||||
struct scan_field *field = batch->fields + batch->used_scans;
|
||||
field->num_bits = riscv_dmi_write_u64_bits(batch->target);
|
||||
field->out_value = (void *)(batch->data_out + batch->used_scans * DMI_SCAN_BUF_SIZE);
|
||||
field->in_value = (void *)(batch->data_in + batch->used_scans * DMI_SCAN_BUF_SIZE);
|
||||
riscv_fill_dmi_write_u64(batch->target, (char *)field->out_value, address, data);
|
||||
riscv_fill_dmi_nop_u64(batch->target, (char *)field->in_value);
|
||||
if (read_back) {
|
||||
field->in_value = (void *)(batch->data_in + batch->used_scans * DMI_SCAN_BUF_SIZE);
|
||||
riscv_fill_dmi_nop_u64(batch->target, (char *)field->in_value);
|
||||
} else {
|
||||
field->in_value = NULL;
|
||||
}
|
||||
batch->last_scan = RISCV_SCAN_TYPE_WRITE;
|
||||
batch->used_scans++;
|
||||
}
|
||||
|
|
|
@ -59,7 +59,8 @@ bool riscv_batch_full(struct riscv_batch *batch);
|
|||
int riscv_batch_run(struct riscv_batch *batch);
|
||||
|
||||
/* Adds a DMI write to this batch. */
|
||||
void riscv_batch_add_dmi_write(struct riscv_batch *batch, unsigned address, uint64_t data);
|
||||
void riscv_batch_add_dmi_write(struct riscv_batch *batch, unsigned address, uint64_t data,
|
||||
bool read_back);
|
||||
|
||||
/* DMI reads must be handled in two parts: the first one schedules a read and
|
||||
* provides a key, the second one actually obtains the result of the read -
|
||||
|
|
|
@ -2188,7 +2188,7 @@ static int sample_memory_bus_v1(struct target *target,
|
|||
sbcs_write |= DM_SBCS_SBREADONDATA;
|
||||
sbcs_write |= sb_sbaccess(config->bucket[i].size_bytes);
|
||||
if (!sbcs_valid || sbcs_write != sbcs) {
|
||||
riscv_batch_add_dmi_write(batch, DM_SBCS, sbcs_write);
|
||||
riscv_batch_add_dmi_write(batch, DM_SBCS, sbcs_write, true);
|
||||
sbcs = sbcs_write;
|
||||
sbcs_valid = true;
|
||||
}
|
||||
|
@ -2197,13 +2197,13 @@ static int sample_memory_bus_v1(struct target *target,
|
|||
(!sbaddress1_valid ||
|
||||
sbaddress1 != config->bucket[i].address >> 32)) {
|
||||
sbaddress1 = config->bucket[i].address >> 32;
|
||||
riscv_batch_add_dmi_write(batch, DM_SBADDRESS1, sbaddress1);
|
||||
riscv_batch_add_dmi_write(batch, DM_SBADDRESS1, sbaddress1, true);
|
||||
sbaddress1_valid = true;
|
||||
}
|
||||
if (!sbaddress0_valid ||
|
||||
sbaddress0 != (config->bucket[i].address & 0xffffffff)) {
|
||||
sbaddress0 = config->bucket[i].address;
|
||||
riscv_batch_add_dmi_write(batch, DM_SBADDRESS0, sbaddress0);
|
||||
riscv_batch_add_dmi_write(batch, DM_SBADDRESS0, sbaddress0, true);
|
||||
sbaddress0_valid = true;
|
||||
}
|
||||
if (config->bucket[i].size_bytes > 4)
|
||||
|
@ -3742,20 +3742,20 @@ static int write_memory_bus_v1(struct target *target, target_addr_t address,
|
|||
((uint32_t) p[12]) |
|
||||
(((uint32_t) p[13]) << 8) |
|
||||
(((uint32_t) p[14]) << 16) |
|
||||
(((uint32_t) p[15]) << 24));
|
||||
(((uint32_t) p[15]) << 24), false);
|
||||
|
||||
if (size > 8)
|
||||
riscv_batch_add_dmi_write(batch, DM_SBDATA2,
|
||||
((uint32_t) p[8]) |
|
||||
(((uint32_t) p[9]) << 8) |
|
||||
(((uint32_t) p[10]) << 16) |
|
||||
(((uint32_t) p[11]) << 24));
|
||||
(((uint32_t) p[11]) << 24), false);
|
||||
if (size > 4)
|
||||
riscv_batch_add_dmi_write(batch, DM_SBDATA1,
|
||||
((uint32_t) p[4]) |
|
||||
(((uint32_t) p[5]) << 8) |
|
||||
(((uint32_t) p[6]) << 16) |
|
||||
(((uint32_t) p[7]) << 24));
|
||||
(((uint32_t) p[7]) << 24), false);
|
||||
uint32_t value = p[0];
|
||||
if (size > 2) {
|
||||
value |= ((uint32_t) p[2]) << 16;
|
||||
|
@ -3763,7 +3763,7 @@ static int write_memory_bus_v1(struct target *target, target_addr_t address,
|
|||
}
|
||||
if (size > 1)
|
||||
value |= ((uint32_t) p[1]) << 8;
|
||||
riscv_batch_add_dmi_write(batch, DM_SBDATA0, value);
|
||||
riscv_batch_add_dmi_write(batch, DM_SBDATA0, value, false);
|
||||
|
||||
log_memory_access(address + i * size, value, size, false);
|
||||
next_address += size;
|
||||
|
@ -3967,8 +3967,8 @@ static int write_memory_progbuf(struct target *target, target_addr_t address,
|
|||
setup_needed = false;
|
||||
} else {
|
||||
if (size > 4)
|
||||
riscv_batch_add_dmi_write(batch, DM_DATA1, value >> 32);
|
||||
riscv_batch_add_dmi_write(batch, DM_DATA0, value);
|
||||
riscv_batch_add_dmi_write(batch, DM_DATA1, value >> 32, false);
|
||||
riscv_batch_add_dmi_write(batch, DM_DATA0, value, false);
|
||||
if (riscv_batch_full(batch))
|
||||
break;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue