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

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)