Upstream tons of RISC-V changes.
[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                 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 != NULL);
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 }