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

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)