daf7cd4266ed6733969eb972fbb92b263f5e4876
[openocd.git] / src / jtag / drivers / driver.c
1 /***************************************************************************
2 * Copyright (C) 2005 by Dominic Rath *
3 * Dominic.Rath@gmx.de *
4 * *
5 * Copyright (C) 2007-2010 √ėyvind Harboe *
6 * oyvind.harboe@zylin.com *
7 * *
8 * Copyright (C) 2009 SoftPLC Corporation *
9 * http://softplc.com *
10 * dick@softplc.com *
11 * *
12 * Copyright (C) 2009 Zachary T Welch *
13 * zw@superlucidity.net *
14 * *
15 * This program is free software; you can redistribute it and/or modify *
16 * it under the terms of the GNU General Public License as published by *
17 * the Free Software Foundation; either version 2 of the License, or *
18 * (at your option) any later version. *
19 * *
20 * This program is distributed in the hope that it will be useful, *
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
23 * GNU General Public License for more details. *
24 * *
25 * You should have received a copy of the GNU General Public License *
26 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
27 ***************************************************************************/
28
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
32
33 #include <jtag/jtag.h>
34 #include <jtag/interface.h>
35 #include <jtag/commands.h>
36 #include <jtag/minidriver.h>
37 #include <helper/command.h>
38
39 struct jtag_callback_entry {
40 struct jtag_callback_entry *next;
41
42 jtag_callback_t callback;
43 jtag_callback_data_t data0;
44 jtag_callback_data_t data1;
45 jtag_callback_data_t data2;
46 jtag_callback_data_t data3;
47 };
48
49 static struct jtag_callback_entry *jtag_callback_queue_head;
50 static struct jtag_callback_entry *jtag_callback_queue_tail;
51
52 static void jtag_callback_queue_reset(void)
53 {
54 jtag_callback_queue_head = NULL;
55 jtag_callback_queue_tail = NULL;
56 }
57
58 /**
59 * Copy a struct scan_field for insertion into the queue.
60 *
61 * This allocates a new copy of out_value using cmd_queue_alloc.
62 */
63 static void cmd_queue_scan_field_clone(struct scan_field *dst, const struct scan_field *src)
64 {
65 dst->num_bits = src->num_bits;
66 dst->out_value = buf_cpy(src->out_value, cmd_queue_alloc(DIV_ROUND_UP(src->num_bits, 8)), src->num_bits);
67 dst->in_value = src->in_value;
68 }
69
70 /**
71 * see jtag_add_ir_scan()
72 *
73 */
74 int interface_jtag_add_ir_scan(struct jtag_tap *active,
75 const struct scan_field *in_fields, tap_state_t state)
76 {
77 size_t num_taps = jtag_tap_count_enabled();
78
79 struct jtag_command *cmd = cmd_queue_alloc(sizeof(struct jtag_command));
80 struct scan_command *scan = cmd_queue_alloc(sizeof(struct scan_command));
81 struct scan_field *out_fields = cmd_queue_alloc(num_taps * sizeof(struct scan_field));
82
83 jtag_queue_command(cmd);
84
85 cmd->type = JTAG_SCAN;
86 cmd->cmd.scan = scan;
87
88 scan->ir_scan = true;
89 scan->num_fields = num_taps; /* one field per device */
90 scan->fields = out_fields;
91 scan->end_state = state;
92
93 struct scan_field *field = out_fields; /* keep track where we insert data */
94
95 /* loop over all enabled TAPs */
96
97 for (struct jtag_tap *tap = jtag_tap_next_enabled(NULL); tap != NULL; tap = jtag_tap_next_enabled(tap)) {
98 /* search the input field list for fields for the current TAP */
99
100 if (tap == active) {
101 /* if TAP is listed in input fields, copy the value */
102 tap->bypass = 0;
103
104 cmd_queue_scan_field_clone(field, in_fields);
105 } else {
106 /* if a TAP isn't listed in input fields, set it to BYPASS */
107
108 tap->bypass = 1;
109
110 field->num_bits = tap->ir_length;
111 field->out_value = buf_set_ones(cmd_queue_alloc(DIV_ROUND_UP(tap->ir_length, 8)), tap->ir_length);
112 field->in_value = NULL; /* do not collect input for tap's in bypass */
113 }
114
115 /* update device information */
116 buf_cpy(field->out_value, tap->cur_instr, tap->ir_length);
117
118 field++;
119 }
120 /* paranoia: jtag_tap_count_enabled() and jtag_tap_next_enabled() not in sync */
121 assert(field == out_fields + num_taps);
122
123 return ERROR_OK;
124 }
125
126 /**
127 * see jtag_add_dr_scan()
128 *
129 */
130 int interface_jtag_add_dr_scan(struct jtag_tap *active, int in_num_fields,
131 const struct scan_field *in_fields, tap_state_t state)
132 {
133 /* count devices in bypass */
134
135 size_t bypass_devices = 0;
136
137 for (struct jtag_tap *tap = jtag_tap_next_enabled(NULL); tap != NULL; tap = jtag_tap_next_enabled(tap)) {
138 if (tap->bypass)
139 bypass_devices++;
140 }
141
142 struct jtag_command *cmd = cmd_queue_alloc(sizeof(struct jtag_command));
143 struct scan_command *scan = cmd_queue_alloc(sizeof(struct scan_command));
144 struct scan_field *out_fields = cmd_queue_alloc((in_num_fields + bypass_devices) * sizeof(struct scan_field));
145
146 jtag_queue_command(cmd);
147
148 cmd->type = JTAG_SCAN;
149 cmd->cmd.scan = scan;
150
151 scan->ir_scan = false;
152 scan->num_fields = in_num_fields + bypass_devices;
153 scan->fields = out_fields;
154 scan->end_state = state;
155
156 struct scan_field *field = out_fields; /* keep track where we insert data */
157
158 /* loop over all enabled TAPs */
159
160 for (struct jtag_tap *tap = jtag_tap_next_enabled(NULL); tap != NULL; tap = jtag_tap_next_enabled(tap)) {
161 /* if TAP is not bypassed insert matching input fields */
162
163 if (!tap->bypass) {
164 assert(active == tap);
165 #ifndef NDEBUG
166 /* remember initial position for assert() */
167 struct scan_field *start_field = field;
168 #endif /* NDEBUG */
169
170 for (int j = 0; j < in_num_fields; j++) {
171 cmd_queue_scan_field_clone(field, in_fields + j);
172
173 field++;
174 }
175
176 assert(field > start_field); /* must have at least one input field per not bypassed TAP */
177 }
178
179 /* if a TAP is bypassed, generated a dummy bit*/
180 else {
181 field->num_bits = 1;
182 field->out_value = NULL;
183 field->in_value = NULL;
184
185 field++;
186 }
187 }
188
189 assert(field == out_fields + scan->num_fields); /* no superfluous input fields permitted */
190
191 return ERROR_OK;
192 }
193
194 static int jtag_add_plain_scan(int num_bits, const uint8_t *out_bits,
195 uint8_t *in_bits, tap_state_t state, bool ir_scan)
196 {
197 struct jtag_command *cmd = cmd_queue_alloc(sizeof(struct jtag_command));
198 struct scan_command *scan = cmd_queue_alloc(sizeof(struct scan_command));
199 struct scan_field *out_fields = cmd_queue_alloc(sizeof(struct scan_field));
200
201 jtag_queue_command(cmd);
202
203 cmd->type = JTAG_SCAN;
204 cmd->cmd.scan = scan;
205
206 scan->ir_scan = ir_scan;
207 scan->num_fields = 1;
208 scan->fields = out_fields;
209 scan->end_state = state;
210
211 out_fields->num_bits = num_bits;
212 out_fields->out_value = buf_cpy(out_bits, cmd_queue_alloc(DIV_ROUND_UP(num_bits, 8)), num_bits);
213 out_fields->in_value = in_bits;
214
215 return ERROR_OK;
216 }
217
218 int interface_jtag_add_plain_dr_scan(int num_bits, const uint8_t *out_bits, uint8_t *in_bits, tap_state_t state)
219 {
220 return jtag_add_plain_scan(num_bits, out_bits, in_bits, state, false);
221 }
222
223 int interface_jtag_add_plain_ir_scan(int num_bits, const uint8_t *out_bits, uint8_t *in_bits, tap_state_t state)
224 {
225 return jtag_add_plain_scan(num_bits, out_bits, in_bits, state, true);
226 }
227
228 int interface_jtag_add_tlr(void)
229 {
230 tap_state_t state = TAP_RESET;
231
232 /* allocate memory for a new list member */
233 struct jtag_command *cmd = cmd_queue_alloc(sizeof(struct jtag_command));
234
235 jtag_queue_command(cmd);
236
237 cmd->type = JTAG_TLR_RESET;
238
239 cmd->cmd.statemove = cmd_queue_alloc(sizeof(struct statemove_command));
240 cmd->cmd.statemove->end_state = state;
241
242 return ERROR_OK;
243 }
244
245 int interface_add_tms_seq(unsigned num_bits, const uint8_t *seq, enum tap_state state)
246 {
247 struct jtag_command *cmd;
248
249 cmd = cmd_queue_alloc(sizeof(struct jtag_command));
250 if (cmd == NULL)
251 return ERROR_FAIL;
252
253 cmd->type = JTAG_TMS;
254 cmd->cmd.tms = cmd_queue_alloc(sizeof(*cmd->cmd.tms));
255 if (!cmd->cmd.tms)
256 return ERROR_FAIL;
257
258 /* copy the bits; our caller doesn't guarantee they'll persist */
259 cmd->cmd.tms->num_bits = num_bits;
260 cmd->cmd.tms->bits = buf_cpy(seq,
261 cmd_queue_alloc(DIV_ROUND_UP(num_bits, 8)), num_bits);
262 if (!cmd->cmd.tms->bits)
263 return ERROR_FAIL;
264
265 jtag_queue_command(cmd);
266
267 return ERROR_OK;
268 }
269
270 int interface_jtag_add_pathmove(int num_states, const tap_state_t *path)
271 {
272 /* allocate memory for a new list member */
273 struct jtag_command *cmd = cmd_queue_alloc(sizeof(struct jtag_command));
274
275 jtag_queue_command(cmd);
276
277 cmd->type = JTAG_PATHMOVE;
278
279 cmd->cmd.pathmove = cmd_queue_alloc(sizeof(struct pathmove_command));
280 cmd->cmd.pathmove->num_states = num_states;
281 cmd->cmd.pathmove->path = cmd_queue_alloc(sizeof(tap_state_t) * num_states);
282
283 for (int i = 0; i < num_states; i++)
284 cmd->cmd.pathmove->path[i] = path[i];
285
286 return ERROR_OK;
287 }
288
289 int interface_jtag_add_runtest(int num_cycles, tap_state_t state)
290 {
291 /* allocate memory for a new list member */
292 struct jtag_command *cmd = cmd_queue_alloc(sizeof(struct jtag_command));
293
294 jtag_queue_command(cmd);
295
296 cmd->type = JTAG_RUNTEST;
297
298 cmd->cmd.runtest = cmd_queue_alloc(sizeof(struct runtest_command));
299 cmd->cmd.runtest->num_cycles = num_cycles;
300 cmd->cmd.runtest->end_state = state;
301
302 return ERROR_OK;
303 }
304
305 int interface_jtag_add_clocks(int num_cycles)
306 {
307 /* allocate memory for a new list member */
308 struct jtag_command *cmd = cmd_queue_alloc(sizeof(struct jtag_command));
309
310 jtag_queue_command(cmd);
311
312 cmd->type = JTAG_STABLECLOCKS;
313
314 cmd->cmd.stableclocks = cmd_queue_alloc(sizeof(struct stableclocks_command));
315 cmd->cmd.stableclocks->num_cycles = num_cycles;
316
317 return ERROR_OK;
318 }
319
320 int interface_jtag_add_reset(int req_trst, int req_srst)
321 {
322 /* allocate memory for a new list member */
323 struct jtag_command *cmd = cmd_queue_alloc(sizeof(struct jtag_command));
324
325 jtag_queue_command(cmd);
326
327 cmd->type = JTAG_RESET;
328
329 cmd->cmd.reset = cmd_queue_alloc(sizeof(struct reset_command));
330 cmd->cmd.reset->trst = req_trst;
331 cmd->cmd.reset->srst = req_srst;
332
333 return ERROR_OK;
334 }
335
336 int interface_jtag_add_sleep(uint32_t us)
337 {
338 /* allocate memory for a new list member */
339 struct jtag_command *cmd = cmd_queue_alloc(sizeof(struct jtag_command));
340
341 jtag_queue_command(cmd);
342
343 cmd->type = JTAG_SLEEP;
344
345 cmd->cmd.sleep = cmd_queue_alloc(sizeof(struct sleep_command));
346 cmd->cmd.sleep->us = us;
347
348 return ERROR_OK;
349 }
350
351 /* add callback to end of queue */
352 void interface_jtag_add_callback4(jtag_callback_t callback,
353 jtag_callback_data_t data0, jtag_callback_data_t data1,
354 jtag_callback_data_t data2, jtag_callback_data_t data3)
355 {
356 struct jtag_callback_entry *entry = cmd_queue_alloc(sizeof(struct jtag_callback_entry));
357
358 entry->next = NULL;
359 entry->callback = callback;
360 entry->data0 = data0;
361 entry->data1 = data1;
362 entry->data2 = data2;
363 entry->data3 = data3;
364
365 if (jtag_callback_queue_head == NULL) {
366 jtag_callback_queue_head = entry;
367 jtag_callback_queue_tail = entry;
368 } else {
369 jtag_callback_queue_tail->next = entry;
370 jtag_callback_queue_tail = entry;
371 }
372 }
373
374 int interface_jtag_execute_queue(void)
375 {
376 static int reentry;
377
378 assert(reentry == 0);
379 reentry++;
380
381 int retval = default_interface_jtag_execute_queue();
382 if (retval == ERROR_OK) {
383 struct jtag_callback_entry *entry;
384 for (entry = jtag_callback_queue_head; entry != NULL; entry = entry->next) {
385 retval = entry->callback(entry->data0, entry->data1, entry->data2, entry->data3);
386 if (retval != ERROR_OK)
387 break;
388 }
389 }
390
391 jtag_command_queue_reset();
392 jtag_callback_queue_reset();
393
394 reentry--;
395
396 return retval;
397 }
398
399 static int jtag_convert_to_callback4(jtag_callback_data_t data0,
400 jtag_callback_data_t data1, jtag_callback_data_t data2, jtag_callback_data_t data3)
401 {
402 ((jtag_callback1_t)data1)(data0);
403 return ERROR_OK;
404 }
405
406 void interface_jtag_add_callback(jtag_callback1_t callback, jtag_callback_data_t data0)
407 {
408 jtag_add_callback4(jtag_convert_to_callback4, data0, (jtag_callback_data_t)callback, 0, 0);
409 }
410
411 void jtag_add_callback(jtag_callback1_t f, jtag_callback_data_t data0)
412 {
413 interface_jtag_add_callback(f, data0);
414 }
415
416 void jtag_add_callback4(jtag_callback_t f, jtag_callback_data_t data0,
417 jtag_callback_data_t data1, jtag_callback_data_t data2,
418 jtag_callback_data_t data3)
419 {
420 interface_jtag_add_callback4(f, data0, data1, data2, data3);
421 }

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)