cmd: add missing usage vars
[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 uint32_t i = 0;
387 int retval;
388
389 for(i = 0; i < count*size; i++)
390 {
391 cur_addr = address + i;
392
393 /* Get cache type */
394 arm946e_read_cp15(target, 0x01, (uint32_t *) &csize);
395
396 /* Conclude cache size to find number of lines */
397 csize = (csize >> 18) & 0x0F;
398
399 if (csize == 0)
400 shift = 0;
401 else
402 shift = csize - 0x3; /* Now 0 = 4KB, 1 = 8KB, ... */
403
404 csize = 1 << (12 + shift);
405
406 set = (cur_addr >> 5) & 0xff; /* set field is 8 bits long */
407
408 for (way = 0; way < NB_CACHE_WAYS; way++)
409 {
410 /**
411 * Find if the affected address is kept in the cache.
412 * Because JTAG Scan Chain 15 offers limited approach,
413 * we have to loop through all cache ways (segments) and
414 * read cache tags, then compare them with with address.
415 */
416
417 /* Form and write cp15 index (segment + line idx) */
418 cp15_idx = way << 30 | set << 5;
419 retval = arm946e_write_cp15(target, 0x3a, cp15_idx);
420 if (retval != ERROR_OK)
421 {
422 LOG_DEBUG("ERROR writing index");
423 return retval;
424 }
425
426 /* Read dtag */
427 arm946e_read_cp15(target, 0x16, (uint32_t *) &dtag);
428
429 /* Check cache line VALID bit */
430 if ( !(dtag >> 4 & 0x1) )
431 continue;
432
433 /* If line is valid and corresponds to affected address - invalidate it */
434 if (dtag >> 5 == cur_addr >> 5)
435 {
436 /* Clean data cache line */
437 retval = arm946e_write_cp15(target, 0x35, 0x1);
438 if (retval != ERROR_OK)
439 {
440 LOG_DEBUG("ERROR cleaning cache line");
441 return retval;
442 }
443
444 /* Flush data cache line */
445 retval = arm946e_write_cp15(target, 0x1c, 0x1);
446 if (retval != ERROR_OK)
447 {
448 LOG_DEBUG("ERROR flushing cache line");
449 return retval;
450 }
451
452 break;
453 }
454 } /* loop through all 4 ways */
455 } /* loop through all addresses */
456
457 return ERROR_OK;
458 }
459
460 uint32_t arm946e_invalidate_icache(struct target *target, uint32_t address,
461 uint32_t size, uint32_t count)
462 {
463 uint32_t cur_addr = 0x0;
464 uint32_t cp15_idx, set, way, itag;
465 uint32_t i = 0;
466 int retval;
467
468 for(i = 0; i < count*size; i++)
469 {
470 cur_addr = address + i;
471
472 set = (cur_addr >> 5) & 0xff; /* set field is 8 bits long */
473
474 for (way = 0; way < NB_CACHE_WAYS; way++)
475 {
476 /* Form and write cp15 index (segment + line idx) */
477 cp15_idx = way << 30 | set << 5;
478 retval = arm946e_write_cp15(target, 0x3a, cp15_idx);
479 if (retval != ERROR_OK)
480 {
481 LOG_DEBUG("ERROR writing index");
482 return retval;
483 }
484
485 /* Read itag */
486 arm946e_read_cp15(target, 0x17, (uint32_t *) &itag);
487
488 /* Check cache line VALID bit */
489 if ( !(itag >> 4 & 0x1) )
490 continue;
491
492 /* If line is valid and corresponds to affected address - invalidate it */
493 if (itag >> 5 == cur_addr >> 5)
494 {
495 /* Flush I$ line */
496 retval = arm946e_write_cp15(target, 0x1d, 0x0);
497 if (retval != ERROR_OK)
498 {
499 LOG_DEBUG("ERROR flushing cache line");
500 return retval;
501 }
502
503 break;
504 }
505 } /* way loop */
506 } /* addr loop */
507
508 return ERROR_OK;
509 }
510
511 /** Writes a buffer, in the specified word size, with current MMU settings. */
512 int arm946e_write_memory(struct target *target, uint32_t address,
513 uint32_t size, uint32_t count, const uint8_t *buffer)
514 {
515 int retval;
516
517 LOG_DEBUG("-");
518
519 /* Invalidate D$ if it is ON */
520 if (!arm946e_preserve_cache && dc == 1)
521 {
522 arm946e_invalidate_dcache(target, address, size, count);
523 }
524
525 /**
526 * Write memory
527 */
528 if ( ( retval = arm7_9_write_memory(target, address,
529 size, count, buffer) ) != ERROR_OK )
530 {
531 return retval;
532 }
533
534 /* *
535 * Invalidate I$ if it is ON.
536 *
537 * D$ has been cleaned and flushed before mem write thus forcing it to behave like write-through,
538 * because arm7_9_write_memory() has seen non-valid bit in D$
539 * and wrote data into physical RAM (without touching or allocating the cache line).
540 * From ARM946ES Technical Reference Manual we can see that it uses "allocate on read-miss"
541 * policy for both I$ and D$ (Chapter 3.2 and 3.3)
542 *
543 * Explanation :
544 * "ARM system developer's guide: designing and optimizing system software" by
545 * Andrew N. Sloss, Dominic Symes and Chris Wright,
546 * Chapter 12.3.3 Allocating Policy on a Cache Miss :
547 * A read allocate on cache miss policy allocates a cache line only during a read from main memory.
548 * If the victim cache line contains valid data, then it is written to main memory before the cache line
549 * is filled with new data.
550 * Under this strategy, a write of new data to memory does not update the contents of the cache memory
551 * unless a cache line was allocated on a previous read from main memory.
552 * If the cache line contains valid data, then the write updates the cache and may update the main memory if
553 * the cache write policy is write-through.
554 * If the data is not in the cache, the controller writes to main memory only.
555 */
556 if (!arm946e_preserve_cache && ic == 1)
557 {
558 arm946e_invalidate_icache(target, address, size, count);
559 }
560
561 return ERROR_OK;
562
563 }
564
565 int arm946e_read_memory(struct target *target, uint32_t address,
566 uint32_t size, uint32_t count, uint8_t *buffer)
567 {
568 int retval;
569
570 LOG_DEBUG("-");
571
572 if ( ( retval = arm7_9_read_memory(target, address,
573 size, count, buffer) ) != ERROR_OK )
574 {
575 return retval;
576 }
577
578 return ERROR_OK;
579 }
580
581
582 COMMAND_HANDLER(arm946e_handle_cp15_command)
583 {
584 int retval;
585 struct target *target = get_current_target(CMD_CTX);
586 struct arm946e_common *arm946e = target_to_arm946(target);
587
588 retval = arm946e_verify_pointer(CMD_CTX, arm946e);
589 if (retval != ERROR_OK)
590 return retval;
591
592 if (target->state != TARGET_HALTED)
593 {
594 command_print(CMD_CTX, "target must be stopped for \"%s\" command", CMD_NAME);
595 return ERROR_OK;
596 }
597
598 /* one or more argument, access a single register (write if second argument is given */
599 if (CMD_ARGC >= 1)
600 {
601 uint32_t address;
602 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address);
603
604 if (CMD_ARGC == 1)
605 {
606 uint32_t value;
607 if ((retval = arm946e_read_cp15(target, address, &value)) != ERROR_OK)
608 {
609 command_print(CMD_CTX,
610 "couldn't access reg %" PRIi32,
611 address);
612 return ERROR_OK;
613 }
614 if ((retval = jtag_execute_queue()) != ERROR_OK)
615 {
616 return retval;
617 }
618
619 command_print(CMD_CTX, "%" PRIi32 ": %8.8" PRIx32,
620 address, value);
621 }
622 else if (CMD_ARGC == 2)
623 {
624 uint32_t value;
625 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value);
626 if ((retval = arm946e_write_cp15(target, address, value)) != ERROR_OK)
627 {
628 command_print(CMD_CTX,
629 "couldn't access reg %" PRIi32,
630 address);
631 return ERROR_OK;
632 }
633 command_print(CMD_CTX, "%" PRIi32 ": %8.8" PRIx32,
634 address, value);
635 }
636 }
637
638 return ERROR_OK;
639 }
640
641 static const struct command_registration arm946e_exec_command_handlers[] = {
642 {
643 .name = "cp15",
644 .handler = arm946e_handle_cp15_command,
645 .mode = COMMAND_EXEC,
646 .usage = "regnum [value]",
647 .help = "display/modify cp15 register",
648 },
649 COMMAND_REGISTRATION_DONE
650 };
651
652 const struct command_registration arm946e_command_handlers[] = {
653 {
654 .chain = arm9tdmi_command_handlers,
655 },
656 {
657 .name = "arm946e",
658 .mode = COMMAND_ANY,
659 .help = "arm946e command group",
660 .usage = "",
661 .chain = arm946e_exec_command_handlers,
662 },
663 COMMAND_REGISTRATION_DONE
664 };
665
666 /** Holds methods for ARM946 targets. */
667 struct target_type arm946e_target =
668 {
669 .name = "arm946e",
670
671 .poll = arm7_9_poll,
672 .arch_state = arm_arch_state,
673
674 .target_request_data = arm7_9_target_request_data,
675
676 .halt = arm7_9_halt,
677 .resume = arm7_9_resume,
678 .step = arm7_9_step,
679
680 .assert_reset = arm7_9_assert_reset,
681 .deassert_reset = arm7_9_deassert_reset,
682 .soft_reset_halt = arm7_9_soft_reset_halt,
683
684 .get_gdb_reg_list = arm_get_gdb_reg_list,
685
686 //.read_memory = arm7_9_read_memory,
687 //.write_memory = arm7_9_write_memory,
688 .read_memory = arm946e_read_memory,
689 .write_memory = arm946e_write_memory,
690
691 .bulk_write_memory = arm7_9_bulk_write_memory,
692
693 .checksum_memory = arm_checksum_memory,
694 .blank_check_memory = arm_blank_check_memory,
695
696 .run_algorithm = armv4_5_run_algorithm,
697
698 .add_breakpoint = arm7_9_add_breakpoint,
699 .remove_breakpoint = arm7_9_remove_breakpoint,
700 //.add_breakpoint = arm946e_add_breakpoint,
701 //.remove_breakpoint = arm946e_remove_breakpoint,
702
703 .add_watchpoint = arm7_9_add_watchpoint,
704 .remove_watchpoint = arm7_9_remove_watchpoint,
705
706 .commands = arm946e_command_handlers,
707 .target_create = arm946e_target_create,
708 .init_target = arm9tdmi_init_target,
709 .examine = arm7_9_examine,
710 .check_reset = arm7_9_check_reset,
711 };

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)