openocd: fix SPDX tag format for files .c
[fw/openocd] / 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 }