Skip to content

Commit df5b531

Browse files
committed
target/riscv: DMI logging improvements
Fixes riscv-collab#1043 There were multiple issuese with DMI logging: 1. Address was assumed to be the same (riscv-collab#1043). 2. Reported IDLE count was not affected by a reset of the delays. 3. VLA were used. These issues are addressed in the commit. Change-Id: I82f45505e8a62dfdd7dcb418784975fe10180109 Signed-off-by: Evgeniy Naydanov <[email protected]>
1 parent 7f8c43a commit df5b531

File tree

1 file changed

+89
-55
lines changed

1 file changed

+89
-55
lines changed

src/target/riscv/batch.c

Lines changed: 89 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -132,18 +132,22 @@ static void add_idle_before_batch(const struct riscv_batch *batch, size_t start_
132132
}
133133

134134
static int get_delay(const struct riscv_batch *batch, size_t scan_idx,
135-
const struct riscv_scan_delays *delays)
135+
const struct riscv_scan_delays *delays, bool resets_delays,
136+
size_t reset_delays_after)
136137
{
137138
assert(batch);
138139
assert(scan_idx < batch->used_scans);
140+
const bool delays_were_reset = resets_delays
141+
&& (scan_idx >= reset_delays_after);
139142
const enum riscv_scan_delay_class delay_class =
140143
batch->delay_classes[scan_idx];
141144
const unsigned int delay = riscv_scan_get_delay(delays, delay_class);
142145
assert(delay <= INT_MAX);
143-
return delay;
146+
return delays_were_reset ? 0 : delay;
144147
}
145148

146-
static unsigned int decode_dmi(const struct target *target, char *text, uint32_t address, uint32_t data)
149+
static unsigned int decode_dmi(const struct riscv_batch *batch, char *text,
150+
uint32_t address, uint32_t data)
147151
{
148152
static const struct {
149153
uint32_t address;
@@ -157,7 +161,8 @@ static unsigned int decode_dmi(const struct target *target, char *text, uint32_t
157161
};
158162

159163
for (unsigned int i = 0; i < ARRAY_SIZE(description); i++) {
160-
if (riscv_get_dmi_address(target, description[i].address) == address) {
164+
if (riscv_get_dmi_address(batch->target, description[i].address)
165+
== address) {
161166
const riscv_debug_reg_ctx_t context = {
162167
.XLEN = { .value = 0, .is_set = false },
163168
.DXLEN = { .value = 0, .is_set = false },
@@ -172,51 +177,85 @@ static unsigned int decode_dmi(const struct target *target, char *text, uint32_t
172177
return 0;
173178
}
174179

175-
static void riscv_log_dmi_scan(const struct target *target, int idle,
176-
const struct scan_field *field)
180+
static void log_dmi_decoded(const struct riscv_batch *batch, bool write,
181+
uint32_t address, uint32_t data)
177182
{
178-
static const char * const op_string[] = {"-", "r", "w", "?"};
179-
static const char * const status_string[] = {"+", "?", "F", "b"};
183+
const size_t size = decode_dmi(batch, /* text */ NULL, address, data) + 1;
184+
char * const decoded = malloc(size);
185+
if (!decoded) {
186+
LOG_ERROR("Not enough memory to allocate %zu bytes.", size);
187+
return;
188+
}
189+
decode_dmi(batch, decoded, address, data);
190+
LOG_DEBUG("%s: %s", write ? "write" : "read", decoded);
191+
free(decoded);
192+
}
180193

194+
static void log_batch(const struct riscv_batch *batch, size_t start_idx,
195+
const struct riscv_scan_delays *delays, bool resets_delays,
196+
size_t reset_delays_after)
197+
{
181198
if (debug_level < LOG_LVL_DEBUG)
182199
return;
183200

184-
assert(field->out_value);
185-
const uint64_t out = buf_get_u64(field->out_value, 0, field->num_bits);
186-
const unsigned int out_op = get_field(out, DTM_DMI_OP);
187-
const uint32_t out_data = get_field(out, DTM_DMI_DATA);
188-
const uint32_t out_address = out >> DTM_DMI_ADDRESS_OFFSET;
189-
190-
if (field->in_value) {
191-
const uint64_t in = buf_get_u64(field->in_value, 0, field->num_bits);
192-
const unsigned int in_op = get_field(in, DTM_DMI_OP);
193-
const uint32_t in_data = get_field(in, DTM_DMI_DATA);
194-
const uint32_t in_address = in >> DTM_DMI_ADDRESS_OFFSET;
195-
196-
LOG_DEBUG("%db %s %08" PRIx32 " @%02" PRIx32 " -> %s %08" PRIx32 " @%02" PRIx32 "; %di",
197-
field->num_bits, op_string[out_op], out_data, out_address,
198-
status_string[in_op], in_data, in_address, idle);
199-
200-
if (in_op == DTM_DMI_OP_SUCCESS) {
201-
char in_decoded[decode_dmi(target, NULL, in_address, in_data) + 1];
202-
decode_dmi(target, in_decoded, in_address, in_data);
203-
/* FIXME: The current code assumes that the hardware
204-
* provides the read address in the dmi.address field
205-
* when returning the dmi.data. That is however not
206-
* required by the spec, and therefore not guaranteed.
207-
* See https://github.com/riscv-collab/riscv-openocd/issues/1043
208-
*/
209-
LOG_DEBUG("read: %s", in_decoded);
210-
}
211-
} else {
212-
LOG_DEBUG("%db %s %08" PRIx32 " @%02" PRIx32 " -> ?; %di",
213-
field->num_bits, op_string[out_op], out_data, out_address,
214-
idle);
201+
bool reads = false;
202+
uint32_t last_address = -1 /* to silence maybe-uninitialized */;
203+
if (start_idx > 0) {
204+
const struct scan_field * const field = &batch->fields[start_idx - 1];
205+
assert(field->out_value);
206+
reads = buf_get_u32(field->out_value, DTM_DMI_OP_OFFSET,
207+
DTM_DMI_OP_LENGTH) == DTM_DMI_OP_READ;
208+
const unsigned int abits = field->num_bits - DTM_DMI_OP_LENGTH
209+
- DTM_DMI_DATA_LENGTH;
210+
last_address = buf_get_u32(field->out_value,
211+
DTM_DMI_ADDRESS_OFFSET, abits);
215212
}
216-
if (out_op == DTM_DMI_OP_WRITE) {
217-
char out_decoded[decode_dmi(target, NULL, out_address, out_data) + 1];
218-
decode_dmi(target, out_decoded, out_address, out_data);
219-
LOG_DEBUG("write: %s", out_decoded);
213+
for (size_t i = start_idx; i < batch->used_scans; ++i) {
214+
static const char * const op_string[] = {"-", "r", "w", "?"};
215+
const int delay = get_delay(batch, i, delays, resets_delays,
216+
reset_delays_after);
217+
const struct scan_field * const field = &batch->fields[i];
218+
219+
assert(field->out_value);
220+
const unsigned int out_op = buf_get_u32(field->out_value,
221+
DTM_DMI_OP_OFFSET, DTM_DMI_OP_LENGTH);
222+
const uint32_t out_data = buf_get_u32(field->out_value,
223+
DTM_DMI_DATA_OFFSET, DTM_DMI_DATA_LENGTH);
224+
const unsigned int abits = field->num_bits - DTM_DMI_OP_LENGTH
225+
- DTM_DMI_DATA_LENGTH;
226+
const uint32_t out_address = buf_get_u32(field->out_value,
227+
DTM_DMI_ADDRESS_OFFSET, abits);
228+
if (field->in_value) {
229+
static const char * const status_string[] = {
230+
"+", "?", "F", "b"
231+
};
232+
const unsigned int in_op = buf_get_u32(field->in_value,
233+
DTM_DMI_OP_OFFSET, DTM_DMI_OP_LENGTH);
234+
const uint32_t in_data = buf_get_u32(field->in_value,
235+
DTM_DMI_DATA_OFFSET, DTM_DMI_DATA_LENGTH);
236+
const uint32_t in_address = buf_get_u32(field->in_value,
237+
DTM_DMI_ADDRESS_OFFSET, abits);
238+
239+
LOG_DEBUG("%db %s %08" PRIx32 " @%02" PRIx32
240+
" -> %s %08" PRIx32 " @%02" PRIx32 "; %di",
241+
field->num_bits, op_string[out_op], out_data, out_address,
242+
status_string[in_op], in_data, in_address, delay);
243+
244+
if (reads && in_op == DTM_DMI_OP_SUCCESS)
245+
log_dmi_decoded(batch, /*write*/ false,
246+
last_address, in_data);
247+
} else {
248+
LOG_DEBUG("%db %s %08" PRIx32 " @%02" PRIx32 " -> ?; %di",
249+
field->num_bits, op_string[out_op], out_data, out_address,
250+
delay);
251+
}
252+
253+
if (out_op == DTM_DMI_OP_WRITE)
254+
log_dmi_decoded(batch, /*write*/ true, out_address,
255+
out_data);
256+
257+
reads = out_op == DTM_DMI_OP_READ;
258+
last_address = out_address;
220259
}
221260
}
222261

@@ -225,6 +264,7 @@ int riscv_batch_run_from(struct riscv_batch *batch, size_t start_idx,
225264
size_t reset_delays_after)
226265
{
227266
assert(batch->used_scans);
267+
assert(start_idx < batch->used_scans);
228268
assert(batch->last_scan == RISCV_SCAN_TYPE_NOP);
229269
assert(!batch->was_run || riscv_batch_was_scan_busy(batch, start_idx));
230270
assert(start_idx == 0 || !riscv_batch_was_scan_busy(batch, start_idx - 1));
@@ -235,18 +275,16 @@ int riscv_batch_run_from(struct riscv_batch *batch, size_t start_idx,
235275
LOG_TARGET_DEBUG(batch->target, "Running batch of scans [%zu, %zu)",
236276
start_idx, batch->used_scans);
237277

278+
unsigned int delay = 0 /* to silence maybe-uninitialized */;
238279
for (size_t i = start_idx; i < batch->used_scans; ++i) {
239280
if (bscan_tunnel_ir_width != 0)
240281
riscv_add_bscan_tunneled_scan(batch->target, batch->fields + i, batch->bscan_ctxt + i);
241282
else
242283
jtag_add_dr_scan(batch->target->tap, 1, batch->fields + i, TAP_IDLE);
243284

244-
const bool delays_were_reset = resets_delays
245-
&& (i >= reset_delays_after);
246-
const int delay = get_delay(batch, i, delays);
247-
248-
if (!delays_were_reset)
249-
jtag_add_runtest(delay, TAP_IDLE);
285+
delay = get_delay(batch, i, delays, resets_delays,
286+
reset_delays_after);
287+
jtag_add_runtest(delay, TAP_IDLE);
250288
}
251289

252290
keep_alive();
@@ -266,13 +304,9 @@ int riscv_batch_run_from(struct riscv_batch *batch, size_t start_idx,
266304
}
267305
}
268306

269-
for (size_t i = start_idx; i < batch->used_scans; ++i) {
270-
const int delay = get_delay(batch, i, delays);
271-
riscv_log_dmi_scan(batch->target, delay, batch->fields + i);
272-
}
273-
307+
log_batch(batch, start_idx, delays, resets_delays, reset_delays_after);
274308
batch->was_run = true;
275-
batch->last_scan_delay = get_delay(batch, batch->used_scans - 1, delays);
309+
batch->last_scan_delay = delay;
276310
return ERROR_OK;
277311
}
278312

0 commit comments

Comments
 (0)