cadd88e8f400fc634cd3dbf24704be1c5306ddea
[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,2008 Ø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, write to the *
27 * Free Software Foundation, Inc., *
28 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
29 ***************************************************************************/
30 #ifdef HAVE_CONFIG_H
31 #include "config.h"
32 #endif
33
34 #include "interface.h"
35 #include "minidriver.h"
36 #include "command.h"
37
38 struct jtag_callback_entry
39 {
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 = NULL;
50 static struct jtag_callback_entry *jtag_callback_queue_tail = NULL;
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->tap = src->tap;
66 dst->num_bits = src->num_bits;
67 dst->out_value = buf_cpy(src->out_value, cmd_queue_alloc(DIV_ROUND_UP(src->num_bits, 8)), src->num_bits);
68 dst->in_value = src->in_value;
69 }
70
71
72 /**
73 * see jtag_add_ir_scan()
74 *
75 */
76 int interface_jtag_add_ir_scan(int in_num_fields, const struct scan_field *in_fields, tap_state_t state)
77 {
78 size_t num_taps = jtag_tap_count_enabled();
79
80 struct jtag_command * cmd = cmd_queue_alloc(sizeof(struct jtag_command));
81 struct scan_command * scan = cmd_queue_alloc(sizeof(struct scan_command));
82 struct scan_field * out_fields = cmd_queue_alloc(num_taps * sizeof(struct scan_field));
83
84 jtag_queue_command(cmd);
85
86 cmd->type = JTAG_SCAN;
87 cmd->cmd.scan = scan;
88
89 scan->ir_scan = true;
90 scan->num_fields = num_taps; /* one field per device */
91 scan->fields = out_fields;
92 scan->end_state = state;
93
94
95 struct scan_field * field = out_fields; /* keep track where we insert data */
96
97 /* loop over all enabled TAPs */
98
99 for (struct jtag_tap * tap = jtag_tap_next_enabled(NULL); tap != NULL; tap = jtag_tap_next_enabled(tap))
100 {
101 /* search the input field list for fields for the current TAP */
102
103 bool found = false;
104
105 for (int j = 0; j < in_num_fields; j++)
106 {
107 if (tap != in_fields[j].tap)
108 continue;
109
110 /* if TAP is listed in input fields, copy the value */
111
112 found = true;
113
114 tap->bypass = 0;
115
116 assert(in_fields[j].num_bits == tap->ir_length); /* input fields must have the same length as the TAP's IR */
117
118 cmd_queue_scan_field_clone(field, in_fields + j);
119
120 break;
121 }
122
123 if (!found)
124 {
125 /* if a TAP isn't listed in input fields, set it to BYPASS */
126
127 tap->bypass = 1;
128
129 field->tap = tap;
130 field->num_bits = tap->ir_length;
131 field->out_value = buf_set_ones(cmd_queue_alloc(DIV_ROUND_UP(tap->ir_length, 8)), tap->ir_length);
132 field->in_value = NULL; /* do not collect input for tap's in bypass */
133 }
134
135 /* update device information */
136 buf_cpy(field->out_value, tap->cur_instr, tap->ir_length);
137
138 field++;
139 }
140
141 assert(field == out_fields + num_taps); /* paranoia: jtag_tap_count_enabled() and jtag_tap_next_enabled() not in sync */
142
143 return ERROR_OK;
144 }
145
146 /**
147 * see jtag_add_plain_ir_scan()
148 *
149 */
150 int interface_jtag_add_plain_ir_scan(int in_num_fields, const struct scan_field *in_fields, tap_state_t state)
151 {
152
153 struct jtag_command * cmd = cmd_queue_alloc(sizeof(struct jtag_command));
154 struct scan_command * scan = cmd_queue_alloc(sizeof(struct scan_command));
155 struct scan_field * out_fields = cmd_queue_alloc(in_num_fields * sizeof(struct scan_field));
156
157 jtag_queue_command(cmd);
158
159 cmd->type = JTAG_SCAN;
160 cmd->cmd.scan = scan;
161
162 scan->ir_scan = true;
163 scan->num_fields = in_num_fields;
164 scan->fields = out_fields;
165 scan->end_state = state;
166
167 for (int i = 0; i < in_num_fields; i++)
168 cmd_queue_scan_field_clone(out_fields + i, in_fields + i);
169
170 return ERROR_OK;
171 }
172
173
174
175 /**
176 * see jtag_add_dr_scan()
177 *
178 */
179 int interface_jtag_add_dr_scan(int in_num_fields, const struct scan_field *in_fields, tap_state_t state)
180 {
181 /* count devices in bypass */
182
183 size_t bypass_devices = 0;
184
185 for (struct jtag_tap * tap = jtag_tap_next_enabled(NULL); tap != NULL; tap = jtag_tap_next_enabled(tap))
186 {
187 if (tap->bypass)
188 bypass_devices++;
189 }
190
191 struct jtag_command * cmd = cmd_queue_alloc(sizeof(struct jtag_command));
192 struct scan_command * scan = cmd_queue_alloc(sizeof(struct scan_command));
193 struct scan_field * out_fields = cmd_queue_alloc((in_num_fields + bypass_devices) * sizeof(struct scan_field));
194
195 jtag_queue_command(cmd);
196
197 cmd->type = JTAG_SCAN;
198 cmd->cmd.scan = scan;
199
200 scan->ir_scan = false;
201 scan->num_fields = in_num_fields + bypass_devices;
202 scan->fields = out_fields;
203 scan->end_state = state;
204
205
206 struct scan_field * field = out_fields; /* keep track where we insert data */
207
208 /* loop over all enabled TAPs */
209
210 for (struct jtag_tap * tap = jtag_tap_next_enabled(NULL); tap != NULL; tap = jtag_tap_next_enabled(tap))
211 {
212 /* if TAP is not bypassed insert matching input fields */
213
214 if (!tap->bypass)
215 {
216 struct scan_field * start_field = field; /* keep initial position for assert() */
217
218 for (int j = 0; j < in_num_fields; j++)
219 {
220 if (tap != in_fields[j].tap)
221 continue;
222
223 cmd_queue_scan_field_clone(field, in_fields + j);
224
225 field++;
226 }
227
228 assert(field > start_field); /* must have at least one input field per not bypassed TAP */
229 }
230
231 /* if a TAP is bypassed, generated a dummy bit*/
232 else
233 {
234 field->tap = tap;
235 field->num_bits = 1;
236 field->out_value = NULL;
237 field->in_value = NULL;
238
239 field++;
240 }
241 }
242
243 assert(field == out_fields + scan->num_fields); /* no superfluous input fields permitted */
244
245 return ERROR_OK;
246 }
247
248
249
250 /**
251 * Generate a DR SCAN using the array of output values passed to the function
252 *
253 * This function assumes that the parameter target_tap specifies the one TAP
254 * that is not bypassed. All other TAPs must be bypassed and the function will
255 * generate a dummy 1bit field for them.
256 *
257 * For the target_tap a sequence of output-only fields will be generated where
258 * each field has the size num_bits and the field's values are taken from
259 * the array value.
260 *
261 * The bypass status of TAPs is set by jtag_add_ir_scan().
262 *
263 */
264 void interface_jtag_add_dr_out(struct jtag_tap *target_tap,
265 int in_num_fields,
266 const int *num_bits,
267 const uint32_t *value,
268 tap_state_t end_state)
269 {
270 /* count devices in bypass */
271
272 size_t bypass_devices = 0;
273
274 for (struct jtag_tap * tap = jtag_tap_next_enabled(NULL); tap != NULL; tap = jtag_tap_next_enabled(tap))
275 {
276 if (tap->bypass)
277 bypass_devices++;
278 }
279
280
281 struct jtag_command * cmd = cmd_queue_alloc(sizeof(struct jtag_command));
282 struct scan_command * scan = cmd_queue_alloc(sizeof(struct scan_command));
283 struct scan_field * out_fields = cmd_queue_alloc((in_num_fields + bypass_devices) * sizeof(struct scan_field));
284
285 jtag_queue_command(cmd);
286
287 cmd->type = JTAG_SCAN;
288 cmd->cmd.scan = scan;
289
290 scan->ir_scan = false;
291 scan->num_fields = in_num_fields + bypass_devices;
292 scan->fields = out_fields;
293 scan->end_state = end_state;
294
295
296 bool target_tap_match = false;
297
298 struct scan_field * field = out_fields; /* keep track where we insert data */
299
300 /* loop over all enabled TAPs */
301
302 for (struct jtag_tap * tap = jtag_tap_next_enabled(NULL); tap != NULL; tap = jtag_tap_next_enabled(tap))
303 {
304 /* if TAP is not bypassed insert matching input fields */
305
306 if (!tap->bypass)
307 {
308 assert(tap == target_tap); /* target_tap must match the one not bypassed TAP */
309
310 target_tap_match = true;
311
312 for (int j = 0; j < in_num_fields; j++)
313 {
314 uint8_t out_value[4];
315 size_t scan_size = num_bits[j];
316 buf_set_u32(out_value, 0, scan_size, value[j]);
317
318 field->tap = tap;
319 field->num_bits = scan_size;
320 field->out_value = buf_cpy(out_value, cmd_queue_alloc(DIV_ROUND_UP(scan_size, 8)), scan_size);
321 field->in_value = NULL;
322
323 field++;
324 }
325 }
326
327 /* if a TAP is bypassed, generated a dummy bit*/
328 else
329 {
330
331 field->tap = tap;
332 field->num_bits = 1;
333 field->out_value = NULL;
334 field->in_value = NULL;
335
336 field++;
337 }
338 }
339
340 assert(target_tap_match); /* target_tap should be enabled and not bypassed */
341 }
342
343 /**
344 * see jtag_add_plain_dr_scan()
345 *
346 */
347 int interface_jtag_add_plain_dr_scan(int in_num_fields, const struct scan_field *in_fields, tap_state_t state)
348 {
349 struct jtag_command * cmd = cmd_queue_alloc(sizeof(struct jtag_command));
350 struct scan_command * scan = cmd_queue_alloc(sizeof(struct scan_command));
351 struct scan_field * out_fields = cmd_queue_alloc(in_num_fields * sizeof(struct scan_field));
352
353 jtag_queue_command(cmd);
354
355 cmd->type = JTAG_SCAN;
356 cmd->cmd.scan = scan;
357
358 scan->ir_scan = false;
359 scan->num_fields = in_num_fields;
360 scan->fields = out_fields;
361 scan->end_state = state;
362
363 for (int i = 0; i < in_num_fields; i++)
364 cmd_queue_scan_field_clone(out_fields + i, in_fields + i);
365
366 return ERROR_OK;
367 }
368
369 int interface_jtag_add_tlr(void)
370 {
371 tap_state_t state = TAP_RESET;
372
373 /* allocate memory for a new list member */
374 struct jtag_command * cmd = cmd_queue_alloc(sizeof(struct jtag_command));
375
376 jtag_queue_command(cmd);
377
378 cmd->type = JTAG_STATEMOVE;
379
380 cmd->cmd.statemove = cmd_queue_alloc(sizeof(struct statemove_command));
381 cmd->cmd.statemove->end_state = state;
382
383 return ERROR_OK;
384 }
385
386 int interface_jtag_add_pathmove(int num_states, const tap_state_t *path)
387 {
388 /* allocate memory for a new list member */
389 struct jtag_command * cmd = cmd_queue_alloc(sizeof(struct jtag_command));
390
391 jtag_queue_command(cmd);
392
393 cmd->type = JTAG_PATHMOVE;
394
395 cmd->cmd.pathmove = cmd_queue_alloc(sizeof(struct pathmove_command));
396 cmd->cmd.pathmove->num_states = num_states;
397 cmd->cmd.pathmove->path = cmd_queue_alloc(sizeof(tap_state_t) * num_states);
398
399 for (int i = 0; i < num_states; i++)
400 cmd->cmd.pathmove->path[i] = path[i];
401
402 return ERROR_OK;
403 }
404
405 int interface_jtag_add_runtest(int num_cycles, tap_state_t state)
406 {
407 /* allocate memory for a new list member */
408 struct jtag_command * cmd = cmd_queue_alloc(sizeof(struct jtag_command));
409
410 jtag_queue_command(cmd);
411
412 cmd->type = JTAG_RUNTEST;
413
414 cmd->cmd.runtest = cmd_queue_alloc(sizeof(struct runtest_command));
415 cmd->cmd.runtest->num_cycles = num_cycles;
416 cmd->cmd.runtest->end_state = state;
417
418 return ERROR_OK;
419 }
420
421 int interface_jtag_add_clocks(int num_cycles)
422 {
423 /* allocate memory for a new list member */
424 struct jtag_command * cmd = cmd_queue_alloc(sizeof(struct jtag_command));
425
426 jtag_queue_command(cmd);
427
428 cmd->type = JTAG_STABLECLOCKS;
429
430 cmd->cmd.stableclocks = cmd_queue_alloc(sizeof(struct stableclocks_command));
431 cmd->cmd.stableclocks->num_cycles = num_cycles;
432
433 return ERROR_OK;
434 }
435
436 int interface_jtag_add_reset(int req_trst, int req_srst)
437 {
438 /* allocate memory for a new list member */
439 struct jtag_command * cmd = cmd_queue_alloc(sizeof(struct jtag_command));
440
441 jtag_queue_command(cmd);
442
443 cmd->type = JTAG_RESET;
444
445 cmd->cmd.reset = cmd_queue_alloc(sizeof(struct reset_command));
446 cmd->cmd.reset->trst = req_trst;
447 cmd->cmd.reset->srst = req_srst;
448
449 return ERROR_OK;
450 }
451
452 int interface_jtag_add_sleep(uint32_t us)
453 {
454 /* allocate memory for a new list member */
455 struct jtag_command * cmd = cmd_queue_alloc(sizeof(struct jtag_command));
456
457 jtag_queue_command(cmd);
458
459 cmd->type = JTAG_SLEEP;
460
461 cmd->cmd.sleep = cmd_queue_alloc(sizeof(struct sleep_command));
462 cmd->cmd.sleep->us = us;
463
464 return ERROR_OK;
465 }
466
467 /* add callback to end of queue */
468 void interface_jtag_add_callback4(jtag_callback_t callback, jtag_callback_data_t data0, jtag_callback_data_t data1, jtag_callback_data_t data2, jtag_callback_data_t data3)
469 {
470 struct jtag_callback_entry *entry = cmd_queue_alloc(sizeof(struct jtag_callback_entry));
471
472 entry->next = NULL;
473 entry->callback = callback;
474 entry->data0 = data0;
475 entry->data1 = data1;
476 entry->data2 = data2;
477 entry->data3 = data3;
478
479 if (jtag_callback_queue_head == NULL)
480 {
481 jtag_callback_queue_head = entry;
482 jtag_callback_queue_tail = entry;
483 } else
484 {
485 jtag_callback_queue_tail->next = entry;
486 jtag_callback_queue_tail = entry;
487 }
488 }
489
490 int interface_jtag_execute_queue(void)
491 {
492 static int reentry = 0;
493
494 assert(reentry==0);
495 reentry++;
496
497 int retval = default_interface_jtag_execute_queue();
498 if (retval == ERROR_OK)
499 {
500 struct jtag_callback_entry *entry;
501 for (entry = jtag_callback_queue_head; entry != NULL; entry = entry->next)
502 {
503 retval = entry->callback(entry->data0, entry->data1, entry->data2, entry->data3);
504 if (retval != ERROR_OK)
505 break;
506 }
507 }
508
509 jtag_command_queue_reset();
510 jtag_callback_queue_reset();
511
512 reentry--;
513
514 return retval;
515 }
516
517 static int jtag_convert_to_callback4(jtag_callback_data_t data0, jtag_callback_data_t data1, jtag_callback_data_t data2, jtag_callback_data_t data3)
518 {
519 ((jtag_callback1_t)data1)(data0);
520 return ERROR_OK;
521 }
522
523 void interface_jtag_add_callback(jtag_callback1_t callback, jtag_callback_data_t data0)
524 {
525 jtag_add_callback4(jtag_convert_to_callback4, data0, (jtag_callback_data_t)callback, 0, 0);
526 }
527

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)