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

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)