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:
Tim Newsome 2022-11-17 11:34:27 -08:00 committed by GitHub
parent 8ae41e86e1
commit bec0fe2236
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 19 additions and 13 deletions

View File

@ -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++;
}

View File

@ -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 -

View File

@ -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;
}