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

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)