Merge remote branch 'origin/master' into HEAD
[openocd.git] / src / target / arm946e.c
1 /***************************************************************************
2 * Copyright (C) 2005 by Dominic Rath *
3 * Dominic.Rath@gmx.de *
4 * *
5 * Copyright (C) 2008 by Spencer Oliver *
6 * spen@spen-soft.co.uk *
7 * *
8 * Copyright (C) 2010 by Drasko DRASKOVIC *
9 * drasko.draskovic@gmail.com *
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 * This program is distributed in the hope that it will be useful, *
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
19 * GNU General Public License for more details. *
20 * *
21 * You should have received a copy of the GNU General Public License *
22 * along with this program; if not, write to the *
23 * Free Software Foundation, Inc., *
24 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
25 ***************************************************************************/
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif
29
30 #include "arm946e.h"
31 #include "target_type.h"
32 #include "arm_opcodes.h"
33
34 #include "breakpoints.h"
35
36 #if 0
37 #define _DEBUG_INSTRUCTION_EXECUTION_
38 #endif
39
40 #define NB_CACHE_WAYS 4
41
42 static uint32_t dc = 0x0;
43 static uint32_t ic = 0x0;
44
45 /**
46 * flag to give info about cache manipulation during debug :
47 * "0" - cache lines are invalidated "on the fly", for affected addresses.
48 * This is prefered from performance point of view.
49 * "1" - cache is invalidated and switched off on debug_entry, and switched back on on restore.
50 * It is kept off during debugging.
51 */
52 static uint8_t arm946e_preserve_cache;
53
54 int arm946e_post_debug_entry(struct target *target);
55 void arm946e_pre_restore_context(struct target *target);
56 static int arm946e_read_cp15(struct target *target, int reg_addr, uint32_t *value);
57
58
59 int arm946e_init_arch_info(struct target *target, struct arm946e_common *arm946e, struct jtag_tap *tap)
60 {
61 struct arm7_9_common *arm7_9 = &arm946e->arm7_9_common;
62
63 /* initialize arm7/arm9 specific info (including armv4_5) */
64 arm9tdmi_init_arch_info(target, arm7_9, tap);
65
66 arm946e->common_magic = ARM946E_COMMON_MAGIC;
67
68 /**
69 * The ARM946E-S implements the ARMv5TE architecture which
70 * has the BKPT instruction, so we don't have to use a watchpoint comparator
71 */
72 arm7_9->arm_bkpt = ARMV5_BKPT(0x0);
73 arm7_9->thumb_bkpt = ARMV5_T_BKPT(0x0) & 0xffff;
74
75
76 arm7_9->post_debug_entry = arm946e_post_debug_entry;
77 arm7_9->pre_restore_context = arm946e_pre_restore_context;
78
79 /**
80 * disabling linefills leads to lockups, so keep them enabled for now
81 * this doesn't affect correctness, but might affect timing issues, if
82 * important data is evicted from the cache during the debug session
83 */
84 arm946e_preserve_cache = 0;
85
86 /* override hw single-step capability from ARM9TDMI */
87 //arm7_9->has_single_step = 1;
88
89 return ERROR_OK;
90 }
91
92 static int arm946e_target_create(struct target *target, Jim_Interp *interp)
93 {
94 struct arm946e_common *arm946e = calloc(1,sizeof(struct arm946e_common));
95
96 arm946e_init_arch_info(target, arm946e, target->tap);
97
98 return ERROR_OK;
99 }
100
101 static int arm946e_verify_pointer(struct command_context *cmd_ctx,
102 struct arm946e_common *arm946e)
103 {
104 if (arm946e->common_magic != ARM946E_COMMON_MAGIC) {
105 command_print(cmd_ctx, "target is not an ARM946");
106 return ERROR_TARGET_INVALID;
107 }
108 return ERROR_OK;
109 }
110
111 /*
112 * REVISIT: The "read_cp15" and "write_cp15" commands could hook up
113 * to eventual mrc() and mcr() routines ... the reg_addr values being
114 * constructed (for CP15 only) from Opcode_1, Opcode_2, and CRn values.
115 * See section 7.3 of the ARM946E-S TRM.
116 */
117 static int arm946e_read_cp15(struct target *target, int reg_addr, uint32_t *value)
118 {
119 int retval = ERROR_OK;
120 struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
121 struct arm_jtag *jtag_info = &arm7_9->jtag_info;
122 struct scan_field fields[3];
123 uint8_t reg_addr_buf = reg_addr & 0x3f;
124 uint8_t nr_w_buf = 0;
125
126 if ((retval = arm_jtag_scann(jtag_info, 0xf, TAP_IDLE)) != ERROR_OK)
127 {
128 return retval;
129 }
130 retval = arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL, TAP_IDLE);
131 if (retval != ERROR_OK)
132 return retval;
133
134 fields[0].num_bits = 32;
135 /* REVISIT: table 7-2 shows that bits 31-31 need to be
136 * specified for accessing BIST registers ...
137 */
138 fields[0].out_value = NULL;
139 fields[0].in_value = NULL;
140
141 fields[1].num_bits = 6;
142 fields[1].out_value = &reg_addr_buf;
143 fields[1].in_value = NULL;
144
145 fields[2].num_bits = 1;
146 fields[2].out_value = &nr_w_buf;
147 fields[2].in_value = NULL;
148
149 jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE);
150
151 fields[0].in_value = (uint8_t *)value;
152 jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE);
153
154 jtag_add_callback(arm_le_to_h_u32, (jtag_callback_data_t)value);
155
156 #ifdef _DEBUG_INSTRUCTION_EXECUTION_
157 LOG_DEBUG("addr: 0x%x value: %8.8x", reg_addr, *value);
158 #endif
159
160 if ((retval = jtag_execute_queue()) != ERROR_OK)
161 {
162 return retval;
163 }
164
165 return ERROR_OK;
166 }
167
168 int arm946e_write_cp15(struct target *target, int reg_addr, uint32_t value)
169 {
170 int retval = ERROR_OK;
171 struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
172 struct arm_jtag *jtag_info = &arm7_9->jtag_info;
173 struct scan_field fields[3];
174 uint8_t reg_addr_buf = reg_addr & 0x3f;
175 uint8_t nr_w_buf = 1;
176 uint8_t value_buf[4];
177
178 buf_set_u32(value_buf, 0, 32, value);
179
180 if ((retval = arm_jtag_scann(jtag_info, 0xf, TAP_IDLE)) != ERROR_OK)
181 {
182 return retval;
183 }
184 retval = arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL, TAP_IDLE);
185 if (retval != ERROR_OK)
186 return retval;
187
188 fields[0].num_bits = 32;
189 fields[0].out_value = value_buf;
190 fields[0].in_value = NULL;
191
192 fields[1].num_bits = 6;
193 fields[1].out_value = &reg_addr_buf;
194 fields[1].in_value = NULL;
195
196 fields[2].num_bits = 1;
197 fields[2].out_value = &nr_w_buf;
198 fields[2].in_value = NULL;
199
200 jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE);
201
202 #ifdef _DEBUG_INSTRUCTION_EXECUTION_
203 LOG_DEBUG("addr: 0x%x value: %8.8x", reg_addr, value);
204 #endif
205
206 if ((retval = jtag_execute_queue()) != ERROR_OK)
207 {
208 return retval;
209 }
210
211 return ERROR_OK;
212 }
213
214 uint32_t arm946e_invalidate_whole_dcache(struct target *target)
215 {
216
217 uint32_t csize = 0;
218 uint32_t shift = 0;
219 uint32_t cp15_idx, seg, dtag;
220 int nb_idx, idx = 0;
221 int retval;
222
223 /* Get cache type */
224 arm946e_read_cp15(target, 0x01, (uint32_t *) &csize);
225
226 csize = (csize >> 18) & 0x0F;
227
228 if (csize == 0)
229 shift = 0;
230 else
231 shift = csize - 0x3; /* Now 0 = 4KB, 1 = 8KB, ... */
232
233 /* Cache size, given in bytes */
234 csize = 1 << (12 + shift);
235 /* One line (index) is 32 bytes (8 words) long */
236 nb_idx = (csize / 32); /* gives nb of lines (indexes) in the cache */
237
238 /* Loop for all segmentde (i.e. ways) */
239 for( seg=0; seg < NB_CACHE_WAYS; seg++)
240 {
241 /* Loop for all indexes */
242 for(idx=0; idx < nb_idx; idx++)
243 {
244 /* Form and write cp15 index (segment + line idx) */
245 cp15_idx = seg << 30 | idx << 5;
246 retval = arm946e_write_cp15(target, 0x3a, cp15_idx);
247 if (retval != ERROR_OK)
248 {
249 LOG_DEBUG("ERROR writing index");
250 return retval;
251 }
252
253 /* Read dtag */
254 arm946e_read_cp15(target, 0x16, (uint32_t *) &dtag);
255
256 /* Check cache line VALID bit */
257 if ( !(dtag >> 4 & 0x1) )
258 continue;
259
260 /* Clean data cache line */
261 retval = arm946e_write_cp15(target, 0x35, 0x1);
262 if (retval != ERROR_OK)
263 {
264 LOG_DEBUG("ERROR cleaning cache line");
265 return retval;
266 }
267
268 /* Flush data cache line */
269 retval = arm946e_write_cp15(target, 0x1a, 0x1);
270 if (retval != ERROR_OK)
271 {
272 LOG_DEBUG("ERROR flushing cache line");
273 return retval;
274 }
275 }
276 }
277
278 return ERROR_OK;
279 }
280
281 uint32_t arm946e_invalidate_whole_icache(struct target *target)
282 {
283 int retval;
284
285 LOG_DEBUG("FLUSHING I$");
286
287 /**
288 * Invalidate (flush) I$
289 * mcr 15, 0, r0, cr7, cr5, {0}
290 */
291 retval = arm946e_write_cp15(target, 0x0f, 0x1);
292 if (retval != ERROR_OK)
293 {
294 LOG_DEBUG("ERROR flushing I$");
295 return retval;
296 }
297
298 return ERROR_OK;
299 }
300
301 int arm946e_post_debug_entry(struct target *target)
302 {
303 uint32_t ctr_reg = 0x0;
304 uint32_t retval = ERROR_OK;
305
306 /* See if CACHES are enabled, and save that info
307 * in the global vars, so that arm946e_pre_restore_context() can use them */
308 arm946e_read_cp15(target, 0x02, (uint32_t *) &ctr_reg);
309 dc = (ctr_reg >> 2) & 0x01;
310 ic = (ctr_reg >> 12) & 0x01;
311
312 if (arm946e_preserve_cache)
313 {
314 if (dc == 1)
315 {
316 /* Clean and flush D$ */
317 arm946e_invalidate_whole_dcache(target);
318
319 /* Disable D$ */
320 ctr_reg &= ~(1 << 2);
321 }
322
323 if (ic == 1)
324 {
325 /* Flush I$ */
326 arm946e_invalidate_whole_icache(target);
327
328 /* Disable I$ */
329 ctr_reg &= ~(1 << 12);
330 }
331
332 /* Write the new configuration */
333 retval = arm946e_write_cp15(target, 0x02, ctr_reg);
334 if (retval != ERROR_OK)
335 {
336 LOG_DEBUG("ERROR disabling cache");
337 return retval;
338 }
339 } /* if preserve_cache */
340
341 return ERROR_OK;
342 }
343
344 void arm946e_pre_restore_context(struct target *target)
345 {
346 uint32_t ctr_reg = 0x0;
347 uint32_t retval;
348
349 if (arm946e_preserve_cache)
350 {
351 /* Get the contents of the CTR reg */
352 arm946e_read_cp15(target, 0x02, (uint32_t *) &ctr_reg);
353
354 /**
355 * Read-modify-write CP15 test state register
356 * to reenable I/D-cache linefills
357 */
358 if (dc == 1)
359 {
360 /* Enable D$ */
361 ctr_reg |= 1 << 2;
362 }
363
364 if (ic == 1)
365 {
366 /* Enable I$ */
367 ctr_reg |= 1 << 12;
368 }
369
370 /* Write the new configuration */
371 retval = arm946e_write_cp15(target, 0x02, ctr_reg);
372 if (retval != ERROR_OK)
373 {
374 LOG_DEBUG("ERROR enabling cache");
375 }
376 } /* if preserve_cache */
377 }
378
379 uint32_t arm946e_invalidate_dcache(struct target *target, uint32_t address,
380 uint32_t size, uint32_t count)
381 {
382 uint32_t csize = 0x0;
383 uint32_t shift = 0;
384 uint32_t cur_addr = 0x0;
385 uint32_t cp15_idx, set, way, dtag;
386 int nb_idx;
387 uint32_t i = 0;
388 int retval;
389
390 for(i = 0; i < count*size; i++)
391 {
392 cur_addr = address + i;
393
394 /* Get cache type */
395 arm946e_read_cp15(target, 0x01, (uint32_t *) &csize);
396
397 /* Conclude cache size to find number of lines */
398 csize = (csize >> 18) & 0x0F;
399
400 if (csize == 0)
401 shift = 0;
402 else
403 shift = csize - 0x3; /* Now 0 = 4KB, 1 = 8KB, ... */
404
405 csize = 1 << (12 + shift);
406 nb_idx = (csize / 32);
407
408 set = (cur_addr >> 5) & 0xff; /* set field is 8 bits long */
409
410 for (way = 0; way < NB_CACHE_WAYS; way++)
411 {
412 /**
413 * Find if the affected address is kept in the cache.
414 * Because JTAG Scan Chain 15 offers limited approach,
415 * we have to loop through all cache ways (segments) and
416 * read cache tags, then compare them with with address.
417 */
418
419 /* Form and write cp15 index (segment + line idx) */
420 cp15_idx = way << 30 | set << 5;
421 retval = arm946e_write_cp15(target, 0x3a, cp15_idx);
422 if (retval != ERROR_OK)
423 {
424 LOG_DEBUG("ERROR writing index");
425 return retval;
426 }
427
428 /* Read dtag */
429 arm946e_read_cp15(target, 0x16, (uint32_t *) &dtag);
430
431 /* Check cache line VALID bit */
432 if ( !(dtag >> 4 & 0x1) )
433 continue;
434
435 /* If line is valid and corresponds to affected address - invalidate it */
436 if (dtag >> 5 == cur_addr >> 5)
437 {
438 /* Clean data cache line */
439 retval = arm946e_write_cp15(target, 0x35, 0x1);
440 if (retval != ERROR_OK)
441 {
442 LOG_DEBUG("ERROR cleaning cache line");
443 return retval;
444 }
445
446 /* Flush data cache line */
447 retval = arm946e_write_cp15(target, 0x1c, 0x1);
448 if (retval != ERROR_OK)
449 {
450 LOG_DEBUG("ERROR flushing cache line");
451 return retval;
452 }
453
454 break;
455 }
456 } /* loop through all 4 ways */
457 } /* loop through all addresses */
458
459 return ERROR_OK;
460 }
461
462 uint32_t arm946e_invalidate_icache(struct target *target, uint32_t address,
463 uint32_t size, uint32_t count)
464 {
465 uint32_t cur_addr = 0x0;
466 uint32_t cp15_idx, set, way, itag;
467 uint32_t i = 0;
468 int retval;
469
470 for(i = 0; i < count*size; i++)
471 {
472 cur_addr = address + i;
473
474 set = (cur_addr >> 5) & 0xff; /* set field is 8 bits long */
475
476 for (way = 0; way < NB_CACHE_WAYS; way++)
477 {
478 /* Form and write cp15 index (segment + line idx) */
479 cp15_idx = way << 30 | set << 5;
480 retval = arm946e_write_cp15(target, 0x3a, cp15_idx);
481 if (retval != ERROR_OK)
482 {
483 LOG_DEBUG("ERROR writing index");
484 return retval;
485 }
486
487 /* Read itag */
488 arm946e_read_cp15(target, 0x17, (uint32_t *) &itag);
489
490 /* Check cache line VALID bit */
491 if ( !(itag >> 4 & 0x1) )
492 continue;
493
494 /* If line is valid and corresponds to affected address - invalidate it */
495 if (itag >> 5 == cur_addr >> 5)
496 {
497 /* Flush I$ line */
498 retval = arm946e_write_cp15(target, 0x1d, 0x0);
499 if (retval != ERROR_OK)
500 {
501 LOG_DEBUG("ERROR flushing cache line");
502 return retval;
503 }
504
505 break;
506 }
507 } /* way loop */
508 } /* addr loop */
509
510 return ERROR_OK;
511 }
512
513 /** Writes a buffer, in the specified word size, with current MMU settings. */
514 int arm946e_write_memory(struct target *target, uint32_t address,
515 uint32_t size, uint32_t count, const uint8_t *buffer)
516 {
517 int retval;
518
519 LOG_DEBUG("-");
520
521 /* Invalidate D$ if it is ON */
522 if (!arm946e_preserve_cache && dc == 1)
523 {
524 arm946e_invalidate_dcache(target, address, size, count);
525 }
526
527 /**
528 * Write memory
529 */
530 if ( ( retval = arm7_9_write_memory(target, address,
531 size, count, buffer) ) != ERROR_OK )
532 {
533 return retval;
534 }
535
536 /* *
537 * Invalidate I$ if it is ON.
538 *
539 * D$ has been cleaned and flushed before mem write thus forcing it to behave like write-through,
540 * because arm7_9_write_memory() has seen non-valid bit in D$
541 * and wrote data into physical RAM (without touching or allocating the cache line).
542 * From ARM946ES Technical Reference Manual we can see that it uses "allocate on read-miss"
543 * policy for both I$ and D$ (Chapter 3.2 and 3.3)
544 *
545 * Explanation :
546 * "ARM system developer's guide: designing and optimizing system software" by
547 * Andrew N. Sloss, Dominic Symes and Chris Wright,
548 * Chapter 12.3.3 Allocating Policy on a Cache Miss :
549 * A read allocate on cache miss policy allocates a cache line only during a read from main memory.
550 * If the victim cache line contains valid data, then it is written to main memory before the cache line
551 * is filled with new data.
552 * Under this strategy, a write of new data to memory does not update the contents of the cache memory
553 * unless a cache line was allocated on a previous read from main memory.
554 * If the cache line contains valid data, then the write updates the cache and may update the main memory if
555 * the cache write policy is write-through.
556 * If the data is not in the cache, the controller writes to main memory only.
557 */
558 if (!arm946e_preserve_cache && ic == 1)
559 {
560 arm946e_invalidate_icache(target, address, size, count);
561 }
562
563 return ERROR_OK;
564
565 }
566
567 int arm946e_read_memory(struct target *target, uint32_t address,
568 uint32_t size, uint32_t count, uint8_t *buffer)
569 {
570 int retval;
571
572 LOG_DEBUG("-");
573
574 if ( ( retval = arm7_9_read_memory(target, address,
575 size, count, buffer) ) != ERROR_OK )
576 {
577 return retval;
578 }
579
580 return ERROR_OK;
581 }
582
583
584 COMMAND_HANDLER(arm946e_handle_cp15_command)
585 {
586 int retval;
587 struct target *target = get_current_target(CMD_CTX);
588 struct arm946e_common *arm946e = target_to_arm946(target);
589
590 retval = arm946e_verify_pointer(CMD_CTX, arm946e);
591 if (retval != ERROR_OK)
592 return retval;
593
594 if (target->state != TARGET_HALTED)
595 {
596 command_print(CMD_CTX, "target must be stopped for \"%s\" command", CMD_NAME);
597 return ERROR_OK;
598 }
599
600 /* one or more argument, access a single register (write if second argument is given */
601 if (CMD_ARGC >= 1)
602 {
603 uint32_t address;
604 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address);
605
606 if (CMD_ARGC == 1)
607 {
608 uint32_t value;
609 if ((retval = arm946e_read_cp15(target, address, &value)) != ERROR_OK)
610 {
611 command_print(CMD_CTX,
612 "couldn't access reg %" PRIi32,
613 address);
614 return ERROR_OK;
615 }
616 if ((retval = jtag_execute_queue()) != ERROR_OK)
617 {
618 return retval;
619 }
620
621 command_print(CMD_CTX, "%" PRIi32 ": %8.8" PRIx32,
622 address, value);
623 }
624 else if (CMD_ARGC == 2)
625 {
626 uint32_t value;
627 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value);
628 if ((retval = arm946e_write_cp15(target, address, value)) != ERROR_OK)
629 {
630 command_print(CMD_CTX,
631 "couldn't access reg %" PRIi32,
632 address);
633 return ERROR_OK;
634 }
635 command_print(CMD_CTX, "%" PRIi32 ": %8.8" PRIx32,
636 address, value);
637 }
638 }
639
640 return ERROR_OK;
641 }
642
643 static const struct command_registration arm946e_exec_command_handlers[] = {
644 {
645 .name = "cp15",
646 .handler = arm946e_handle_cp15_command,
647 .mode = COMMAND_EXEC,
648 .usage = "regnum [value]",
649 .help = "display/modify cp15 register",
650 },
651 COMMAND_REGISTRATION_DONE
652 };
653
654 const struct command_registration arm946e_command_handlers[] = {
655 {
656 .chain = arm9tdmi_command_handlers,
657 },
658 {
659 .name = "arm946e",
660 .mode = COMMAND_ANY,
661 .help = "arm946e command group",
662 .chain = arm946e_exec_command_handlers,
663 },
664 COMMAND_REGISTRATION_DONE
665 };
666
667 /** Holds methods for ARM946 targets. */
668 struct target_type arm946e_target =
669 {
670 .name = "arm946e",
671
672 .poll = arm7_9_poll,
673 .arch_state = arm_arch_state,
674
675 .target_request_data = arm7_9_target_request_data,
676
677 .halt = arm7_9_halt,
678 .resume = arm7_9_resume,
679 .step = arm7_9_step,
680
681 .assert_reset = arm7_9_assert_reset,
682 .deassert_reset = arm7_9_deassert_reset,
683 .soft_reset_halt = arm7_9_soft_reset_halt,
684
685 .get_gdb_reg_list = arm_get_gdb_reg_list,
686
687 //.read_memory = arm7_9_read_memory,
688 //.write_memory = arm7_9_write_memory,
689 .read_memory = arm946e_read_memory,
690 .write_memory = arm946e_write_memory,
691
692 .bulk_write_memory = arm7_9_bulk_write_memory,
693
694 .checksum_memory = arm_checksum_memory,
695 .blank_check_memory = arm_blank_check_memory,
696
697 .run_algorithm = armv4_5_run_algorithm,
698
699 .add_breakpoint = arm7_9_add_breakpoint,
700 .remove_breakpoint = arm7_9_remove_breakpoint,
701 //.add_breakpoint = arm946e_add_breakpoint,
702 //.remove_breakpoint = arm946e_remove_breakpoint,
703
704 .add_watchpoint = arm7_9_add_watchpoint,
705 .remove_watchpoint = arm7_9_remove_watchpoint,
706
707 .commands = arm946e_command_handlers,
708 .target_create = arm946e_target_create,
709 .init_target = arm9tdmi_init_target,
710 .examine = arm7_9_examine,
711 .check_reset = arm7_9_check_reset,
712 };

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)