cortex_m3: use armv7m's async algorithm implementation
[openocd.git] / src / target / avr32_ap7k.c
1 /***************************************************************************
2 * Copyright (C) 2010 by Oleksandr Tymoshenko <gonzo@bluezbox.com> *
3 * Based on mips_m4k code: *
4 * Copyright (C) 2008 by Spencer Oliver <spen@spen-soft.co.uk> *
5 * Copyright (C) 2008 by David T.L. Wong *
6 * *
7 * This program is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation; either version 2 of the License, or *
10 * (at your option) any later version. *
11 * *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program; if not, write to the *
19 * Free Software Foundation, Inc., *
20 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
21 ***************************************************************************/
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include "jtag/jtag.h"
27 #include "register.h"
28 #include "algorithm.h"
29 #include "target.h"
30 #include "breakpoints.h"
31 #include "target_type.h"
32 #include "avr32_jtag.h"
33 #include "avr32_mem.h"
34 #include "avr32_regs.h"
35 #include "avr32_ap7k.h"
36
37 static char* avr32_core_reg_list[] =
38 {
39 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8",
40 "r9", "r10", "r11", "r12", "sp", "lr", "pc", "sr"
41 };
42
43 static struct avr32_core_reg
44 avr32_core_reg_list_arch_info[AVR32NUMCOREREGS] =
45 {
46 {0, NULL, NULL},
47 {1, NULL, NULL},
48 {2, NULL, NULL},
49 {3, NULL, NULL},
50 {4, NULL, NULL},
51 {5, NULL, NULL},
52 {6, NULL, NULL},
53 {7, NULL, NULL},
54 {8, NULL, NULL},
55 {9, NULL, NULL},
56 {10, NULL, NULL},
57 {11, NULL, NULL},
58 {12, NULL, NULL},
59 {13, NULL, NULL},
60 {14, NULL, NULL},
61 {15, NULL, NULL},
62 {16, NULL, NULL},
63 };
64
65
66 static int avr32_read_core_reg(struct target *target, int num);
67 static int avr32_write_core_reg(struct target *target, int num);
68
69 int avr32_ap7k_save_context(struct target *target)
70 {
71 int retval, i;
72 struct avr32_ap7k_common *ap7k = target_to_ap7k(target);
73
74 retval = avr32_jtag_read_regs(&ap7k->jtag, ap7k->core_regs);
75 if (retval != ERROR_OK)
76 return retval;
77
78 for (i = 0; i < AVR32NUMCOREREGS; i++)
79 {
80 if (!ap7k->core_cache->reg_list[i].valid)
81 {
82 avr32_read_core_reg(target, i);
83 }
84 }
85
86 return ERROR_OK;
87 }
88
89 int avr32_ap7k_restore_context(struct target *target)
90 {
91 int i;
92
93 /* get pointers to arch-specific information */
94 struct avr32_ap7k_common *ap7k = target_to_ap7k(target);
95
96 for (i = 0; i < AVR32NUMCOREREGS; i++)
97 {
98 if (ap7k->core_cache->reg_list[i].dirty)
99 {
100 avr32_write_core_reg(target, i);
101 }
102 }
103
104 /* write core regs */
105 avr32_jtag_write_regs(&ap7k->jtag, ap7k->core_regs);
106
107 return ERROR_OK;
108 }
109
110 static int avr32_read_core_reg(struct target *target, int num)
111 {
112 uint32_t reg_value;
113
114 /* get pointers to arch-specific information */
115 struct avr32_ap7k_common *ap7k = target_to_ap7k(target);
116
117 if ((num < 0) || (num >= AVR32NUMCOREREGS))
118 return ERROR_INVALID_ARGUMENTS;
119
120 reg_value = ap7k->core_regs[num];
121 buf_set_u32(ap7k->core_cache->reg_list[num].value, 0, 32, reg_value);
122 ap7k->core_cache->reg_list[num].valid = 1;
123 ap7k->core_cache->reg_list[num].dirty = 0;
124
125 return ERROR_OK;
126 }
127
128 static int avr32_write_core_reg(struct target *target, int num)
129 {
130 uint32_t reg_value;
131
132 /* get pointers to arch-specific information */
133 struct avr32_ap7k_common *ap7k = target_to_ap7k(target);
134
135 if ((num < 0) || (num >= AVR32NUMCOREREGS))
136 return ERROR_INVALID_ARGUMENTS;
137
138 reg_value = buf_get_u32(ap7k->core_cache->reg_list[num].value, 0, 32);
139 ap7k->core_regs[num] = reg_value;
140 LOG_DEBUG("write core reg %i value 0x%" PRIx32 "", num , reg_value);
141 ap7k->core_cache->reg_list[num].valid = 1;
142 ap7k->core_cache->reg_list[num].dirty = 0;
143
144 return ERROR_OK;
145 }
146
147 static int avr32_get_core_reg(struct reg *reg)
148 {
149 int retval;
150 struct avr32_core_reg *avr32_reg = reg->arch_info;
151 struct target *target = avr32_reg->target;
152
153 if (target->state != TARGET_HALTED)
154 {
155 return ERROR_TARGET_NOT_HALTED;
156 }
157
158 retval = avr32_read_core_reg(target, avr32_reg->num);
159
160 return retval;
161 }
162
163 static int avr32_set_core_reg(struct reg *reg, uint8_t *buf)
164 {
165 struct avr32_core_reg *avr32_reg = reg->arch_info;
166 struct target *target = avr32_reg->target;
167 uint32_t value = buf_get_u32(buf, 0, 32);
168
169 if (target->state != TARGET_HALTED)
170 {
171 return ERROR_TARGET_NOT_HALTED;
172 }
173
174 buf_set_u32(reg->value, 0, 32, value);
175 reg->dirty = 1;
176 reg->valid = 1;
177
178 return ERROR_OK;
179 }
180
181 static const struct reg_arch_type avr32_reg_type = {
182 .get = avr32_get_core_reg,
183 .set = avr32_set_core_reg,
184 };
185
186 static struct reg_cache *avr32_build_reg_cache(struct target *target)
187 {
188 int num_regs = AVR32NUMCOREREGS;
189 struct avr32_ap7k_common *ap7k = target_to_ap7k(target);
190 struct reg_cache **cache_p = register_get_last_cache_p(&target->reg_cache);
191 struct reg_cache *cache = malloc(sizeof(struct reg_cache));
192 struct reg *reg_list = malloc(sizeof(struct reg) * num_regs);
193 struct avr32_core_reg *arch_info =
194 malloc(sizeof(struct avr32_core_reg) * num_regs);
195 int i;
196
197 /* Build the process context cache */
198 cache->name = "avr32 registers";
199 cache->next = NULL;
200 cache->reg_list = reg_list;
201 cache->num_regs = num_regs;
202 (*cache_p) = cache;
203 ap7k->core_cache = cache;
204
205 for (i = 0; i < num_regs; i++)
206 {
207 arch_info[i] = avr32_core_reg_list_arch_info[i];
208 arch_info[i].target = target;
209 arch_info[i].avr32_common = ap7k;
210 reg_list[i].name = avr32_core_reg_list[i];
211 reg_list[i].size = 32;
212 reg_list[i].value = calloc(1, 4);
213 reg_list[i].dirty = 0;
214 reg_list[i].valid = 0;
215 reg_list[i].type = &avr32_reg_type;
216 reg_list[i].arch_info = &arch_info[i];
217 }
218
219 return cache;
220 }
221
222 static int avr32_ap7k_debug_entry(struct target *target)
223 {
224
225 uint32_t dpc, dinst;
226 int retval;
227 struct avr32_ap7k_common *ap7k = target_to_ap7k(target);
228
229 retval = avr32_jtag_nexus_read(&ap7k->jtag, AVR32_OCDREG_DPC, &dpc);
230 if (retval != ERROR_OK)
231 return retval;
232
233 retval = avr32_jtag_nexus_read(&ap7k->jtag, AVR32_OCDREG_DINST, &dinst);
234 if (retval != ERROR_OK)
235 return retval;
236
237 ap7k->jtag.dpc = dpc;
238
239 avr32_ap7k_save_context(target);
240
241 return ERROR_OK;
242 }
243
244
245 static int avr32_ap7k_poll(struct target *target)
246 {
247 uint32_t ds;
248 int retval;
249 struct avr32_ap7k_common *ap7k = target_to_ap7k(target);
250
251 retval = avr32_jtag_nexus_read(&ap7k->jtag, AVR32_OCDREG_DS, &ds);
252 if (retval != ERROR_OK)
253 return retval;
254
255 /* check for processor halted */
256 if (ds & OCDREG_DS_DBA)
257 {
258 if ((target->state == TARGET_RUNNING) || (target->state == TARGET_RESET))
259 {
260 target->state = TARGET_HALTED;
261
262 if ((retval = avr32_ap7k_debug_entry(target)) != ERROR_OK)
263 return retval;
264
265 target_call_event_callbacks(target, TARGET_EVENT_HALTED);
266 }
267 else if (target->state == TARGET_DEBUG_RUNNING)
268 {
269 target->state = TARGET_HALTED;
270
271 if ((retval = avr32_ap7k_debug_entry(target)) != ERROR_OK)
272 return retval;
273
274 target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED);
275 }
276 }
277 else
278 {
279 target->state = TARGET_RUNNING;
280 }
281
282
283 return ERROR_OK;
284 }
285
286 static int avr32_ap7k_halt(struct target *target)
287 {
288 struct avr32_ap7k_common *ap7k = target_to_ap7k(target);
289
290 LOG_DEBUG("target->state: %s",
291 target_state_name(target));
292
293 if (target->state == TARGET_HALTED)
294 {
295 LOG_DEBUG("target was already halted");
296 return ERROR_OK;
297 }
298
299 if (target->state == TARGET_UNKNOWN)
300 {
301 LOG_WARNING("target was in unknown state when halt was requested");
302 }
303
304 if (target->state == TARGET_RESET)
305 {
306 if ((jtag_get_reset_config() & RESET_SRST_PULLS_TRST) && jtag_get_srst())
307 {
308 LOG_ERROR("can't request a halt while in reset if nSRST pulls nTRST");
309 return ERROR_TARGET_FAILURE;
310 }
311 else
312 {
313 target->debug_reason = DBG_REASON_DBGRQ;
314
315 return ERROR_OK;
316 }
317 }
318
319
320 avr32_ocd_setbits(&ap7k->jtag, AVR32_OCDREG_DC, OCDREG_DC_DBR);
321 target->debug_reason = DBG_REASON_DBGRQ;
322
323 return ERROR_OK;
324 }
325
326 static int avr32_ap7k_assert_reset(struct target *target)
327 {
328 LOG_ERROR("%s: implement me", __func__);
329
330 return ERROR_OK;
331 }
332
333 static int avr32_ap7k_deassert_reset(struct target *target)
334 {
335 LOG_ERROR("%s: implement me", __func__);
336
337 return ERROR_OK;
338 }
339
340 static int avr32_ap7k_soft_reset_halt(struct target *target)
341 {
342 LOG_ERROR("%s: implement me", __func__);
343
344 return ERROR_OK;
345 }
346
347 static int avr32_ap7k_resume(struct target *target, int current,
348 uint32_t address, int handle_breakpoints, int debug_execution)
349 {
350 struct avr32_ap7k_common *ap7k = target_to_ap7k(target);
351 struct breakpoint *breakpoint = NULL;
352 uint32_t resume_pc;
353 int retval;
354
355 if (target->state != TARGET_HALTED)
356 {
357 LOG_WARNING("target not halted");
358 return ERROR_TARGET_NOT_HALTED;
359 }
360
361 if (!debug_execution)
362 {
363 target_free_all_working_areas(target);
364 /*
365 avr32_ap7k_enable_breakpoints(target);
366 avr32_ap7k_enable_watchpoints(target);
367 */
368 }
369
370 /* current = 1: continue on current pc, otherwise continue at <address> */
371 if (!current)
372 {
373 #if 0
374 if (retval != ERROR_OK)
375 return retval;
376 #endif
377 }
378
379 resume_pc =
380 buf_get_u32(ap7k->core_cache->reg_list[AVR32_REG_PC].value, 0, 32);
381 avr32_ap7k_restore_context(target);
382
383 /* the front-end may request us not to handle breakpoints */
384 if (handle_breakpoints)
385 {
386 /* Single step past breakpoint at current address */
387 if ((breakpoint = breakpoint_find(target, resume_pc)))
388 {
389 LOG_DEBUG("unset breakpoint at 0x%8.8" PRIx32 "", breakpoint->address);
390 #if 0
391 avr32_ap7k_unset_breakpoint(target, breakpoint);
392 avr32_ap7k_single_step_core(target);
393 avr32_ap7k_set_breakpoint(target, breakpoint);
394 #endif
395 }
396 }
397
398 #if 0
399 /* enable interrupts if we are running */
400 avr32_ap7k_enable_interrupts(target, !debug_execution);
401
402 /* exit debug mode */
403 mips_ejtag_exit_debug(ejtag_info);
404 #endif
405
406
407 retval = avr32_ocd_clearbits(&ap7k->jtag, AVR32_OCDREG_DC,
408 OCDREG_DC_DBR);
409 if (retval != ERROR_OK)
410 return retval;
411
412 retval = avr32_jtag_exec(&ap7k->jtag, RETD);
413 if (retval != ERROR_OK)
414 return retval;
415
416 target->debug_reason = DBG_REASON_NOTHALTED;
417
418 /* registers are now invalid */
419 register_cache_invalidate(ap7k->core_cache);
420
421 if (!debug_execution)
422 {
423 target->state = TARGET_RUNNING;
424 target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
425 LOG_DEBUG("target resumed at 0x%" PRIx32 "", resume_pc);
426 }
427 else
428 {
429 target->state = TARGET_DEBUG_RUNNING;
430 target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED);
431 LOG_DEBUG("target debug resumed at 0x%" PRIx32 "", resume_pc);
432 }
433
434 return ERROR_OK;
435 }
436
437 static int avr32_ap7k_step(struct target *target, int current,
438 uint32_t address, int handle_breakpoints)
439 {
440 LOG_ERROR("%s: implement me", __func__);
441
442 return ERROR_OK;
443 }
444
445 static int avr32_ap7k_add_breakpoint(struct target *target, struct breakpoint *breakpoint)
446 {
447 LOG_ERROR("%s: implement me", __func__);
448
449 return ERROR_OK;
450 }
451
452 static int avr32_ap7k_remove_breakpoint(struct target *target,
453 struct breakpoint *breakpoint)
454 {
455 LOG_ERROR("%s: implement me", __func__);
456
457 return ERROR_OK;
458 }
459
460 static int avr32_ap7k_add_watchpoint(struct target *target, struct watchpoint *watchpoint)
461 {
462 LOG_ERROR("%s: implement me", __func__);
463
464 return ERROR_OK;
465 }
466
467 static int avr32_ap7k_remove_watchpoint(struct target *target,
468 struct watchpoint *watchpoint)
469 {
470 LOG_ERROR("%s: implement me", __func__);
471
472 return ERROR_OK;
473 }
474
475 static int avr32_ap7k_read_memory(struct target *target, uint32_t address,
476 uint32_t size, uint32_t count, uint8_t *buffer)
477 {
478 struct avr32_ap7k_common *ap7k = target_to_ap7k(target);
479
480 LOG_DEBUG("address: 0x%8.8" PRIx32 ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32 "", address, size, count);
481
482 if (target->state != TARGET_HALTED)
483 {
484 LOG_WARNING("target not halted");
485 return ERROR_TARGET_NOT_HALTED;
486 }
487
488 /* sanitize arguments */
489 if (((size != 4) && (size != 2) && (size != 1)) || (count == 0) || !(buffer))
490 return ERROR_INVALID_ARGUMENTS;
491
492 if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u)))
493 return ERROR_TARGET_UNALIGNED_ACCESS;
494
495 switch (size)
496 {
497 case 4:
498 return avr32_jtag_read_memory32(&ap7k->jtag, address, count, (uint32_t*)(void *)buffer);
499 break;
500 case 2:
501 return avr32_jtag_read_memory16(&ap7k->jtag, address, count, (uint16_t*)(void *)buffer);
502 break;
503 case 1:
504 return avr32_jtag_read_memory8(&ap7k->jtag, address, count, buffer);
505 break;
506 default:
507 break;
508 }
509
510 return ERROR_OK;
511 }
512
513 static int avr32_ap7k_write_memory(struct target *target, uint32_t address,
514 uint32_t size, uint32_t count, const uint8_t *buffer)
515 {
516 struct avr32_ap7k_common *ap7k = target_to_ap7k(target);
517
518 LOG_DEBUG("address: 0x%8.8" PRIx32 ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32 "", address, size, count);
519
520 if (target->state != TARGET_HALTED)
521 {
522 LOG_WARNING("target not halted");
523 return ERROR_TARGET_NOT_HALTED;
524 }
525
526 /* sanitize arguments */
527 if (((size != 4) && (size != 2) && (size != 1)) || (count == 0) || !(buffer))
528 return ERROR_INVALID_ARGUMENTS;
529
530 if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u)))
531 return ERROR_TARGET_UNALIGNED_ACCESS;
532
533 switch (size)
534 {
535 case 4:
536 return avr32_jtag_write_memory32(&ap7k->jtag, address, count, (uint32_t*)(void *)buffer);
537 break;
538 case 2:
539 return avr32_jtag_write_memory16(&ap7k->jtag, address, count, (uint16_t*)(void *)buffer);
540 break;
541 case 1:
542 return avr32_jtag_write_memory8(&ap7k->jtag, address, count, buffer);
543 break;
544 default:
545 break;
546 }
547
548 return ERROR_OK;
549 }
550
551 static int avr32_ap7k_init_target(struct command_context *cmd_ctx,
552 struct target *target)
553 {
554 struct avr32_ap7k_common *ap7k = target_to_ap7k(target);
555
556 ap7k->jtag.tap = target->tap;
557 avr32_build_reg_cache(target);
558 return ERROR_OK;
559 }
560
561 static int avr32_ap7k_target_create(struct target *target, Jim_Interp *interp)
562 {
563 struct avr32_ap7k_common *ap7k = calloc(1, sizeof(struct
564 avr32_ap7k_common));
565
566 ap7k->common_magic = AP7k_COMMON_MAGIC;
567 target->arch_info = ap7k;
568
569 return ERROR_OK;
570 }
571
572 static int avr32_ap7k_examine(struct target *target)
573 {
574 uint32_t devid, ds;
575 struct avr32_ap7k_common *ap7k = target_to_ap7k(target);
576
577 if (!target_was_examined(target))
578 {
579 target_set_examined(target);
580 avr32_jtag_nexus_read(&ap7k->jtag, AVR32_OCDREG_DID, &devid);
581 LOG_INFO("device id: %08x", devid);
582 avr32_ocd_setbits(&ap7k->jtag, AVR32_OCDREG_DC,OCDREG_DC_DBE);
583 avr32_jtag_nexus_read(&ap7k->jtag, AVR32_OCDREG_DS, &ds);
584
585 /* check for processor halted */
586 if (ds & OCDREG_DS_DBA)
587 {
588 LOG_INFO("target is halted");
589 target->state = TARGET_HALTED;
590 }
591 else
592 target->state = TARGET_RUNNING;
593 }
594
595 return ERROR_OK;
596 }
597
598 static int avr32_ap7k_bulk_write_memory(struct target *target, uint32_t address,
599 uint32_t count, const uint8_t *buffer)
600 {
601 LOG_ERROR("%s: implement me", __func__);
602
603 return ERROR_OK;
604 }
605
606
607 int avr32_ap7k_arch_state(struct target *target)
608 {
609 struct avr32_ap7k_common *ap7k = target_to_ap7k(target);
610
611 LOG_USER("target halted due to %s, pc: 0x%8.8" PRIx32 "",
612 debug_reason_name(target), ap7k->jtag.dpc);
613
614 return ERROR_OK;
615 }
616
617 int avr32_ap7k_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size)
618 {
619 #if 0
620 /* get pointers to arch-specific information */
621 int i;
622
623 /* include floating point registers */
624 *reg_list_size = AVR32NUMCOREREGS + AVR32NUMFPREGS;
625 *reg_list = malloc(sizeof(struct reg*) * (*reg_list_size));
626
627 for (i = 0; i < AVR32NUMCOREREGS; i++)
628 {
629 (*reg_list)[i] = &mips32->core_cache->reg_list[i];
630 }
631
632 /* add dummy floating points regs */
633 for (i = AVR32NUMCOREREGS; i < (AVR32NUMCOREREGS + AVR32NUMFPREGS); i++)
634 {
635 (*reg_list)[i] = &avr32_ap7k_gdb_dummy_fp_reg;
636 }
637 #endif
638
639 LOG_ERROR("%s: implement me", __func__);
640 return ERROR_FAIL;
641 }
642
643
644
645 struct target_type avr32_ap7k_target =
646 {
647 .name = "avr32_ap7k",
648
649 .poll = avr32_ap7k_poll,
650 .arch_state = avr32_ap7k_arch_state,
651
652 .target_request_data = NULL,
653
654 .halt = avr32_ap7k_halt,
655 .resume = avr32_ap7k_resume,
656 .step = avr32_ap7k_step,
657
658 .assert_reset = avr32_ap7k_assert_reset,
659 .deassert_reset = avr32_ap7k_deassert_reset,
660 .soft_reset_halt = avr32_ap7k_soft_reset_halt,
661
662 .get_gdb_reg_list = avr32_ap7k_get_gdb_reg_list,
663
664 .read_memory = avr32_ap7k_read_memory,
665 .write_memory = avr32_ap7k_write_memory,
666 .bulk_write_memory = avr32_ap7k_bulk_write_memory,
667 // .checksum_memory = avr32_ap7k_checksum_memory,
668 // .blank_check_memory = avr32_ap7k_blank_check_memory,
669
670 // .run_algorithm = avr32_ap7k_run_algorithm,
671
672 .add_breakpoint = avr32_ap7k_add_breakpoint,
673 .remove_breakpoint = avr32_ap7k_remove_breakpoint,
674 .add_watchpoint = avr32_ap7k_add_watchpoint,
675 .remove_watchpoint = avr32_ap7k_remove_watchpoint,
676
677 .target_create = avr32_ap7k_target_create,
678 .init_target = avr32_ap7k_init_target,
679 .examine = avr32_ap7k_examine,
680 };

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)