cmsis-dap: add initial cmsis-dap support
[openocd.git] / src / jtag / tcl.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, write to the *
27 * Free Software Foundation, Inc., *
28 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
29 ***************************************************************************/
30
31 #ifdef HAVE_CONFIG_H
32 #include "config.h"
33 #endif
34
35 #include "jtag.h"
36 #include "swd.h"
37 #include "minidriver.h"
38 #include "interface.h"
39 #include "interfaces.h"
40 #include "tcl.h"
41
42 #ifdef HAVE_STRINGS_H
43 #include <strings.h>
44 #endif
45
46 #include <helper/time_support.h>
47
48 /**
49 * @file
50 * Holds support for accessing JTAG-specific mechanisms from TCl scripts.
51 */
52
53 static const Jim_Nvp nvp_jtag_tap_event[] = {
54 { .value = JTAG_TRST_ASSERTED, .name = "post-reset" },
55 { .value = JTAG_TAP_EVENT_SETUP, .name = "setup" },
56 { .value = JTAG_TAP_EVENT_ENABLE, .name = "tap-enable" },
57 { .value = JTAG_TAP_EVENT_DISABLE, .name = "tap-disable" },
58
59 { .name = NULL, .value = -1 }
60 };
61
62 struct jtag_tap *jtag_tap_by_jim_obj(Jim_Interp *interp, Jim_Obj *o)
63 {
64 const char *cp = Jim_GetString(o, NULL);
65 struct jtag_tap *t = cp ? jtag_tap_by_string(cp) : NULL;
66 if (NULL == cp)
67 cp = "(unknown)";
68 if (NULL == t)
69 Jim_SetResultFormatted(interp, "Tap '%s' could not be found", cp);
70 return t;
71 }
72
73 static bool scan_is_safe(tap_state_t state)
74 {
75 switch (state) {
76 case TAP_RESET:
77 case TAP_IDLE:
78 case TAP_DRPAUSE:
79 case TAP_IRPAUSE:
80 return true;
81 default:
82 return false;
83 }
84 }
85
86 static int Jim_Command_drscan(Jim_Interp *interp, int argc, Jim_Obj *const *args)
87 {
88 int retval;
89 struct scan_field *fields;
90 int num_fields;
91 int field_count = 0;
92 int i, e;
93 struct jtag_tap *tap;
94 tap_state_t endstate;
95
96 /* args[1] = device
97 * args[2] = num_bits
98 * args[3] = hex string
99 * ... repeat num bits and hex string ...
100 *
101 * .. optionally:
102 * args[N-2] = "-endstate"
103 * args[N-1] = statename
104 */
105 if ((argc < 4) || ((argc % 2) != 0)) {
106 Jim_WrongNumArgs(interp, 1, args, "wrong arguments");
107 return JIM_ERR;
108 }
109
110 endstate = TAP_IDLE;
111
112 script_debug(interp, "drscan", argc, args);
113
114 /* validate arguments as numbers */
115 e = JIM_OK;
116 for (i = 2; i < argc; i += 2) {
117 long bits;
118 const char *cp;
119
120 e = Jim_GetLong(interp, args[i], &bits);
121 /* If valid - try next arg */
122 if (e == JIM_OK)
123 continue;
124
125 /* Not valid.. are we at the end? */
126 if (((i + 2) != argc)) {
127 /* nope, then error */
128 return e;
129 }
130
131 /* it could be: "-endstate FOO"
132 * e.g. DRPAUSE so we can issue more instructions
133 * before entering RUN/IDLE and executing them.
134 */
135
136 /* get arg as a string. */
137 cp = Jim_GetString(args[i], NULL);
138 /* is it the magic? */
139 if (0 == strcmp("-endstate", cp)) {
140 /* is the statename valid? */
141 cp = Jim_GetString(args[i + 1], NULL);
142
143 /* see if it is a valid state name */
144 endstate = tap_state_by_name(cp);
145 if (endstate < 0) {
146 /* update the error message */
147 Jim_SetResultFormatted(interp, "endstate: %s invalid", cp);
148 } else {
149 if (!scan_is_safe(endstate))
150 LOG_WARNING("drscan with unsafe "
151 "endstate \"%s\"", cp);
152
153 /* valid - so clear the error */
154 e = JIM_OK;
155 /* and remove the last 2 args */
156 argc -= 2;
157 }
158 }
159
160 /* Still an error? */
161 if (e != JIM_OK)
162 return e; /* too bad */
163 } /* validate args */
164
165 assert(e == JIM_OK);
166
167 tap = jtag_tap_by_jim_obj(interp, args[1]);
168 if (tap == NULL)
169 return JIM_ERR;
170
171 num_fields = (argc-2)/2;
172 assert(num_fields > 0);
173 fields = malloc(sizeof(struct scan_field) * num_fields);
174 for (i = 2; i < argc; i += 2) {
175 long bits;
176 int len;
177 const char *str;
178
179 Jim_GetLong(interp, args[i], &bits);
180 str = Jim_GetString(args[i + 1], &len);
181
182 fields[field_count].num_bits = bits;
183 void *t = malloc(DIV_ROUND_UP(bits, 8));
184 fields[field_count].out_value = t;
185 str_to_buf(str, len, t, bits, 0);
186 fields[field_count].in_value = t;
187 field_count++;
188 }
189
190 jtag_add_dr_scan(tap, num_fields, fields, endstate);
191
192 retval = jtag_execute_queue();
193 if (retval != ERROR_OK) {
194 Jim_SetResultString(interp, "drscan: jtag execute failed", -1);
195 return JIM_ERR;
196 }
197
198 field_count = 0;
199 Jim_Obj *list = Jim_NewListObj(interp, NULL, 0);
200 for (i = 2; i < argc; i += 2) {
201 long bits;
202 char *str;
203
204 Jim_GetLong(interp, args[i], &bits);
205 str = buf_to_str(fields[field_count].in_value, bits, 16);
206 free(fields[field_count].in_value);
207
208 Jim_ListAppendElement(interp, list, Jim_NewStringObj(interp, str, strlen(str)));
209 free(str);
210 field_count++;
211 }
212
213 Jim_SetResult(interp, list);
214
215 free(fields);
216
217 return JIM_OK;
218 }
219
220
221 static int Jim_Command_pathmove(Jim_Interp *interp, int argc, Jim_Obj *const *args)
222 {
223 tap_state_t states[8];
224
225 if ((argc < 2) || ((size_t)argc > (ARRAY_SIZE(states) + 1))) {
226 Jim_WrongNumArgs(interp, 1, args, "wrong arguments");
227 return JIM_ERR;
228 }
229
230 script_debug(interp, "pathmove", argc, args);
231
232 int i;
233 for (i = 0; i < argc-1; i++) {
234 const char *cp;
235 cp = Jim_GetString(args[i + 1], NULL);
236 states[i] = tap_state_by_name(cp);
237 if (states[i] < 0) {
238 /* update the error message */
239 Jim_SetResultFormatted(interp, "endstate: %s invalid", cp);
240 return JIM_ERR;
241 }
242 }
243
244 if ((jtag_add_statemove(states[0]) != ERROR_OK) || (jtag_execute_queue() != ERROR_OK)) {
245 Jim_SetResultString(interp, "pathmove: jtag execute failed", -1);
246 return JIM_ERR;
247 }
248
249 jtag_add_pathmove(argc - 2, states + 1);
250
251 if (jtag_execute_queue() != ERROR_OK) {
252 Jim_SetResultString(interp, "pathmove: failed", -1);
253 return JIM_ERR;
254 }
255
256 return JIM_OK;
257 }
258
259
260 static int Jim_Command_flush_count(Jim_Interp *interp, int argc, Jim_Obj *const *args)
261 {
262 script_debug(interp, "flush_count", argc, args);
263
264 Jim_SetResult(interp, Jim_NewIntObj(interp, jtag_get_flush_queue_count()));
265
266 return JIM_OK;
267 }
268
269 /* REVISIT Just what about these should "move" ... ?
270 * These registrations, into the main JTAG table?
271 *
272 * There's a minor compatibility issue, these all show up twice;
273 * that's not desirable:
274 * - jtag drscan ... NOT DOCUMENTED!
275 * - drscan ...
276 *
277 * The "irscan" command (for example) doesn't show twice.
278 */
279 static const struct command_registration jtag_command_handlers_to_move[] = {
280 {
281 .name = "drscan",
282 .mode = COMMAND_EXEC,
283 .jim_handler = Jim_Command_drscan,
284 .help = "Execute Data Register (DR) scan for one TAP. "
285 "Other TAPs must be in BYPASS mode.",
286 .usage = "tap_name [num_bits value]* ['-endstate' state_name]",
287 },
288 {
289 .name = "flush_count",
290 .mode = COMMAND_EXEC,
291 .jim_handler = Jim_Command_flush_count,
292 .help = "Returns the number of times the JTAG queue "
293 "has been flushed.",
294 },
295 {
296 .name = "pathmove",
297 .mode = COMMAND_EXEC,
298 .jim_handler = Jim_Command_pathmove,
299 .usage = "start_state state1 [state2 [state3 ...]]",
300 .help = "Move JTAG state machine from current state "
301 "(start_state) to state1, then state2, state3, etc.",
302 },
303 COMMAND_REGISTRATION_DONE
304 };
305
306
307 enum jtag_tap_cfg_param {
308 JCFG_EVENT
309 };
310
311 static Jim_Nvp nvp_config_opts[] = {
312 { .name = "-event", .value = JCFG_EVENT },
313
314 { .name = NULL, .value = -1 }
315 };
316
317 static int jtag_tap_configure_event(Jim_GetOptInfo *goi, struct jtag_tap *tap)
318 {
319 if (goi->argc == 0) {
320 Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "-event <event-name> ...");
321 return JIM_ERR;
322 }
323
324 Jim_Nvp *n;
325 int e = Jim_GetOpt_Nvp(goi, nvp_jtag_tap_event, &n);
326 if (e != JIM_OK) {
327 Jim_GetOpt_NvpUnknown(goi, nvp_jtag_tap_event, 1);
328 return e;
329 }
330
331 if (goi->isconfigure) {
332 if (goi->argc != 1) {
333 Jim_WrongNumArgs(goi->interp,
334 goi->argc,
335 goi->argv,
336 "-event <event-name> <event-body>");
337 return JIM_ERR;
338 }
339 } else {
340 if (goi->argc != 0) {
341 Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "-event <event-name>");
342 return JIM_ERR;
343 }
344 }
345
346 struct jtag_tap_event_action *jteap = tap->event_action;
347 /* replace existing event body */
348 bool found = false;
349 while (jteap) {
350 if (jteap->event == (enum jtag_event)n->value) {
351 found = true;
352 break;
353 }
354 jteap = jteap->next;
355 }
356
357 Jim_SetEmptyResult(goi->interp);
358
359 if (goi->isconfigure) {
360 if (!found)
361 jteap = calloc(1, sizeof(*jteap));
362 else if (NULL != jteap->body)
363 Jim_DecrRefCount(goi->interp, jteap->body);
364
365 jteap->interp = goi->interp;
366 jteap->event = n->value;
367
368 Jim_Obj *o;
369 Jim_GetOpt_Obj(goi, &o);
370 jteap->body = Jim_DuplicateObj(goi->interp, o);
371 Jim_IncrRefCount(jteap->body);
372
373 if (!found) {
374 /* add to head of event list */
375 jteap->next = tap->event_action;
376 tap->event_action = jteap;
377 }
378 } else if (found) {
379 jteap->interp = goi->interp;
380 Jim_SetResult(goi->interp,
381 Jim_DuplicateObj(goi->interp, jteap->body));
382 }
383 return JIM_OK;
384 }
385
386 static int jtag_tap_configure_cmd(Jim_GetOptInfo *goi, struct jtag_tap *tap)
387 {
388 /* parse config or cget options */
389 while (goi->argc > 0) {
390 Jim_SetEmptyResult(goi->interp);
391
392 Jim_Nvp *n;
393 int e = Jim_GetOpt_Nvp(goi, nvp_config_opts, &n);
394 if (e != JIM_OK) {
395 Jim_GetOpt_NvpUnknown(goi, nvp_config_opts, 0);
396 return e;
397 }
398
399 switch (n->value) {
400 case JCFG_EVENT:
401 e = jtag_tap_configure_event(goi, tap);
402 if (e != JIM_OK)
403 return e;
404 break;
405 default:
406 Jim_SetResultFormatted(goi->interp, "unknown event: %s", n->name);
407 return JIM_ERR;
408 }
409 }
410
411 return JIM_OK;
412 }
413
414 static int is_bad_irval(int ir_length, jim_wide w)
415 {
416 jim_wide v = 1;
417
418 v <<= ir_length;
419 v -= 1;
420 v = ~v;
421 return (w & v) != 0;
422 }
423
424 static int jim_newtap_expected_id(Jim_Nvp *n, Jim_GetOptInfo *goi,
425 struct jtag_tap *pTap)
426 {
427 jim_wide w;
428 int e = Jim_GetOpt_Wide(goi, &w);
429 if (e != JIM_OK) {
430 Jim_SetResultFormatted(goi->interp, "option: %s bad parameter", n->name);
431 return e;
432 }
433
434 unsigned expected_len = sizeof(uint32_t) * pTap->expected_ids_cnt;
435 uint32_t *new_expected_ids = malloc(expected_len + sizeof(uint32_t));
436 if (new_expected_ids == NULL) {
437 Jim_SetResultFormatted(goi->interp, "no memory");
438 return JIM_ERR;
439 }
440
441 memcpy(new_expected_ids, pTap->expected_ids, expected_len);
442
443 new_expected_ids[pTap->expected_ids_cnt] = w;
444
445 free(pTap->expected_ids);
446 pTap->expected_ids = new_expected_ids;
447 pTap->expected_ids_cnt++;
448
449 return JIM_OK;
450 }
451
452 #define NTAP_OPT_IRLEN 0
453 #define NTAP_OPT_IRMASK 1
454 #define NTAP_OPT_IRCAPTURE 2
455 #define NTAP_OPT_ENABLED 3
456 #define NTAP_OPT_DISABLED 4
457 #define NTAP_OPT_EXPECTED_ID 5
458 #define NTAP_OPT_VERSION 6
459
460 static int jim_newtap_ir_param(Jim_Nvp *n, Jim_GetOptInfo *goi,
461 struct jtag_tap *pTap)
462 {
463 jim_wide w;
464 int e = Jim_GetOpt_Wide(goi, &w);
465 if (e != JIM_OK) {
466 Jim_SetResultFormatted(goi->interp,
467 "option: %s bad parameter", n->name);
468 return e;
469 }
470 switch (n->value) {
471 case NTAP_OPT_IRLEN:
472 if (w > (jim_wide) (8 * sizeof(pTap->ir_capture_value))) {
473 LOG_WARNING("%s: huge IR length %d",
474 pTap->dotted_name, (int) w);
475 }
476 pTap->ir_length = w;
477 break;
478 case NTAP_OPT_IRMASK:
479 if (is_bad_irval(pTap->ir_length, w)) {
480 LOG_ERROR("%s: IR mask %x too big",
481 pTap->dotted_name,
482 (int) w);
483 return JIM_ERR;
484 }
485 if ((w & 3) != 3)
486 LOG_WARNING("%s: nonstandard IR mask", pTap->dotted_name);
487 pTap->ir_capture_mask = w;
488 break;
489 case NTAP_OPT_IRCAPTURE:
490 if (is_bad_irval(pTap->ir_length, w)) {
491 LOG_ERROR("%s: IR capture %x too big",
492 pTap->dotted_name, (int) w);
493 return JIM_ERR;
494 }
495 if ((w & 3) != 1)
496 LOG_WARNING("%s: nonstandard IR value",
497 pTap->dotted_name);
498 pTap->ir_capture_value = w;
499 break;
500 default:
501 return JIM_ERR;
502 }
503 return JIM_OK;
504 }
505
506 static int jim_newtap_cmd(Jim_GetOptInfo *goi)
507 {
508 struct jtag_tap *pTap;
509 int x;
510 int e;
511 Jim_Nvp *n;
512 char *cp;
513 const Jim_Nvp opts[] = {
514 { .name = "-irlen", .value = NTAP_OPT_IRLEN },
515 { .name = "-irmask", .value = NTAP_OPT_IRMASK },
516 { .name = "-ircapture", .value = NTAP_OPT_IRCAPTURE },
517 { .name = "-enable", .value = NTAP_OPT_ENABLED },
518 { .name = "-disable", .value = NTAP_OPT_DISABLED },
519 { .name = "-expected-id", .value = NTAP_OPT_EXPECTED_ID },
520 { .name = "-ignore-version", .value = NTAP_OPT_VERSION },
521 { .name = NULL, .value = -1 },
522 };
523
524 pTap = calloc(1, sizeof(struct jtag_tap));
525 if (!pTap) {
526 Jim_SetResultFormatted(goi->interp, "no memory");
527 return JIM_ERR;
528 }
529
530 /*
531 * we expect CHIP + TAP + OPTIONS
532 * */
533 if (goi->argc < 3) {
534 Jim_SetResultFormatted(goi->interp, "Missing CHIP TAP OPTIONS ....");
535 free(pTap);
536 return JIM_ERR;
537 }
538 Jim_GetOpt_String(goi, &cp, NULL);
539 pTap->chip = strdup(cp);
540
541 Jim_GetOpt_String(goi, &cp, NULL);
542 pTap->tapname = strdup(cp);
543
544 /* name + dot + name + null */
545 x = strlen(pTap->chip) + 1 + strlen(pTap->tapname) + 1;
546 cp = malloc(x);
547 sprintf(cp, "%s.%s", pTap->chip, pTap->tapname);
548 pTap->dotted_name = cp;
549
550 LOG_DEBUG("Creating New Tap, Chip: %s, Tap: %s, Dotted: %s, %d params",
551 pTap->chip, pTap->tapname, pTap->dotted_name, goi->argc);
552
553 /* IEEE specifies that the two LSBs of an IR scan are 01, so make
554 * that the default. The "-irlen" and "-irmask" options are only
555 * needed to cope with nonstandard TAPs, or to specify more bits.
556 */
557 pTap->ir_capture_mask = 0x03;
558 pTap->ir_capture_value = 0x01;
559
560 while (goi->argc) {
561 e = Jim_GetOpt_Nvp(goi, opts, &n);
562 if (e != JIM_OK) {
563 Jim_GetOpt_NvpUnknown(goi, opts, 0);
564 free(cp);
565 free(pTap);
566 return e;
567 }
568 LOG_DEBUG("Processing option: %s", n->name);
569 switch (n->value) {
570 case NTAP_OPT_ENABLED:
571 pTap->disabled_after_reset = false;
572 break;
573 case NTAP_OPT_DISABLED:
574 pTap->disabled_after_reset = true;
575 break;
576 case NTAP_OPT_EXPECTED_ID:
577 e = jim_newtap_expected_id(n, goi, pTap);
578 if (JIM_OK != e) {
579 free(cp);
580 free(pTap);
581 return e;
582 }
583 break;
584 case NTAP_OPT_IRLEN:
585 case NTAP_OPT_IRMASK:
586 case NTAP_OPT_IRCAPTURE:
587 e = jim_newtap_ir_param(n, goi, pTap);
588 if (JIM_OK != e) {
589 free(cp);
590 free(pTap);
591 return e;
592 }
593 break;
594 case NTAP_OPT_VERSION:
595 pTap->ignore_version = true;
596 break;
597 } /* switch (n->value) */
598 } /* while (goi->argc) */
599
600 /* default is enabled-after-reset */
601 pTap->enabled = !pTap->disabled_after_reset;
602
603 /* Did all the required option bits get cleared? */
604 if (pTap->ir_length != 0) {
605 jtag_tap_init(pTap);
606 return JIM_OK;
607 }
608
609 Jim_SetResultFormatted(goi->interp,
610 "newtap: %s missing IR length",
611 pTap->dotted_name);
612 jtag_tap_free(pTap);
613 return JIM_ERR;
614 }
615
616 static void jtag_tap_handle_event(struct jtag_tap *tap, enum jtag_event e)
617 {
618 struct jtag_tap_event_action *jteap;
619
620 for (jteap = tap->event_action; jteap != NULL; jteap = jteap->next) {
621 if (jteap->event != e)
622 continue;
623
624 Jim_Nvp *nvp = Jim_Nvp_value2name_simple(nvp_jtag_tap_event, e);
625 LOG_DEBUG("JTAG tap: %s event: %d (%s)\n\taction: %s",
626 tap->dotted_name, e, nvp->name,
627 Jim_GetString(jteap->body, NULL));
628
629 if (Jim_EvalObj(jteap->interp, jteap->body) != JIM_OK) {
630 Jim_MakeErrorMessage(jteap->interp);
631 LOG_USER("%s", Jim_GetString(Jim_GetResult(jteap->interp), NULL));
632 continue;
633 }
634
635 switch (e) {
636 case JTAG_TAP_EVENT_ENABLE:
637 case JTAG_TAP_EVENT_DISABLE:
638 /* NOTE: we currently assume the handlers
639 * can't fail. Right here is where we should
640 * really be verifying the scan chains ...
641 */
642 tap->enabled = (e == JTAG_TAP_EVENT_ENABLE);
643 LOG_INFO("JTAG tap: %s %s", tap->dotted_name,
644 tap->enabled ? "enabled" : "disabled");
645 break;
646 default:
647 break;
648 }
649 }
650 }
651
652 static int jim_jtag_arp_init(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
653 {
654 Jim_GetOptInfo goi;
655 Jim_GetOpt_Setup(&goi, interp, argc-1, argv + 1);
656 if (goi.argc != 0) {
657 Jim_WrongNumArgs(goi.interp, 1, goi.argv-1, "(no params)");
658 return JIM_ERR;
659 }
660 struct command_context *context = current_command_context(interp);
661 int e = jtag_init_inner(context);
662 if (e != ERROR_OK) {
663 Jim_Obj *eObj = Jim_NewIntObj(goi.interp, e);
664 Jim_SetResultFormatted(goi.interp, "error: %#s", eObj);
665 Jim_FreeNewObj(goi.interp, eObj);
666 return JIM_ERR;
667 }
668 return JIM_OK;
669 }
670
671 static int jim_jtag_arp_init_reset(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
672 {
673 int e = ERROR_OK;
674 Jim_GetOptInfo goi;
675 Jim_GetOpt_Setup(&goi, interp, argc-1, argv + 1);
676 if (goi.argc != 0) {
677 Jim_WrongNumArgs(goi.interp, 1, goi.argv-1, "(no params)");
678 return JIM_ERR;
679 }
680 struct command_context *context = current_command_context(interp);
681 if (transport_is_jtag())
682 e = jtag_init_reset(context);
683 else if (transport_is_swd())
684 e = swd_init_reset(context);
685
686 if (e != ERROR_OK) {
687 Jim_Obj *eObj = Jim_NewIntObj(goi.interp, e);
688 Jim_SetResultFormatted(goi.interp, "error: %#s", eObj);
689 Jim_FreeNewObj(goi.interp, eObj);
690 return JIM_ERR;
691 }
692 return JIM_OK;
693 }
694
695 int jim_jtag_newtap(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
696 {
697 Jim_GetOptInfo goi;
698 Jim_GetOpt_Setup(&goi, interp, argc-1, argv + 1);
699 return jim_newtap_cmd(&goi);
700 }
701
702 static bool jtag_tap_enable(struct jtag_tap *t)
703 {
704 if (t->enabled)
705 return false;
706 jtag_tap_handle_event(t, JTAG_TAP_EVENT_ENABLE);
707 if (!t->enabled)
708 return false;
709
710 /* FIXME add JTAG sanity checks, w/o TLR
711 * - scan chain length grew by one (this)
712 * - IDs and IR lengths are as expected
713 */
714 jtag_call_event_callbacks(JTAG_TAP_EVENT_ENABLE);
715 return true;
716 }
717 static bool jtag_tap_disable(struct jtag_tap *t)
718 {
719 if (!t->enabled)
720 return false;
721 jtag_tap_handle_event(t, JTAG_TAP_EVENT_DISABLE);
722 if (t->enabled)
723 return false;
724
725 /* FIXME add JTAG sanity checks, w/o TLR
726 * - scan chain length shrank by one (this)
727 * - IDs and IR lengths are as expected
728 */
729 jtag_call_event_callbacks(JTAG_TAP_EVENT_DISABLE);
730 return true;
731 }
732
733 int jim_jtag_tap_enabler(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
734 {
735 const char *cmd_name = Jim_GetString(argv[0], NULL);
736 Jim_GetOptInfo goi;
737 Jim_GetOpt_Setup(&goi, interp, argc-1, argv + 1);
738 if (goi.argc != 1) {
739 Jim_SetResultFormatted(goi.interp, "usage: %s <name>", cmd_name);
740 return JIM_ERR;
741 }
742
743 struct jtag_tap *t;
744
745 t = jtag_tap_by_jim_obj(goi.interp, goi.argv[0]);
746 if (t == NULL)
747 return JIM_ERR;
748
749 if (strcasecmp(cmd_name, "tapisenabled") == 0) {
750 /* do nothing, just return the value */
751 } else if (strcasecmp(cmd_name, "tapenable") == 0) {
752 if (!jtag_tap_enable(t)) {
753 LOG_WARNING("failed to enable tap %s", t->dotted_name);
754 return JIM_ERR;
755 }
756 } else if (strcasecmp(cmd_name, "tapdisable") == 0) {
757 if (!jtag_tap_disable(t)) {
758 LOG_WARNING("failed to disable tap %s", t->dotted_name);
759 return JIM_ERR;
760 }
761 } else {
762 LOG_ERROR("command '%s' unknown", cmd_name);
763 return JIM_ERR;
764 }
765 bool e = t->enabled;
766 Jim_SetResult(goi.interp, Jim_NewIntObj(goi.interp, e));
767 return JIM_OK;
768 }
769
770 int jim_jtag_configure(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
771 {
772 const char *cmd_name = Jim_GetString(argv[0], NULL);
773 Jim_GetOptInfo goi;
774 Jim_GetOpt_Setup(&goi, interp, argc-1, argv + 1);
775 goi.isconfigure = !strcmp(cmd_name, "configure");
776 if (goi.argc < 2 + goi.isconfigure) {
777 Jim_WrongNumArgs(goi.interp, 0, NULL,
778 "<tap_name> <attribute> ...");
779 return JIM_ERR;
780 }
781
782 struct jtag_tap *t;
783
784 Jim_Obj *o;
785 Jim_GetOpt_Obj(&goi, &o);
786 t = jtag_tap_by_jim_obj(goi.interp, o);
787 if (t == NULL)
788 return JIM_ERR;
789
790 return jtag_tap_configure_cmd(&goi, t);
791 }
792
793 static int jim_jtag_names(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
794 {
795 Jim_GetOptInfo goi;
796 Jim_GetOpt_Setup(&goi, interp, argc-1, argv + 1);
797 if (goi.argc != 0) {
798 Jim_WrongNumArgs(goi.interp, 1, goi.argv, "Too many parameters");
799 return JIM_ERR;
800 }
801 Jim_SetResult(goi.interp, Jim_NewListObj(goi.interp, NULL, 0));
802 struct jtag_tap *tap;
803
804 for (tap = jtag_all_taps(); tap; tap = tap->next_tap) {
805 Jim_ListAppendElement(goi.interp,
806 Jim_GetResult(goi.interp),
807 Jim_NewStringObj(goi.interp,
808 tap->dotted_name, -1));
809 }
810 return JIM_OK;
811 }
812
813 COMMAND_HANDLER(handle_jtag_init_command)
814 {
815 if (CMD_ARGC != 0)
816 return ERROR_COMMAND_SYNTAX_ERROR;
817
818 static bool jtag_initialized;
819 if (jtag_initialized) {
820 LOG_INFO("'jtag init' has already been called");
821 return ERROR_OK;
822 }
823 jtag_initialized = true;
824
825 LOG_DEBUG("Initializing jtag devices...");
826 return jtag_init(CMD_CTX);
827 }
828
829 static const struct command_registration jtag_subcommand_handlers[] = {
830 {
831 .name = "init",
832 .mode = COMMAND_ANY,
833 .handler = handle_jtag_init_command,
834 .help = "initialize jtag scan chain",
835 .usage = ""
836 },
837 {
838 .name = "arp_init",
839 .mode = COMMAND_ANY,
840 .jim_handler = jim_jtag_arp_init,
841 .help = "Validates JTAG scan chain against the list of "
842 "declared TAPs using just the four standard JTAG "
843 "signals.",
844 },
845 {
846 .name = "arp_init-reset",
847 .mode = COMMAND_ANY,
848 .jim_handler = jim_jtag_arp_init_reset,
849 .help = "Uses TRST and SRST to try resetting everything on "
850 "the JTAG scan chain, then performs 'jtag arp_init'."
851 },
852 {
853 .name = "newtap",
854 .mode = COMMAND_CONFIG,
855 .jim_handler = jim_jtag_newtap,
856 .help = "Create a new TAP instance named basename.tap_type, "
857 "and appends it to the scan chain.",
858 .usage = "basename tap_type '-irlen' count "
859 "['-enable'|'-disable'] "
860 "['-expected_id' number] "
861 "['-ignore-version'] "
862 "['-ircapture' number] "
863 "['-mask' number] ",
864 },
865 {
866 .name = "tapisenabled",
867 .mode = COMMAND_EXEC,
868 .jim_handler = jim_jtag_tap_enabler,
869 .help = "Returns a Tcl boolean (0/1) indicating whether "
870 "the TAP is enabled (1) or not (0).",
871 .usage = "tap_name",
872 },
873 {
874 .name = "tapenable",
875 .mode = COMMAND_EXEC,
876 .jim_handler = jim_jtag_tap_enabler,
877 .help = "Try to enable the specified TAP using the "
878 "'tap-enable' TAP event.",
879 .usage = "tap_name",
880 },
881 {
882 .name = "tapdisable",
883 .mode = COMMAND_EXEC,
884 .jim_handler = jim_jtag_tap_enabler,
885 .help = "Try to disable the specified TAP using the "
886 "'tap-disable' TAP event.",
887 .usage = "tap_name",
888 },
889 {
890 .name = "configure",
891 .mode = COMMAND_EXEC,
892 .jim_handler = jim_jtag_configure,
893 .help = "Provide a Tcl handler for the specified "
894 "TAP event.",
895 .usage = "tap_name '-event' event_name handler",
896 },
897 {
898 .name = "cget",
899 .mode = COMMAND_EXEC,
900 .jim_handler = jim_jtag_configure,
901 .help = "Return any Tcl handler for the specified "
902 "TAP event.",
903 .usage = "tap_name '-event' event_name",
904 },
905 {
906 .name = "names",
907 .mode = COMMAND_ANY,
908 .jim_handler = jim_jtag_names,
909 .help = "Returns list of all JTAG tap names.",
910 },
911 {
912 .chain = jtag_command_handlers_to_move,
913 },
914 COMMAND_REGISTRATION_DONE
915 };
916
917 void jtag_notify_event(enum jtag_event event)
918 {
919 struct jtag_tap *tap;
920
921 for (tap = jtag_all_taps(); tap; tap = tap->next_tap)
922 jtag_tap_handle_event(tap, event);
923 }
924
925
926 COMMAND_HANDLER(handle_scan_chain_command)
927 {
928 struct jtag_tap *tap;
929 char expected_id[12];
930
931 tap = jtag_all_taps();
932 command_print(CMD_CTX,
933 " TapName Enabled IdCode Expected IrLen IrCap IrMask");
934 command_print(CMD_CTX,
935 "-- ------------------- -------- ---------- ---------- ----- ----- ------");
936
937 while (tap) {
938 uint32_t expected, expected_mask, ii;
939
940 snprintf(expected_id, sizeof expected_id, "0x%08x",
941 (unsigned)((tap->expected_ids_cnt > 0)
942 ? tap->expected_ids[0]
943 : 0));
944 if (tap->ignore_version)
945 expected_id[2] = '*';
946
947 expected = buf_get_u32(tap->expected, 0, tap->ir_length);
948 expected_mask = buf_get_u32(tap->expected_mask, 0, tap->ir_length);
949
950 command_print(CMD_CTX,
951 "%2d %-18s %c 0x%08x %s %5d 0x%02x 0x%02x",
952 tap->abs_chain_position,
953 tap->dotted_name,
954 tap->enabled ? 'Y' : 'n',
955 (unsigned int)(tap->idcode),
956 expected_id,
957 (unsigned int)(tap->ir_length),
958 (unsigned int)(expected),
959 (unsigned int)(expected_mask));
960
961 for (ii = 1; ii < tap->expected_ids_cnt; ii++) {
962 snprintf(expected_id, sizeof expected_id, "0x%08x",
963 (unsigned) tap->expected_ids[ii]);
964 if (tap->ignore_version)
965 expected_id[2] = '*';
966
967 command_print(CMD_CTX,
968 " %s",
969 expected_id);
970 }
971
972 tap = tap->next_tap;
973 }
974
975 return ERROR_OK;
976 }
977
978 COMMAND_HANDLER(handle_jtag_ntrst_delay_command)
979 {
980 if (CMD_ARGC > 1)
981 return ERROR_COMMAND_SYNTAX_ERROR;
982 if (CMD_ARGC == 1) {
983 unsigned delay;
984 COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], delay);
985
986 jtag_set_ntrst_delay(delay);
987 }
988 command_print(CMD_CTX, "jtag_ntrst_delay: %u", jtag_get_ntrst_delay());
989 return ERROR_OK;
990 }
991
992 COMMAND_HANDLER(handle_jtag_ntrst_assert_width_command)
993 {
994 if (CMD_ARGC > 1)
995 return ERROR_COMMAND_SYNTAX_ERROR;
996 if (CMD_ARGC == 1) {
997 unsigned delay;
998 COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], delay);
999
1000 jtag_set_ntrst_assert_width(delay);
1001 }
1002 command_print(CMD_CTX, "jtag_ntrst_assert_width: %u", jtag_get_ntrst_assert_width());
1003 return ERROR_OK;
1004 }
1005
1006 COMMAND_HANDLER(handle_jtag_rclk_command)
1007 {
1008 if (CMD_ARGC > 1)
1009 return ERROR_COMMAND_SYNTAX_ERROR;
1010
1011 int retval = ERROR_OK;
1012 if (CMD_ARGC == 1) {
1013 unsigned khz = 0;
1014 COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], khz);
1015
1016 retval = jtag_config_rclk(khz);
1017 if (ERROR_OK != retval)
1018 return retval;
1019 }
1020
1021 int cur_khz = jtag_get_speed_khz();
1022 retval = jtag_get_speed_readable(&cur_khz);
1023 if (ERROR_OK != retval)
1024 return retval;
1025
1026 if (cur_khz)
1027 command_print(CMD_CTX, "RCLK not supported - fallback to %d kHz", cur_khz);
1028 else
1029 command_print(CMD_CTX, "RCLK - adaptive");
1030
1031 return retval;
1032 }
1033
1034 COMMAND_HANDLER(handle_jtag_reset_command)
1035 {
1036 if (CMD_ARGC != 2)
1037 return ERROR_COMMAND_SYNTAX_ERROR;
1038
1039 int trst = -1;
1040 if (CMD_ARGV[0][0] == '1')
1041 trst = 1;
1042 else if (CMD_ARGV[0][0] == '0')
1043 trst = 0;
1044 else
1045 return ERROR_COMMAND_SYNTAX_ERROR;
1046
1047 int srst = -1;
1048 if (CMD_ARGV[1][0] == '1')
1049 srst = 1;
1050 else if (CMD_ARGV[1][0] == '0')
1051 srst = 0;
1052 else
1053 return ERROR_COMMAND_SYNTAX_ERROR;
1054
1055 if (adapter_init(CMD_CTX) != ERROR_OK)
1056 return ERROR_JTAG_INIT_FAILED;
1057
1058 jtag_add_reset(trst, srst);
1059 return jtag_execute_queue();
1060 }
1061
1062 COMMAND_HANDLER(handle_runtest_command)
1063 {
1064 if (CMD_ARGC != 1)
1065 return ERROR_COMMAND_SYNTAX_ERROR;
1066
1067 unsigned num_clocks;
1068 COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], num_clocks);
1069
1070 jtag_add_runtest(num_clocks, TAP_IDLE);
1071 return jtag_execute_queue();
1072 }
1073
1074 /*
1075 * For "irscan" or "drscan" commands, the "end" (really, "next") state
1076 * should be stable ... and *NOT* a shift state, otherwise free-running
1077 * jtag clocks could change the values latched by the update state.
1078 * Not surprisingly, this is the same constraint as SVF; the "irscan"
1079 * and "drscan" commands are a write-only subset of what SVF provides.
1080 */
1081
1082 COMMAND_HANDLER(handle_irscan_command)
1083 {
1084 int i;
1085 struct scan_field *fields;
1086 struct jtag_tap *tap = NULL;
1087 tap_state_t endstate;
1088
1089 if ((CMD_ARGC < 2) || (CMD_ARGC % 2))
1090 return ERROR_COMMAND_SYNTAX_ERROR;
1091
1092 /* optional "-endstate" "statename" at the end of the arguments,
1093 * so that e.g. IRPAUSE can let us load the data register before
1094 * entering RUN/IDLE to execute the instruction we load here.
1095 */
1096 endstate = TAP_IDLE;
1097
1098 if (CMD_ARGC >= 4) {
1099 /* have at least one pair of numbers.
1100 * is last pair the magic text? */
1101 if (strcmp("-endstate", CMD_ARGV[CMD_ARGC - 2]) == 0) {
1102 endstate = tap_state_by_name(CMD_ARGV[CMD_ARGC - 1]);
1103 if (endstate == TAP_INVALID)
1104 return ERROR_COMMAND_SYNTAX_ERROR;
1105 if (!scan_is_safe(endstate))
1106 LOG_WARNING("unstable irscan endstate \"%s\"",
1107 CMD_ARGV[CMD_ARGC - 1]);
1108 CMD_ARGC -= 2;
1109 }
1110 }
1111
1112 int num_fields = CMD_ARGC / 2;
1113 if (num_fields > 1) {
1114 /* we really should be looking at plain_ir_scan if we want
1115 * anything more fancy.
1116 */
1117 LOG_ERROR("Specify a single value for tap");
1118 return ERROR_COMMAND_SYNTAX_ERROR;
1119 }
1120
1121 fields = calloc(num_fields, sizeof(*fields));
1122
1123 int retval;
1124 for (i = 0; i < num_fields; i++) {
1125 tap = jtag_tap_by_string(CMD_ARGV[i*2]);
1126 if (tap == NULL) {
1127 free(fields);
1128 command_print(CMD_CTX, "Tap: %s unknown", CMD_ARGV[i*2]);
1129
1130 return ERROR_FAIL;
1131 }
1132 int field_size = tap->ir_length;
1133 fields[i].num_bits = field_size;
1134 uint8_t *v = malloc(DIV_ROUND_UP(field_size, 8));
1135
1136 uint64_t value;
1137 retval = parse_u64(CMD_ARGV[i * 2 + 1], &value);
1138 if (ERROR_OK != retval)
1139 goto error_return;
1140 buf_set_u64(v, 0, field_size, value);
1141 fields[i].out_value = v;
1142 fields[i].in_value = NULL;
1143 }
1144
1145 /* did we have an endstate? */
1146 jtag_add_ir_scan(tap, fields, endstate);
1147
1148 retval = jtag_execute_queue();
1149
1150 error_return:
1151 for (i = 0; i < num_fields; i++) {
1152 if (NULL != fields[i].out_value)
1153 free((void *)fields[i].out_value);
1154 }
1155
1156 free(fields);
1157
1158 return retval;
1159 }
1160
1161 COMMAND_HANDLER(handle_verify_ircapture_command)
1162 {
1163 if (CMD_ARGC > 1)
1164 return ERROR_COMMAND_SYNTAX_ERROR;
1165
1166 if (CMD_ARGC == 1) {
1167 bool enable;
1168 COMMAND_PARSE_ENABLE(CMD_ARGV[0], enable);
1169 jtag_set_verify_capture_ir(enable);
1170 }
1171
1172 const char *status = jtag_will_verify_capture_ir() ? "enabled" : "disabled";
1173 command_print(CMD_CTX, "verify Capture-IR is %s", status);
1174
1175 return ERROR_OK;
1176 }
1177
1178 COMMAND_HANDLER(handle_verify_jtag_command)
1179 {
1180 if (CMD_ARGC > 1)
1181 return ERROR_COMMAND_SYNTAX_ERROR;
1182
1183 if (CMD_ARGC == 1) {
1184 bool enable;
1185 COMMAND_PARSE_ENABLE(CMD_ARGV[0], enable);
1186 jtag_set_verify(enable);
1187 }
1188
1189 const char *status = jtag_will_verify() ? "enabled" : "disabled";
1190 command_print(CMD_CTX, "verify jtag capture is %s", status);
1191
1192 return ERROR_OK;
1193 }
1194
1195 COMMAND_HANDLER(handle_tms_sequence_command)
1196 {
1197 if (CMD_ARGC > 1)
1198 return ERROR_COMMAND_SYNTAX_ERROR;
1199
1200 if (CMD_ARGC == 1) {
1201 bool use_new_table;
1202 if (strcmp(CMD_ARGV[0], "short") == 0)
1203 use_new_table = true;
1204 else if (strcmp(CMD_ARGV[0], "long") == 0)
1205 use_new_table = false;
1206 else
1207 return ERROR_COMMAND_SYNTAX_ERROR;
1208
1209 tap_use_new_tms_table(use_new_table);
1210 }
1211
1212 command_print(CMD_CTX, "tms sequence is %s",
1213 tap_uses_new_tms_table() ? "short" : "long");
1214
1215 return ERROR_OK;
1216 }
1217
1218 COMMAND_HANDLER(handle_jtag_flush_queue_sleep)
1219 {
1220 if (CMD_ARGC != 1)
1221 return ERROR_COMMAND_SYNTAX_ERROR;
1222
1223 int sleep_ms;
1224 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], sleep_ms);
1225
1226 jtag_set_flush_queue_sleep(sleep_ms);
1227
1228 return ERROR_OK;
1229 }
1230
1231 COMMAND_HANDLER(handle_wait_srst_deassert)
1232 {
1233 if (CMD_ARGC != 1)
1234 return ERROR_COMMAND_SYNTAX_ERROR;
1235
1236 int timeout_ms;
1237 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], timeout_ms);
1238 if ((timeout_ms <= 0) || (timeout_ms > 100000)) {
1239 LOG_ERROR("Timeout must be an integer between 0 and 100000");
1240 return ERROR_FAIL;
1241 }
1242
1243 LOG_USER("Waiting for srst assert + deassert for at most %dms", timeout_ms);
1244 int asserted_yet;
1245 long long then = timeval_ms();
1246 while (jtag_srst_asserted(&asserted_yet) == ERROR_OK) {
1247 if ((timeval_ms() - then) > timeout_ms) {
1248 LOG_ERROR("Timed out");
1249 return ERROR_FAIL;
1250 }
1251 if (asserted_yet)
1252 break;
1253 }
1254 while (jtag_srst_asserted(&asserted_yet) == ERROR_OK) {
1255 if ((timeval_ms() - then) > timeout_ms) {
1256 LOG_ERROR("Timed out");
1257 return ERROR_FAIL;
1258 }
1259 if (!asserted_yet)
1260 break;
1261 }
1262
1263 return ERROR_OK;
1264 }
1265
1266 static const struct command_registration jtag_command_handlers[] = {
1267
1268 {
1269 .name = "jtag_flush_queue_sleep",
1270 .handler = handle_jtag_flush_queue_sleep,
1271 .mode = COMMAND_ANY,
1272 .help = "For debug purposes(simulate long delays of interface) "
1273 "to test performance or change in behavior. Default 0ms.",
1274 .usage = "[sleep in ms]",
1275 },
1276 {
1277 .name = "jtag_rclk",
1278 .handler = handle_jtag_rclk_command,
1279 .mode = COMMAND_ANY,
1280 .help = "With an argument, change to to use adaptive clocking "
1281 "if possible; else to use the fallback speed. "
1282 "With or without argument, display current setting.",
1283 .usage = "[fallback_speed_khz]",
1284 },
1285 {
1286 .name = "jtag_ntrst_delay",
1287 .handler = handle_jtag_ntrst_delay_command,
1288 .mode = COMMAND_ANY,
1289 .help = "delay after deasserting trst in ms",
1290 .usage = "[milliseconds]",
1291 },
1292 {
1293 .name = "jtag_ntrst_assert_width",
1294 .handler = handle_jtag_ntrst_assert_width_command,
1295 .mode = COMMAND_ANY,
1296 .help = "delay after asserting trst in ms",
1297 .usage = "[milliseconds]",
1298 },
1299 {
1300 .name = "scan_chain",
1301 .handler = handle_scan_chain_command,
1302 .mode = COMMAND_ANY,
1303 .help = "print current scan chain configuration",
1304 .usage = ""
1305 },
1306 {
1307 .name = "jtag_reset",
1308 .handler = handle_jtag_reset_command,
1309 .mode = COMMAND_EXEC,
1310 .help = "Set reset line values. Value '1' is active, "
1311 "value '0' is inactive.",
1312 .usage = "trst_active srst_active",
1313 },
1314 {
1315 .name = "runtest",
1316 .handler = handle_runtest_command,
1317 .mode = COMMAND_EXEC,
1318 .help = "Move to Run-Test/Idle, and issue TCK for num_cycles.",
1319 .usage = "num_cycles"
1320 },
1321 {
1322 .name = "irscan",
1323 .handler = handle_irscan_command,
1324 .mode = COMMAND_EXEC,
1325 .help = "Execute Instruction Register (DR) scan. The "
1326 "specified opcodes are put into each TAP's IR, "
1327 "and other TAPs are put in BYPASS.",
1328 .usage = "[tap_name instruction]* ['-endstate' state_name]",
1329 },
1330 {
1331 .name = "verify_ircapture",
1332 .handler = handle_verify_ircapture_command,
1333 .mode = COMMAND_ANY,
1334 .help = "Display or assign flag controlling whether to "
1335 "verify values captured during Capture-IR.",
1336 .usage = "['enable'|'disable']",
1337 },
1338 {
1339 .name = "verify_jtag",
1340 .handler = handle_verify_jtag_command,
1341 .mode = COMMAND_ANY,
1342 .help = "Display or assign flag controlling whether to "
1343 "verify values captured during IR and DR scans.",
1344 .usage = "['enable'|'disable']",
1345 },
1346 {
1347 .name = "tms_sequence",
1348 .handler = handle_tms_sequence_command,
1349 .mode = COMMAND_ANY,
1350 .help = "Display or change what style TMS sequences to use "
1351 "for JTAG state transitions: short (default) or "
1352 "long. Only for working around JTAG bugs.",
1353 /* Specifically for working around DRIVER bugs... */
1354 .usage = "['short'|'long']",
1355 },
1356 {
1357 .name = "wait_srst_deassert",
1358 .handler = handle_wait_srst_deassert,
1359 .mode = COMMAND_ANY,
1360 .help = "Wait for an SRST deassert. "
1361 "Useful for cases where you need something to happen within ms "
1362 "of an srst deassert. Timeout in ms ",
1363 .usage = "ms",
1364 },
1365 {
1366 .name = "jtag",
1367 .mode = COMMAND_ANY,
1368 .help = "perform jtag tap actions",
1369 .usage = "",
1370
1371 .chain = jtag_subcommand_handlers,
1372 },
1373 {
1374 .chain = jtag_command_handlers_to_move,
1375 },
1376 COMMAND_REGISTRATION_DONE
1377 };
1378
1379 int jtag_register_commands(struct command_context *cmd_ctx)
1380 {
1381 return register_commands(cmd_ctx, NULL, jtag_command_handlers);
1382 }

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)