9327cb38babdea7bb6ddadb80fed40a9179501c3
[openocd.git] / src / target / riscv / batch.c
1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif
4
5 #include "batch.h"
6 #include "debug_defines.h"
7 #include "riscv.h"
8
9 #define get_field(reg, mask) (((reg) & (mask)) / ((mask) & ~((mask) << 1)))
10 #define set_field(reg, mask, val) (((reg) & ~(mask)) | (((val) * ((mask) & ~((mask) << 1))) & (mask)))
11
12 static void dump_field(const struct scan_field *field);
13
14 struct riscv_batch *riscv_batch_alloc(struct target *target, size_t scans, size_t idle)
15 {
16 scans += 4;
17 struct riscv_batch *out = malloc(sizeof(*out));
18 memset(out, 0, sizeof(*out));
19 out->target = target;
20 out->allocated_scans = scans;
21 out->used_scans = 0;
22 out->idle_count = idle;
23 out->data_out = malloc(sizeof(*out->data_out) * (scans) * sizeof(uint64_t));
24 out->data_in = malloc(sizeof(*out->data_in) * (scans) * sizeof(uint64_t));
25 out->fields = malloc(sizeof(*out->fields) * (scans));
26 out->last_scan = RISCV_SCAN_TYPE_INVALID;
27 out->read_keys = malloc(sizeof(*out->read_keys) * (scans));
28 out->read_keys_used = 0;
29 return out;
30 }
31
32 void riscv_batch_free(struct riscv_batch *batch)
33 {
34 free(batch->data_in);
35 free(batch->data_out);
36 free(batch->fields);
37 free(batch);
38 }
39
40 bool riscv_batch_full(struct riscv_batch *batch)
41 {
42 return batch->used_scans > (batch->allocated_scans - 4);
43 }
44
45 int riscv_batch_run(struct riscv_batch *batch)
46 {
47 if (batch->used_scans == 0) {
48 LOG_DEBUG("Ignoring empty batch.");
49 return ERROR_OK;
50 }
51
52 keep_alive();
53
54 LOG_DEBUG("running a batch of %ld scans", (long)batch->used_scans);
55 riscv_batch_add_nop(batch);
56
57 for (size_t i = 0; i < batch->used_scans; ++i) {
58 jtag_add_dr_scan(batch->target->tap, 1, batch->fields + i, TAP_IDLE);
59 if (batch->idle_count > 0)
60 jtag_add_runtest(batch->idle_count, TAP_IDLE);
61 }
62
63 LOG_DEBUG("executing queue");
64 if (jtag_execute_queue() != ERROR_OK) {
65 LOG_ERROR("Unable to execute JTAG queue");
66 return ERROR_FAIL;
67 }
68
69 for (size_t i = 0; i < batch->used_scans; ++i)
70 dump_field(batch->fields + i);
71
72 return ERROR_OK;
73 }
74
75 void riscv_batch_add_dmi_write(struct riscv_batch *batch, unsigned address, uint64_t data)
76 {
77 assert(batch->used_scans < batch->allocated_scans);
78 struct scan_field *field = batch->fields + batch->used_scans;
79 field->num_bits = riscv_dmi_write_u64_bits(batch->target);
80 field->out_value = (void *)(batch->data_out + batch->used_scans * sizeof(uint64_t));
81 field->in_value = (void *)(batch->data_in + batch->used_scans * sizeof(uint64_t));
82 riscv_fill_dmi_write_u64(batch->target, (char *)field->out_value, address, data);
83 riscv_fill_dmi_nop_u64(batch->target, (char *)field->in_value);
84 batch->last_scan = RISCV_SCAN_TYPE_WRITE;
85 batch->used_scans++;
86 }
87
88 size_t riscv_batch_add_dmi_read(struct riscv_batch *batch, unsigned address)
89 {
90 assert(batch->used_scans < batch->allocated_scans);
91 struct scan_field *field = batch->fields + batch->used_scans;
92 field->num_bits = riscv_dmi_write_u64_bits(batch->target);
93 field->out_value = (void *)(batch->data_out + batch->used_scans * sizeof(uint64_t));
94 field->in_value = (void *)(batch->data_in + batch->used_scans * sizeof(uint64_t));
95 riscv_fill_dmi_read_u64(batch->target, (char *)field->out_value, address);
96 riscv_fill_dmi_nop_u64(batch->target, (char *)field->in_value);
97 batch->last_scan = RISCV_SCAN_TYPE_READ;
98 batch->used_scans++;
99
100 /* FIXME We get the read response back on the next scan. For now I'm
101 * just sticking a NOP in there, but this should be coelesced away. */
102 riscv_batch_add_nop(batch);
103
104 batch->read_keys[batch->read_keys_used] = batch->used_scans - 1;
105 LOG_DEBUG("read key %u for batch 0x%p is %u (0x%p)",
106 (unsigned) batch->read_keys_used, batch, (unsigned) (batch->used_scans - 1),
107 batch->data_in + sizeof(uint64_t) * (batch->used_scans + 1));
108 return batch->read_keys_used++;
109 }
110
111 uint64_t riscv_batch_get_dmi_read(struct riscv_batch *batch, size_t key)
112 {
113 assert(key < batch->read_keys_used);
114 size_t index = batch->read_keys[key];
115 assert(index <= batch->used_scans);
116 uint8_t *base = batch->data_in + 8 * index;
117 return base[0] |
118 ((uint64_t) base[1]) << 8 |
119 ((uint64_t) base[2]) << 16 |
120 ((uint64_t) base[3]) << 24 |
121 ((uint64_t) base[4]) << 32 |
122 ((uint64_t) base[5]) << 40 |
123 ((uint64_t) base[6]) << 48 |
124 ((uint64_t) base[7]) << 56;
125 }
126
127 void riscv_batch_add_nop(struct riscv_batch *batch)
128 {
129 assert(batch->used_scans < batch->allocated_scans);
130 struct scan_field *field = batch->fields + batch->used_scans;
131 field->num_bits = riscv_dmi_write_u64_bits(batch->target);
132 field->out_value = (void *)(batch->data_out + batch->used_scans * sizeof(uint64_t));
133 field->in_value = (void *)(batch->data_in + batch->used_scans * sizeof(uint64_t));
134 riscv_fill_dmi_nop_u64(batch->target, (char *)field->out_value);
135 riscv_fill_dmi_nop_u64(batch->target, (char *)field->in_value);
136 batch->last_scan = RISCV_SCAN_TYPE_NOP;
137 batch->used_scans++;
138 LOG_DEBUG(" added NOP with in_value=0x%p", field->in_value);
139 }
140
141 void dump_field(const struct scan_field *field)
142 {
143 static const char * const op_string[] = {"-", "r", "w", "?"};
144 static const char * const status_string[] = {"+", "?", "F", "b"};
145
146 if (debug_level < LOG_LVL_DEBUG)
147 return;
148
149 assert(field->out_value != NULL);
150 uint64_t out = buf_get_u64(field->out_value, 0, field->num_bits);
151 unsigned int out_op = get_field(out, DTM_DMI_OP);
152 unsigned int out_data = get_field(out, DTM_DMI_DATA);
153 unsigned int out_address = out >> DTM_DMI_ADDRESS_OFFSET;
154
155 if (field->in_value) {
156 uint64_t in = buf_get_u64(field->in_value, 0, field->num_bits);
157 unsigned int in_op = get_field(in, DTM_DMI_OP);
158 unsigned int in_data = get_field(in, DTM_DMI_DATA);
159 unsigned int in_address = in >> DTM_DMI_ADDRESS_OFFSET;
160
161 log_printf_lf(LOG_LVL_DEBUG,
162 __FILE__, __LINE__, __PRETTY_FUNCTION__,
163 "%db %s %08x @%02x -> %s %08x @%02x",
164 field->num_bits,
165 op_string[out_op], out_data, out_address,
166 status_string[in_op], in_data, in_address);
167 } else {
168 log_printf_lf(LOG_LVL_DEBUG,
169 __FILE__, __LINE__, __PRETTY_FUNCTION__, "%db %s %08x @%02x -> ?",
170 field->num_bits, op_string[out_op], out_data, out_address);
171 }
172 }

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)