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

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)