3c062e15011aefb03af5fecd56dc4314c55af155
[openocd.git] / src / target / riscv / batch.c
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2
3 #ifdef HAVE_CONFIG_H
4 #include "config.h"
5 #endif
6
7 #include "batch.h"
8 #include "debug_defines.h"
9 #include "riscv.h"
10
11 #define get_field(reg, mask) (((reg) & (mask)) / ((mask) & ~((mask) << 1)))
12 #define set_field(reg, mask, val) (((reg) & ~(mask)) | (((val) * ((mask) & ~((mask) << 1))) & (mask)))
13
14 #define DTM_DMI_MAX_ADDRESS_LENGTH ((1<<DTM_DTMCS_ABITS_LENGTH)-1)
15 #define DMI_SCAN_MAX_BIT_LENGTH (DTM_DMI_MAX_ADDRESS_LENGTH + DTM_DMI_DATA_LENGTH + DTM_DMI_OP_LENGTH)
16 #define DMI_SCAN_BUF_SIZE (DIV_ROUND_UP(DMI_SCAN_MAX_BIT_LENGTH, 8))
17
18 static void dump_field(int idle, const struct scan_field *field);
19
20 struct riscv_batch *riscv_batch_alloc(struct target *target, size_t scans, size_t idle)
21 {
22 scans += 4;
23 struct riscv_batch *out = calloc(1, sizeof(*out));
24 if (!out)
25 goto error0;
26 out->target = target;
27 out->allocated_scans = scans;
28 out->idle_count = idle;
29 out->data_out = malloc(sizeof(*out->data_out) * (scans) * DMI_SCAN_BUF_SIZE);
30 if (!out->data_out)
31 goto error1;
32 out->data_in = malloc(sizeof(*out->data_in) * (scans) * DMI_SCAN_BUF_SIZE);
33 if (!out->data_in)
34 goto error2;
35 out->fields = malloc(sizeof(*out->fields) * (scans));
36 if (!out->fields)
37 goto error3;
38 if (bscan_tunnel_ir_width != 0) {
39 out->bscan_ctxt = malloc(sizeof(*out->bscan_ctxt) * (scans));
40 if (!out->bscan_ctxt)
41 goto error4;
42 }
43 out->last_scan = RISCV_SCAN_TYPE_INVALID;
44 out->read_keys = malloc(sizeof(*out->read_keys) * (scans));
45 if (!out->read_keys)
46 goto error5;
47 return out;
48
49 error5:
50 free(out->bscan_ctxt);
51 error4:
52 free(out->fields);
53 error3:
54 free(out->data_in);
55 error2:
56 free(out->data_out);
57 error1:
58 free(out);
59 error0:
60 return NULL;
61 }
62
63 void riscv_batch_free(struct riscv_batch *batch)
64 {
65 free(batch->data_in);
66 free(batch->data_out);
67 free(batch->fields);
68 free(batch->bscan_ctxt);
69 free(batch->read_keys);
70 free(batch);
71 }
72
73 bool riscv_batch_full(struct riscv_batch *batch)
74 {
75 return batch->used_scans > (batch->allocated_scans - 4);
76 }
77
78 int riscv_batch_run(struct riscv_batch *batch)
79 {
80 if (batch->used_scans == 0) {
81 LOG_DEBUG("Ignoring empty batch.");
82 return ERROR_OK;
83 }
84
85 keep_alive();
86
87 riscv_batch_add_nop(batch);
88
89 for (size_t i = 0; i < batch->used_scans; ++i) {
90 if (bscan_tunnel_ir_width != 0)
91 riscv_add_bscan_tunneled_scan(batch->target, batch->fields+i, batch->bscan_ctxt+i);
92 else
93 jtag_add_dr_scan(batch->target->tap, 1, batch->fields + i, TAP_IDLE);
94
95 if (batch->idle_count > 0)
96 jtag_add_runtest(batch->idle_count, TAP_IDLE);
97 }
98
99 if (jtag_execute_queue() != ERROR_OK) {
100 LOG_ERROR("Unable to execute JTAG queue");
101 return ERROR_FAIL;
102 }
103
104 if (bscan_tunnel_ir_width != 0) {
105 /* need to right-shift "in" by one bit, because of clock skew between BSCAN TAP and DM TAP */
106 for (size_t i = 0; i < batch->used_scans; ++i)
107 buffer_shr((batch->fields + i)->in_value, DMI_SCAN_BUF_SIZE, 1);
108 }
109
110 for (size_t i = 0; i < batch->used_scans; ++i)
111 dump_field(batch->idle_count, batch->fields + i);
112
113 return ERROR_OK;
114 }
115
116 void riscv_batch_add_dmi_write(struct riscv_batch *batch, unsigned address, uint64_t data)
117 {
118 assert(batch->used_scans < batch->allocated_scans);
119 struct scan_field *field = batch->fields + batch->used_scans;
120 field->num_bits = riscv_dmi_write_u64_bits(batch->target);
121 field->out_value = (void *)(batch->data_out + batch->used_scans * DMI_SCAN_BUF_SIZE);
122 field->in_value = (void *)(batch->data_in + batch->used_scans * DMI_SCAN_BUF_SIZE);
123 riscv_fill_dmi_write_u64(batch->target, (char *)field->out_value, address, data);
124 riscv_fill_dmi_nop_u64(batch->target, (char *)field->in_value);
125 batch->last_scan = RISCV_SCAN_TYPE_WRITE;
126 batch->used_scans++;
127 }
128
129 size_t riscv_batch_add_dmi_read(struct riscv_batch *batch, unsigned address)
130 {
131 assert(batch->used_scans < batch->allocated_scans);
132 struct scan_field *field = batch->fields + batch->used_scans;
133 field->num_bits = riscv_dmi_write_u64_bits(batch->target);
134 field->out_value = (void *)(batch->data_out + batch->used_scans * DMI_SCAN_BUF_SIZE);
135 field->in_value = (void *)(batch->data_in + batch->used_scans * DMI_SCAN_BUF_SIZE);
136 riscv_fill_dmi_read_u64(batch->target, (char *)field->out_value, address);
137 riscv_fill_dmi_nop_u64(batch->target, (char *)field->in_value);
138 batch->last_scan = RISCV_SCAN_TYPE_READ;
139 batch->used_scans++;
140
141 batch->read_keys[batch->read_keys_used] = batch->used_scans;
142 return batch->read_keys_used++;
143 }
144
145 unsigned riscv_batch_get_dmi_read_op(struct riscv_batch *batch, size_t key)
146 {
147 assert(key < batch->read_keys_used);
148 size_t index = batch->read_keys[key];
149 assert(index <= batch->used_scans);
150 uint8_t *base = batch->data_in + DMI_SCAN_BUF_SIZE * index;
151 /* extract "op" field from the DMI read result */
152 return (unsigned)buf_get_u32(base, DTM_DMI_OP_OFFSET, DTM_DMI_OP_LENGTH);
153 }
154
155 uint32_t riscv_batch_get_dmi_read_data(struct riscv_batch *batch, size_t key)
156 {
157 assert(key < batch->read_keys_used);
158 size_t index = batch->read_keys[key];
159 assert(index <= batch->used_scans);
160 uint8_t *base = batch->data_in + DMI_SCAN_BUF_SIZE * index;
161 /* extract "data" field from the DMI read result */
162 return buf_get_u32(base, DTM_DMI_DATA_OFFSET, DTM_DMI_DATA_LENGTH);
163 }
164
165 void riscv_batch_add_nop(struct riscv_batch *batch)
166 {
167 assert(batch->used_scans < batch->allocated_scans);
168 struct scan_field *field = batch->fields + batch->used_scans;
169 field->num_bits = riscv_dmi_write_u64_bits(batch->target);
170 field->out_value = (void *)(batch->data_out + batch->used_scans * DMI_SCAN_BUF_SIZE);
171 field->in_value = (void *)(batch->data_in + batch->used_scans * DMI_SCAN_BUF_SIZE);
172 riscv_fill_dmi_nop_u64(batch->target, (char *)field->out_value);
173 riscv_fill_dmi_nop_u64(batch->target, (char *)field->in_value);
174 batch->last_scan = RISCV_SCAN_TYPE_NOP;
175 batch->used_scans++;
176 }
177
178 void dump_field(int idle, const struct scan_field *field)
179 {
180 static const char * const op_string[] = {"-", "r", "w", "?"};
181 static const char * const status_string[] = {"+", "?", "F", "b"};
182
183 if (debug_level < LOG_LVL_DEBUG)
184 return;
185
186 assert(field->out_value);
187 uint64_t out = buf_get_u64(field->out_value, 0, field->num_bits);
188 unsigned int out_op = get_field(out, DTM_DMI_OP);
189 unsigned int out_data = get_field(out, DTM_DMI_DATA);
190 unsigned int out_address = out >> DTM_DMI_ADDRESS_OFFSET;
191
192 if (field->in_value) {
193 uint64_t in = buf_get_u64(field->in_value, 0, field->num_bits);
194 unsigned int in_op = get_field(in, DTM_DMI_OP);
195 unsigned int in_data = get_field(in, DTM_DMI_DATA);
196 unsigned int in_address = in >> DTM_DMI_ADDRESS_OFFSET;
197
198 log_printf_lf(LOG_LVL_DEBUG,
199 __FILE__, __LINE__, __PRETTY_FUNCTION__,
200 "%db %s %08x @%02x -> %s %08x @%02x; %di",
201 field->num_bits, op_string[out_op], out_data, out_address,
202 status_string[in_op], in_data, in_address, idle);
203 } else {
204 log_printf_lf(LOG_LVL_DEBUG,
205 __FILE__, __LINE__, __PRETTY_FUNCTION__, "%db %s %08x @%02x -> ?; %di",
206 field->num_bits, op_string[out_op], out_data, out_address, idle);
207 }
208 }
209
210 size_t riscv_batch_available_scans(struct riscv_batch *batch)
211 {
212 return batch->allocated_scans - batch->used_scans - 4;
213 }

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)