Magnus Lundin <lundin@mlu.mine.nu>, Oyvind Harboe <oyvind.harboe@zylin.com>, David...
[openocd.git] / src / target / cortex_m3.c
1 /***************************************************************************
2 * Copyright (C) 2005 by Dominic Rath *
3 * Dominic.Rath@gmx.de *
4 * *
5 * Copyright (C) 2006 by Magnus Lundin *
6 * lundin@mlu.mine.nu *
7 * *
8 * Copyright (C) 2008 by Spencer Oliver *
9 * spen@spen-soft.co.uk *
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 * *
27 * Cortex-M3(tm) TRM, ARM DDI 0337E (r1p1) and 0337G (r2p0) *
28 * *
29 ***************************************************************************/
30 #ifdef HAVE_CONFIG_H
31 #include "config.h"
32 #endif
33
34 #include "cortex_m3.h"
35 #include "target_request.h"
36 #include "target_type.h"
37 #include "arm_disassembler.h"
38
39
40 /* cli handling */
41 int cortex_m3_register_commands(struct command_context_s *cmd_ctx);
42 int handle_cortex_m3_mask_interrupts_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
43
44 /* forward declarations */
45 void cortex_m3_enable_breakpoints(struct target_s *target);
46 void cortex_m3_enable_watchpoints(struct target_s *target);
47 int cortex_m3_target_create(struct target_s *target, Jim_Interp *interp);
48 int cortex_m3_init_target(struct command_context_s *cmd_ctx, struct target_s *target);
49 int cortex_m3_quit(void);
50 int cortex_m3_load_core_reg_u32(target_t *target, enum armv7m_regtype type, uint32_t num, uint32_t *value);
51 int cortex_m3_store_core_reg_u32(target_t *target, enum armv7m_regtype type, uint32_t num, uint32_t value);
52 int cortex_m3_target_request_data(target_t *target, uint32_t size, uint8_t *buffer);
53 int cortex_m3_examine(struct target_s *target);
54
55 #ifdef ARMV7_GDB_HACKS
56 extern uint8_t armv7m_gdb_dummy_cpsr_value[];
57 extern reg_t armv7m_gdb_dummy_cpsr_reg;
58 #endif
59
60 target_type_t cortexm3_target =
61 {
62 .name = "cortex_m3",
63
64 .poll = cortex_m3_poll,
65 .arch_state = armv7m_arch_state,
66
67 .target_request_data = cortex_m3_target_request_data,
68
69 .halt = cortex_m3_halt,
70 .resume = cortex_m3_resume,
71 .step = cortex_m3_step,
72
73 .assert_reset = cortex_m3_assert_reset,
74 .deassert_reset = cortex_m3_deassert_reset,
75 .soft_reset_halt = cortex_m3_soft_reset_halt,
76
77 .get_gdb_reg_list = armv7m_get_gdb_reg_list,
78
79 .read_memory = cortex_m3_read_memory,
80 .write_memory = cortex_m3_write_memory,
81 .bulk_write_memory = cortex_m3_bulk_write_memory,
82 .checksum_memory = armv7m_checksum_memory,
83 .blank_check_memory = armv7m_blank_check_memory,
84
85 .run_algorithm = armv7m_run_algorithm,
86
87 .add_breakpoint = cortex_m3_add_breakpoint,
88 .remove_breakpoint = cortex_m3_remove_breakpoint,
89 .add_watchpoint = cortex_m3_add_watchpoint,
90 .remove_watchpoint = cortex_m3_remove_watchpoint,
91
92 .register_commands = cortex_m3_register_commands,
93 .target_create = cortex_m3_target_create,
94 .init_target = cortex_m3_init_target,
95 .examine = cortex_m3_examine,
96 .quit = cortex_m3_quit
97 };
98
99 int cortexm3_dap_read_coreregister_u32(swjdp_common_t *swjdp, uint32_t *value, int regnum)
100 {
101 int retval;
102 uint32_t dcrdr;
103
104 /* because the DCB_DCRDR is used for the emulated dcc channel
105 * we gave to save/restore the DCB_DCRDR when used */
106
107 mem_ap_read_u32(swjdp, DCB_DCRDR, &dcrdr);
108
109 swjdp->trans_mode = TRANS_MODE_COMPOSITE;
110
111 /* mem_ap_write_u32(swjdp, DCB_DCRSR, regnum); */
112 dap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, DCB_DCRSR & 0xFFFFFFF0);
113 dap_ap_write_reg_u32(swjdp, AP_REG_BD0 | (DCB_DCRSR & 0xC), regnum);
114
115 /* mem_ap_read_u32(swjdp, DCB_DCRDR, value); */
116 dap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, DCB_DCRDR & 0xFFFFFFF0);
117 dap_ap_read_reg_u32(swjdp, AP_REG_BD0 | (DCB_DCRDR & 0xC), value);
118
119 mem_ap_write_u32(swjdp, DCB_DCRDR, dcrdr);
120 retval = swjdp_transaction_endcheck(swjdp);
121 return retval;
122 }
123
124 int cortexm3_dap_write_coreregister_u32(swjdp_common_t *swjdp, uint32_t value, int regnum)
125 {
126 int retval;
127 uint32_t dcrdr;
128
129 /* because the DCB_DCRDR is used for the emulated dcc channel
130 * we gave to save/restore the DCB_DCRDR when used */
131
132 mem_ap_read_u32(swjdp, DCB_DCRDR, &dcrdr);
133
134 swjdp->trans_mode = TRANS_MODE_COMPOSITE;
135
136 /* mem_ap_write_u32(swjdp, DCB_DCRDR, core_regs[i]); */
137 dap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, DCB_DCRDR & 0xFFFFFFF0);
138 dap_ap_write_reg_u32(swjdp, AP_REG_BD0 | (DCB_DCRDR & 0xC), value);
139
140 /* mem_ap_write_u32(swjdp, DCB_DCRSR, i | DCRSR_WnR); */
141 dap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, DCB_DCRSR & 0xFFFFFFF0);
142 dap_ap_write_reg_u32(swjdp, AP_REG_BD0 | (DCB_DCRSR & 0xC), regnum | DCRSR_WnR);
143
144 mem_ap_write_u32(swjdp, DCB_DCRDR, dcrdr);
145 retval = swjdp_transaction_endcheck(swjdp);
146 return retval;
147 }
148
149
150 int cortex_m3_write_debug_halt_mask(target_t *target, uint32_t mask_on, uint32_t mask_off)
151 {
152 /* get pointers to arch-specific information */
153 armv7m_common_t *armv7m = target->arch_info;
154 cortex_m3_common_t *cortex_m3 = armv7m->arch_info;
155 swjdp_common_t *swjdp = &armv7m->swjdp_info;
156
157 /* mask off status bits */
158 cortex_m3->dcb_dhcsr &= ~((0xFFFF << 16) | mask_off);
159 /* create new register mask */
160 cortex_m3->dcb_dhcsr |= DBGKEY | C_DEBUGEN | mask_on;
161
162 return mem_ap_write_atomic_u32(swjdp, DCB_DHCSR, cortex_m3->dcb_dhcsr);
163 }
164
165 int cortex_m3_clear_halt(target_t *target)
166 {
167 /* get pointers to arch-specific information */
168 armv7m_common_t *armv7m = target->arch_info;
169 cortex_m3_common_t *cortex_m3 = armv7m->arch_info;
170 swjdp_common_t *swjdp = &armv7m->swjdp_info;
171
172 /* clear step if any */
173 cortex_m3_write_debug_halt_mask(target, C_HALT, C_STEP);
174
175 /* Read Debug Fault Status Register */
176 mem_ap_read_atomic_u32(swjdp, NVIC_DFSR, &cortex_m3->nvic_dfsr);
177 /* Write Debug Fault Status Register to enable processing to resume ?? Try with and without this !! */
178 mem_ap_write_atomic_u32(swjdp, NVIC_DFSR, cortex_m3->nvic_dfsr);
179 LOG_DEBUG(" NVIC_DFSR 0x%" PRIx32 "", cortex_m3->nvic_dfsr);
180
181 return ERROR_OK;
182 }
183
184 int cortex_m3_single_step_core(target_t *target)
185 {
186 /* get pointers to arch-specific information */
187 armv7m_common_t *armv7m = target->arch_info;
188 cortex_m3_common_t *cortex_m3 = armv7m->arch_info;
189 swjdp_common_t *swjdp = &armv7m->swjdp_info;
190 uint32_t dhcsr_save;
191
192 /* backup dhcsr reg */
193 dhcsr_save = cortex_m3->dcb_dhcsr;
194
195 /* mask interrupts if not done already */
196 if (!(cortex_m3->dcb_dhcsr & C_MASKINTS))
197 mem_ap_write_atomic_u32(swjdp, DCB_DHCSR, DBGKEY | C_MASKINTS | C_HALT | C_DEBUGEN);
198 mem_ap_write_atomic_u32(swjdp, DCB_DHCSR, DBGKEY | C_MASKINTS | C_STEP | C_DEBUGEN);
199 LOG_DEBUG(" ");
200
201 /* restore dhcsr reg */
202 cortex_m3->dcb_dhcsr = dhcsr_save;
203 cortex_m3_clear_halt(target);
204
205 return ERROR_OK;
206 }
207
208 int cortex_m3_exec_opcode(target_t *target,uint32_t opcode, int len /* MODE, r0_invalue, &r0_outvalue */)
209 {
210 /* get pointers to arch-specific information */
211 armv7m_common_t *armv7m = target->arch_info;
212 swjdp_common_t *swjdp = &armv7m->swjdp_info;
213 uint32_t savedram;
214 int retvalue;
215
216 mem_ap_read_u32(swjdp, 0x20000000, &savedram);
217 mem_ap_write_u32(swjdp, 0x20000000, opcode);
218 cortexm3_dap_write_coreregister_u32(swjdp, 0x20000000, 15);
219 cortex_m3_single_step_core(target);
220 armv7m->core_cache->reg_list[15].dirty = armv7m->core_cache->reg_list[15].valid;
221 retvalue = mem_ap_write_atomic_u32(swjdp, 0x20000000, savedram);
222
223 return retvalue;
224 }
225
226 #if 0
227 /* Enable interrupts */
228 int cortex_m3_cpsie(target_t *target, uint32_t IF)
229 {
230 return cortex_m3_exec_opcode(target, ARMV7M_T_CPSIE(IF), 2);
231 }
232
233 /* Disable interrupts */
234 int cortex_m3_cpsid(target_t *target, uint32_t IF)
235 {
236 return cortex_m3_exec_opcode(target, ARMV7M_T_CPSID(IF), 2);
237 }
238 #endif
239
240 int cortex_m3_endreset_event(target_t *target)
241 {
242 int i;
243 uint32_t dcb_demcr;
244
245 /* get pointers to arch-specific information */
246 armv7m_common_t *armv7m = target->arch_info;
247 cortex_m3_common_t *cortex_m3 = armv7m->arch_info;
248 swjdp_common_t *swjdp = &armv7m->swjdp_info;
249 cortex_m3_fp_comparator_t *fp_list = cortex_m3->fp_comparator_list;
250 cortex_m3_dwt_comparator_t *dwt_list = cortex_m3->dwt_comparator_list;
251
252 mem_ap_read_atomic_u32(swjdp, DCB_DEMCR, &dcb_demcr);
253 LOG_DEBUG("DCB_DEMCR = 0x%8.8" PRIx32 "",dcb_demcr);
254
255 /* this regsiter is used for emulated dcc channel */
256 mem_ap_write_u32(swjdp, DCB_DCRDR, 0);
257
258 /* Enable debug requests */
259 mem_ap_read_atomic_u32(swjdp, DCB_DHCSR, &cortex_m3->dcb_dhcsr);
260 if (!(cortex_m3->dcb_dhcsr & C_DEBUGEN))
261 mem_ap_write_u32(swjdp, DCB_DHCSR, DBGKEY | C_DEBUGEN);
262
263 /* clear any interrupt masking */
264 cortex_m3_write_debug_halt_mask(target, 0, C_MASKINTS);
265
266 /* Enable trace and dwt */
267 mem_ap_write_u32(swjdp, DCB_DEMCR, TRCENA | VC_HARDERR | VC_BUSERR);
268 /* Monitor bus faults */
269 mem_ap_write_u32(swjdp, NVIC_SHCSR, SHCSR_BUSFAULTENA);
270
271 /* Enable FPB */
272 target_write_u32(target, FP_CTRL, 3);
273 cortex_m3->fpb_enabled = 1;
274
275 /* Restore FPB registers */
276 for (i = 0; i < cortex_m3->fp_num_code + cortex_m3->fp_num_lit; i++)
277 {
278 target_write_u32(target, fp_list[i].fpcr_address, fp_list[i].fpcr_value);
279 }
280
281 /* Restore DWT registers */
282 for (i = 0; i < cortex_m3->dwt_num_comp; i++)
283 {
284 target_write_u32(target, dwt_list[i].dwt_comparator_address, dwt_list[i].comp);
285 target_write_u32(target, dwt_list[i].dwt_comparator_address | 0x4, dwt_list[i].mask);
286 target_write_u32(target, dwt_list[i].dwt_comparator_address | 0x8, dwt_list[i].function);
287 }
288 swjdp_transaction_endcheck(swjdp);
289
290 armv7m_invalidate_core_regs(target);
291
292 /* make sure we have latest dhcsr flags */
293 mem_ap_read_atomic_u32(swjdp, DCB_DHCSR, &cortex_m3->dcb_dhcsr);
294
295 return ERROR_OK;
296 }
297
298 int cortex_m3_examine_debug_reason(target_t *target)
299 {
300 /* get pointers to arch-specific information */
301 armv7m_common_t *armv7m = target->arch_info;
302 cortex_m3_common_t *cortex_m3 = armv7m->arch_info;
303
304 /* THIS IS NOT GOOD, TODO - better logic for detection of debug state reason */
305 /* only check the debug reason if we don't know it already */
306
307 if ((target->debug_reason != DBG_REASON_DBGRQ)
308 && (target->debug_reason != DBG_REASON_SINGLESTEP))
309 {
310 /* INCOMPLETE */
311
312 if (cortex_m3->nvic_dfsr & DFSR_BKPT)
313 {
314 target->debug_reason = DBG_REASON_BREAKPOINT;
315 if (cortex_m3->nvic_dfsr & DFSR_DWTTRAP)
316 target->debug_reason = DBG_REASON_WPTANDBKPT;
317 }
318 else if (cortex_m3->nvic_dfsr & DFSR_DWTTRAP)
319 target->debug_reason = DBG_REASON_WATCHPOINT;
320 }
321
322 return ERROR_OK;
323 }
324
325 int cortex_m3_examine_exception_reason(target_t *target)
326 {
327 uint32_t shcsr, except_sr, cfsr = -1, except_ar = -1;
328
329 /* get pointers to arch-specific information */
330 armv7m_common_t *armv7m = target->arch_info;
331 swjdp_common_t *swjdp = &armv7m->swjdp_info;
332
333 mem_ap_read_u32(swjdp, NVIC_SHCSR, &shcsr);
334 switch (armv7m->exception_number)
335 {
336 case 2: /* NMI */
337 break;
338 case 3: /* Hard Fault */
339 mem_ap_read_atomic_u32(swjdp, NVIC_HFSR, &except_sr);
340 if (except_sr & 0x40000000)
341 {
342 mem_ap_read_u32(swjdp, NVIC_CFSR, &cfsr);
343 }
344 break;
345 case 4: /* Memory Management */
346 mem_ap_read_u32(swjdp, NVIC_CFSR, &except_sr);
347 mem_ap_read_u32(swjdp, NVIC_MMFAR, &except_ar);
348 break;
349 case 5: /* Bus Fault */
350 mem_ap_read_u32(swjdp, NVIC_CFSR, &except_sr);
351 mem_ap_read_u32(swjdp, NVIC_BFAR, &except_ar);
352 break;
353 case 6: /* Usage Fault */
354 mem_ap_read_u32(swjdp, NVIC_CFSR, &except_sr);
355 break;
356 case 11: /* SVCall */
357 break;
358 case 12: /* Debug Monitor */
359 mem_ap_read_u32(swjdp, NVIC_DFSR, &except_sr);
360 break;
361 case 14: /* PendSV */
362 break;
363 case 15: /* SysTick */
364 break;
365 default:
366 except_sr = 0;
367 break;
368 }
369 swjdp_transaction_endcheck(swjdp);
370 LOG_DEBUG("%s SHCSR 0x%" PRIx32 ", SR 0x%" PRIx32 ", CFSR 0x%" PRIx32 ", AR 0x%" PRIx32 "", armv7m_exception_string(armv7m->exception_number), \
371 shcsr, except_sr, cfsr, except_ar);
372 return ERROR_OK;
373 }
374
375 int cortex_m3_debug_entry(target_t *target)
376 {
377 int i;
378 uint32_t xPSR;
379 int retval;
380
381 /* get pointers to arch-specific information */
382 armv7m_common_t *armv7m = target->arch_info;
383 cortex_m3_common_t *cortex_m3 = armv7m->arch_info;
384 swjdp_common_t *swjdp = &armv7m->swjdp_info;
385
386 LOG_DEBUG(" ");
387 if (armv7m->pre_debug_entry)
388 armv7m->pre_debug_entry(target);
389
390 cortex_m3_clear_halt(target);
391 mem_ap_read_atomic_u32(swjdp, DCB_DHCSR, &cortex_m3->dcb_dhcsr);
392
393 if ((retval = armv7m->examine_debug_reason(target)) != ERROR_OK)
394 return retval;
395
396 /* Examine target state and mode */
397 /* First load register acessible through core debug port*/
398 for (i = 0; i < ARMV7NUMCOREREGS; i++)
399 {
400 if (!armv7m->core_cache->reg_list[i].valid)
401 armv7m->read_core_reg(target, i);
402 }
403
404 xPSR = buf_get_u32(armv7m->core_cache->reg_list[ARMV7M_xPSR].value, 0, 32);
405
406 #ifdef ARMV7_GDB_HACKS
407 /* copy real xpsr reg for gdb, setting thumb bit */
408 buf_set_u32(armv7m_gdb_dummy_cpsr_value, 0, 32, xPSR);
409 buf_set_u32(armv7m_gdb_dummy_cpsr_value, 5, 1, 1);
410 armv7m_gdb_dummy_cpsr_reg.valid = armv7m->core_cache->reg_list[ARMV7M_xPSR].valid;
411 armv7m_gdb_dummy_cpsr_reg.dirty = armv7m->core_cache->reg_list[ARMV7M_xPSR].dirty;
412 #endif
413
414 /* For IT instructions xPSR must be reloaded on resume and clear on debug exec */
415 if (xPSR & 0xf00)
416 {
417 armv7m->core_cache->reg_list[ARMV7M_xPSR].dirty = armv7m->core_cache->reg_list[ARMV7M_xPSR].valid;
418 cortex_m3_store_core_reg_u32(target, ARMV7M_REGISTER_CORE_GP, 16, xPSR &~ 0xff);
419 }
420
421 /* Are we in an exception handler */
422 if (xPSR & 0x1FF)
423 {
424 armv7m->core_mode = ARMV7M_MODE_HANDLER;
425 armv7m->exception_number = (xPSR & 0x1FF);
426 }
427 else if (armv7m->has_spec20)
428 {
429 /* NOTE: CONTROL is bits 31:24 of SPEC20 register, holding
430 * a two-bit field. Unavailable before r2p0...
431 */
432 armv7m->core_mode = buf_get_u32(
433 armv7m->core_cache->reg_list[ARMV7M_SPEC20].value, 24, 2);
434 armv7m->exception_number = 0;
435 }
436
437 if (armv7m->exception_number)
438 {
439 cortex_m3_examine_exception_reason(target);
440 }
441
442 LOG_DEBUG("entered debug state in core mode: %s at PC 0x%" PRIx32 ", target->state: %s",
443 armv7m_mode_strings[armv7m->core_mode],
444 *(uint32_t*)(armv7m->core_cache->reg_list[15].value),
445 target_state_name(target));
446
447 if (armv7m->post_debug_entry)
448 armv7m->post_debug_entry(target);
449
450 return ERROR_OK;
451 }
452
453 int cortex_m3_poll(target_t *target)
454 {
455 int retval;
456 enum target_state prev_target_state = target->state;
457
458 /* get pointers to arch-specific information */
459 armv7m_common_t *armv7m = target->arch_info;
460 cortex_m3_common_t *cortex_m3 = armv7m->arch_info;
461 swjdp_common_t *swjdp = &armv7m->swjdp_info;
462
463 /* Read from Debug Halting Control and Status Register */
464 retval = mem_ap_read_atomic_u32(swjdp, DCB_DHCSR, &cortex_m3->dcb_dhcsr);
465 if (retval != ERROR_OK)
466 {
467 target->state = TARGET_UNKNOWN;
468 return retval;
469 }
470
471 if (cortex_m3->dcb_dhcsr & S_RESET_ST)
472 {
473 /* check if still in reset */
474 mem_ap_read_atomic_u32(swjdp, DCB_DHCSR, &cortex_m3->dcb_dhcsr);
475
476 if (cortex_m3->dcb_dhcsr & S_RESET_ST)
477 {
478 target->state = TARGET_RESET;
479 return ERROR_OK;
480 }
481 }
482
483 if (target->state == TARGET_RESET)
484 {
485 /* Cannot switch context while running so endreset is called with target->state == TARGET_RESET */
486 LOG_DEBUG("Exit from reset with dcb_dhcsr 0x%" PRIx32 "", cortex_m3->dcb_dhcsr);
487 cortex_m3_endreset_event(target);
488 target->state = TARGET_RUNNING;
489 prev_target_state = TARGET_RUNNING;
490 }
491
492 if (cortex_m3->dcb_dhcsr & S_HALT)
493 {
494 target->state = TARGET_HALTED;
495
496 if ((prev_target_state == TARGET_RUNNING) || (prev_target_state == TARGET_RESET))
497 {
498 if ((retval = cortex_m3_debug_entry(target)) != ERROR_OK)
499 return retval;
500
501 target_call_event_callbacks(target, TARGET_EVENT_HALTED);
502 }
503 if (prev_target_state == TARGET_DEBUG_RUNNING)
504 {
505 LOG_DEBUG(" ");
506 if ((retval = cortex_m3_debug_entry(target)) != ERROR_OK)
507 return retval;
508
509 target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED);
510 }
511 }
512
513 /* REVISIT when S_SLEEP is set, it's in a Sleep or DeepSleep state.
514 * How best to model low power modes?
515 */
516
517 if (target->state == TARGET_UNKNOWN)
518 {
519 /* check if processor is retiring instructions */
520 if (cortex_m3->dcb_dhcsr & S_RETIRE_ST)
521 {
522 target->state = TARGET_RUNNING;
523 return ERROR_OK;
524 }
525 }
526
527 return ERROR_OK;
528 }
529
530 int cortex_m3_halt(target_t *target)
531 {
532 LOG_DEBUG("target->state: %s",
533 target_state_name(target));
534
535 if (target->state == TARGET_HALTED)
536 {
537 LOG_DEBUG("target was already halted");
538 return ERROR_OK;
539 }
540
541 if (target->state == TARGET_UNKNOWN)
542 {
543 LOG_WARNING("target was in unknown state when halt was requested");
544 }
545
546 if (target->state == TARGET_RESET)
547 {
548 if ((jtag_get_reset_config() & RESET_SRST_PULLS_TRST) && jtag_get_srst())
549 {
550 LOG_ERROR("can't request a halt while in reset if nSRST pulls nTRST");
551 return ERROR_TARGET_FAILURE;
552 }
553 else
554 {
555 /* we came here in a reset_halt or reset_init sequence
556 * debug entry was already prepared in cortex_m3_prepare_reset_halt()
557 */
558 target->debug_reason = DBG_REASON_DBGRQ;
559
560 return ERROR_OK;
561 }
562 }
563
564 /* Write to Debug Halting Control and Status Register */
565 cortex_m3_write_debug_halt_mask(target, C_HALT, 0);
566
567 target->debug_reason = DBG_REASON_DBGRQ;
568
569 return ERROR_OK;
570 }
571
572 int cortex_m3_soft_reset_halt(struct target_s *target)
573 {
574 /* get pointers to arch-specific information */
575 armv7m_common_t *armv7m = target->arch_info;
576 cortex_m3_common_t *cortex_m3 = armv7m->arch_info;
577 swjdp_common_t *swjdp = &armv7m->swjdp_info;
578 uint32_t dcb_dhcsr = 0;
579 int retval, timeout = 0;
580
581 /* Enter debug state on reset, cf. end_reset_event() */
582 mem_ap_write_u32(swjdp, DCB_DEMCR, TRCENA | VC_HARDERR | VC_BUSERR | VC_CORERESET);
583
584 /* Request a reset */
585 mem_ap_write_atomic_u32(swjdp, NVIC_AIRCR, AIRCR_VECTKEY | AIRCR_VECTRESET);
586 target->state = TARGET_RESET;
587
588 /* registers are now invalid */
589 armv7m_invalidate_core_regs(target);
590
591 while (timeout < 100)
592 {
593 retval = mem_ap_read_atomic_u32(swjdp, DCB_DHCSR, &dcb_dhcsr);
594 if (retval == ERROR_OK)
595 {
596 mem_ap_read_atomic_u32(swjdp, NVIC_DFSR, &cortex_m3->nvic_dfsr);
597 if ((dcb_dhcsr & S_HALT) && (cortex_m3->nvic_dfsr & DFSR_VCATCH))
598 {
599 LOG_DEBUG("system reset-halted, dcb_dhcsr 0x%" PRIx32 ", nvic_dfsr 0x%" PRIx32 "", dcb_dhcsr, cortex_m3->nvic_dfsr);
600 cortex_m3_poll(target);
601 return ERROR_OK;
602 }
603 else
604 LOG_DEBUG("waiting for system reset-halt, dcb_dhcsr 0x%" PRIx32 ", %i ms", dcb_dhcsr, timeout);
605 }
606 timeout++;
607 alive_sleep(1);
608 }
609
610 return ERROR_OK;
611 }
612
613 int cortex_m3_resume(struct target_s *target, int current, uint32_t address, int handle_breakpoints, int debug_execution)
614 {
615 /* get pointers to arch-specific information */
616 armv7m_common_t *armv7m = target->arch_info;
617 breakpoint_t *breakpoint = NULL;
618 uint32_t resume_pc;
619
620 if (target->state != TARGET_HALTED)
621 {
622 LOG_WARNING("target not halted");
623 return ERROR_TARGET_NOT_HALTED;
624 }
625
626 if (!debug_execution)
627 {
628 target_free_all_working_areas(target);
629 cortex_m3_enable_breakpoints(target);
630 cortex_m3_enable_watchpoints(target);
631 }
632
633 if (debug_execution)
634 {
635 /* Disable interrupts */
636 /* We disable interrupts in the PRIMASK register instead
637 * of masking with C_MASKINTS,
638 * This is probably the same issue as Cortex-M3 Errata 377493:
639 * C_MASKINTS in parallel with disabled interrupts can cause
640 * local faults to not be taken. (FIXED in r1p0 and later.)
641 *
642 * NOTE: PRIMASK is bits 7:0 of SPEC20 register, holding a
643 * one bit field. Available this way for r2p0 and later...
644 */
645 if (armv7m->has_spec20) {
646 buf_set_u32(armv7m->core_cache->reg_list[ARMV7M_SPEC20]
647 .value, 0, 1, 1);
648 armv7m->core_cache->reg_list[ARMV7M_SPEC20].dirty = 1;
649 armv7m->core_cache->reg_list[ARMV7M_SPEC20].valid = 1;
650 }
651
652 /* Make sure we are in Thumb mode */
653 buf_set_u32(armv7m->core_cache->reg_list[ARMV7M_xPSR].value, 0, 32,
654 buf_get_u32(armv7m->core_cache->reg_list[ARMV7M_xPSR].value, 0, 32)
655 | (1 << 24));
656 armv7m->core_cache->reg_list[ARMV7M_xPSR].dirty = 1;
657 armv7m->core_cache->reg_list[ARMV7M_xPSR].valid = 1;
658 }
659
660 /* current = 1: continue on current pc, otherwise continue at <address> */
661 if (!current)
662 {
663 buf_set_u32(armv7m->core_cache->reg_list[15].value, 0, 32, address);
664 armv7m->core_cache->reg_list[15].dirty = 1;
665 armv7m->core_cache->reg_list[15].valid = 1;
666 }
667
668 resume_pc = buf_get_u32(armv7m->core_cache->reg_list[15].value, 0, 32);
669
670 armv7m_restore_context(target);
671
672 /* the front-end may request us not to handle breakpoints */
673 if (handle_breakpoints)
674 {
675 /* Single step past breakpoint at current address */
676 if ((breakpoint = breakpoint_find(target, resume_pc)))
677 {
678 LOG_DEBUG("unset breakpoint at 0x%8.8" PRIx32 " (ID: %d)",
679 breakpoint->address,
680 breakpoint->unique_id );
681 cortex_m3_unset_breakpoint(target, breakpoint);
682 cortex_m3_single_step_core(target);
683 cortex_m3_set_breakpoint(target, breakpoint);
684 }
685 }
686
687 /* Restart core */
688 cortex_m3_write_debug_halt_mask(target, 0, C_HALT);
689
690 target->debug_reason = DBG_REASON_NOTHALTED;
691
692 /* registers are now invalid */
693 armv7m_invalidate_core_regs(target);
694 if (!debug_execution)
695 {
696 target->state = TARGET_RUNNING;
697 target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
698 LOG_DEBUG("target resumed at 0x%" PRIx32 "", resume_pc);
699 }
700 else
701 {
702 target->state = TARGET_DEBUG_RUNNING;
703 target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED);
704 LOG_DEBUG("target debug resumed at 0x%" PRIx32 "", resume_pc);
705 }
706
707 return ERROR_OK;
708 }
709
710 /* int irqstepcount = 0; */
711 int cortex_m3_step(struct target_s *target, int current, uint32_t address, int handle_breakpoints)
712 {
713 /* get pointers to arch-specific information */
714 armv7m_common_t *armv7m = target->arch_info;
715 cortex_m3_common_t *cortex_m3 = armv7m->arch_info;
716 swjdp_common_t *swjdp = &armv7m->swjdp_info;
717 breakpoint_t *breakpoint = NULL;
718
719 if (target->state != TARGET_HALTED)
720 {
721 LOG_WARNING("target not halted");
722 return ERROR_TARGET_NOT_HALTED;
723 }
724
725 /* current = 1: continue on current pc, otherwise continue at <address> */
726 if (!current)
727 buf_set_u32(armv7m->core_cache->reg_list[15].value, 0, 32, address);
728
729 /* the front-end may request us not to handle breakpoints */
730 if (handle_breakpoints)
731 if ((breakpoint = breakpoint_find(target, buf_get_u32(armv7m->core_cache->reg_list[15].value, 0, 32))))
732 cortex_m3_unset_breakpoint(target, breakpoint);
733
734 target->debug_reason = DBG_REASON_SINGLESTEP;
735
736 armv7m_restore_context(target);
737
738 target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
739
740 /* set step and clear halt */
741 cortex_m3_write_debug_halt_mask(target, C_STEP, C_HALT);
742 mem_ap_read_atomic_u32(swjdp, DCB_DHCSR, &cortex_m3->dcb_dhcsr);
743
744 /* registers are now invalid */
745 armv7m_invalidate_core_regs(target);
746
747 if (breakpoint)
748 cortex_m3_set_breakpoint(target, breakpoint);
749
750 LOG_DEBUG("target stepped dcb_dhcsr = 0x%" PRIx32 " nvic_icsr = 0x%" PRIx32 "", cortex_m3->dcb_dhcsr, cortex_m3->nvic_icsr);
751
752 cortex_m3_debug_entry(target);
753 target_call_event_callbacks(target, TARGET_EVENT_HALTED);
754
755 LOG_DEBUG("target stepped dcb_dhcsr = 0x%" PRIx32 " nvic_icsr = 0x%" PRIx32 "", cortex_m3->dcb_dhcsr, cortex_m3->nvic_icsr);
756 return ERROR_OK;
757 }
758
759 int cortex_m3_assert_reset(target_t *target)
760 {
761 armv7m_common_t *armv7m = target->arch_info;
762 cortex_m3_common_t *cortex_m3 = armv7m->arch_info;
763 swjdp_common_t *swjdp = &armv7m->swjdp_info;
764 int assert_srst = 1;
765
766 LOG_DEBUG("target->state: %s",
767 target_state_name(target));
768
769 enum reset_types jtag_reset_config = jtag_get_reset_config();
770 if (!(jtag_reset_config & RESET_HAS_SRST))
771 {
772 LOG_ERROR("Can't assert SRST");
773 return ERROR_FAIL;
774 }
775
776 /* Enable debug requests */
777 mem_ap_read_atomic_u32(swjdp, DCB_DHCSR, &cortex_m3->dcb_dhcsr);
778 if (!(cortex_m3->dcb_dhcsr & C_DEBUGEN))
779 mem_ap_write_u32(swjdp, DCB_DHCSR, DBGKEY | C_DEBUGEN);
780
781 mem_ap_write_u32(swjdp, DCB_DCRDR, 0);
782
783 if (!target->reset_halt)
784 {
785 /* Set/Clear C_MASKINTS in a separate operation */
786 if (cortex_m3->dcb_dhcsr & C_MASKINTS)
787 mem_ap_write_atomic_u32(swjdp, DCB_DHCSR, DBGKEY | C_DEBUGEN | C_HALT);
788
789 /* clear any debug flags before resuming */
790 cortex_m3_clear_halt(target);
791
792 /* clear C_HALT in dhcsr reg */
793 cortex_m3_write_debug_halt_mask(target, 0, C_HALT);
794
795 /* Enter debug state on reset, cf. end_reset_event() */
796 mem_ap_write_u32(swjdp, DCB_DEMCR, TRCENA | VC_HARDERR | VC_BUSERR);
797 }
798 else
799 {
800 /* Enter debug state on reset, cf. end_reset_event() */
801 mem_ap_write_atomic_u32(swjdp, DCB_DEMCR, TRCENA | VC_HARDERR | VC_BUSERR | VC_CORERESET);
802 }
803
804 /* following hack is to handle luminary reset
805 * when srst is asserted the luminary device seesm to also clear the debug registers
806 * which does not match the armv7 debug TRM */
807
808 if (strcmp(target->variant, "lm3s") == 0)
809 {
810 /* get revision of lm3s target, only early silicon has this issue
811 * Fury Rev B, DustDevil Rev B, Tempest all ok */
812
813 uint32_t did0;
814
815 if (target_read_u32(target, 0x400fe000, &did0) == ERROR_OK)
816 {
817 switch ((did0 >> 16) & 0xff)
818 {
819 case 0:
820 /* all Sandstorm suffer issue */
821 assert_srst = 0;
822 break;
823
824 case 1:
825 case 3:
826 /* only Fury/DustDevil rev A suffer reset problems */
827 if (((did0 >> 8) & 0xff) == 0)
828 assert_srst = 0;
829 break;
830 }
831 }
832 }
833
834 if (assert_srst)
835 {
836 /* default to asserting srst */
837 if (jtag_reset_config & RESET_SRST_PULLS_TRST)
838 {
839 jtag_add_reset(1, 1);
840 }
841 else
842 {
843 jtag_add_reset(0, 1);
844 }
845 }
846 else
847 {
848 /* this causes the luminary device to reset using the watchdog */
849 mem_ap_write_atomic_u32(swjdp, NVIC_AIRCR, AIRCR_VECTKEY | AIRCR_SYSRESETREQ);
850 LOG_DEBUG("Using Luminary Reset: SYSRESETREQ");
851
852 {
853 /* I do not know why this is necessary, but it fixes strange effects
854 * (step/resume cause a NMI after reset) on LM3S6918 -- Michael Schwingen */
855 uint32_t tmp;
856 mem_ap_read_atomic_u32(swjdp, NVIC_AIRCR, &tmp);
857 }
858 }
859
860 target->state = TARGET_RESET;
861 jtag_add_sleep(50000);
862
863 armv7m_invalidate_core_regs(target);
864
865 if (target->reset_halt)
866 {
867 int retval;
868 if ((retval = target_halt(target)) != ERROR_OK)
869 return retval;
870 }
871
872 return ERROR_OK;
873 }
874
875 int cortex_m3_deassert_reset(target_t *target)
876 {
877 LOG_DEBUG("target->state: %s",
878 target_state_name(target));
879
880 /* deassert reset lines */
881 jtag_add_reset(0, 0);
882
883 return ERROR_OK;
884 }
885
886 void cortex_m3_enable_breakpoints(struct target_s *target)
887 {
888 breakpoint_t *breakpoint = target->breakpoints;
889
890 /* set any pending breakpoints */
891 while (breakpoint)
892 {
893 if (breakpoint->set == 0)
894 cortex_m3_set_breakpoint(target, breakpoint);
895 breakpoint = breakpoint->next;
896 }
897 }
898
899 int cortex_m3_set_breakpoint(struct target_s *target, breakpoint_t *breakpoint)
900 {
901 int retval;
902 int fp_num = 0;
903 uint32_t hilo;
904
905 /* get pointers to arch-specific information */
906 armv7m_common_t *armv7m = target->arch_info;
907 cortex_m3_common_t *cortex_m3 = armv7m->arch_info;
908
909 cortex_m3_fp_comparator_t * comparator_list = cortex_m3->fp_comparator_list;
910
911 if (breakpoint->set)
912 {
913 LOG_WARNING("breakpoint (BPID: %d) already set", breakpoint->unique_id);
914 return ERROR_OK;
915 }
916
917 if (cortex_m3->auto_bp_type)
918 {
919 breakpoint->type = (breakpoint->address < 0x20000000) ? BKPT_HARD : BKPT_SOFT;
920 }
921
922 if (breakpoint->type == BKPT_HARD)
923 {
924 while (comparator_list[fp_num].used && (fp_num < cortex_m3->fp_num_code))
925 fp_num++;
926 if (fp_num >= cortex_m3->fp_num_code)
927 {
928 LOG_DEBUG("ERROR Can not find free FP Comparator");
929 LOG_WARNING("ERROR Can not find free FP Comparator");
930 exit(-1);
931 }
932 breakpoint->set = fp_num + 1;
933 hilo = (breakpoint->address & 0x2) ? FPCR_REPLACE_BKPT_HIGH : FPCR_REPLACE_BKPT_LOW;
934 comparator_list[fp_num].used = 1;
935 comparator_list[fp_num].fpcr_value = (breakpoint->address & 0x1FFFFFFC) | hilo | 1;
936 target_write_u32(target, comparator_list[fp_num].fpcr_address, comparator_list[fp_num].fpcr_value);
937 LOG_DEBUG("fpc_num %i fpcr_value 0x%" PRIx32 "", fp_num, comparator_list[fp_num].fpcr_value);
938 if (!cortex_m3->fpb_enabled)
939 {
940 LOG_DEBUG("FPB wasn't enabled, do it now");
941 target_write_u32(target, FP_CTRL, 3);
942 }
943 }
944 else if (breakpoint->type == BKPT_SOFT)
945 {
946 uint8_t code[4];
947 buf_set_u32(code, 0, 32, ARMV7M_T_BKPT(0x11));
948 if ((retval = target_read_memory(target, breakpoint->address & 0xFFFFFFFE, breakpoint->length, 1, breakpoint->orig_instr)) != ERROR_OK)
949 {
950 return retval;
951 }
952 if ((retval = target_write_memory(target, breakpoint->address & 0xFFFFFFFE, breakpoint->length, 1, code)) != ERROR_OK)
953 {
954 return retval;
955 }
956 breakpoint->set = 0x11; /* Any nice value but 0 */
957 }
958
959 LOG_DEBUG("BPID: %d, Type: %d, Address: 0x%08" PRIx32 " Length: %d (set=%d)",
960 breakpoint->unique_id,
961 (int)(breakpoint->type),
962 breakpoint->address,
963 breakpoint->length,
964 breakpoint->set);
965
966 return ERROR_OK;
967 }
968
969 int cortex_m3_unset_breakpoint(struct target_s *target, breakpoint_t *breakpoint)
970 {
971 int retval;
972 /* get pointers to arch-specific information */
973 armv7m_common_t *armv7m = target->arch_info;
974 cortex_m3_common_t *cortex_m3 = armv7m->arch_info;
975 cortex_m3_fp_comparator_t * comparator_list = cortex_m3->fp_comparator_list;
976
977 if (!breakpoint->set)
978 {
979 LOG_WARNING("breakpoint not set");
980 return ERROR_OK;
981 }
982
983 LOG_DEBUG("BPID: %d, Type: %d, Address: 0x%08" PRIx32 " Length: %d (set=%d)",
984 breakpoint->unique_id,
985 (int)(breakpoint->type),
986 breakpoint->address,
987 breakpoint->length,
988 breakpoint->set);
989
990 if (breakpoint->type == BKPT_HARD)
991 {
992 int fp_num = breakpoint->set - 1;
993 if ((fp_num < 0) || (fp_num >= cortex_m3->fp_num_code))
994 {
995 LOG_DEBUG("Invalid FP Comparator number in breakpoint");
996 return ERROR_OK;
997 }
998 comparator_list[fp_num].used = 0;
999 comparator_list[fp_num].fpcr_value = 0;
1000 target_write_u32(target, comparator_list[fp_num].fpcr_address, comparator_list[fp_num].fpcr_value);
1001 }
1002 else
1003 {
1004 /* restore original instruction (kept in target endianness) */
1005 if (breakpoint->length == 4)
1006 {
1007 if ((retval = target_write_memory(target, breakpoint->address & 0xFFFFFFFE, 4, 1, breakpoint->orig_instr)) != ERROR_OK)
1008 {
1009 return retval;
1010 }
1011 }
1012 else
1013 {
1014 if ((retval = target_write_memory(target, breakpoint->address & 0xFFFFFFFE, 2, 1, breakpoint->orig_instr)) != ERROR_OK)
1015 {
1016 return retval;
1017 }
1018 }
1019 }
1020 breakpoint->set = 0;
1021
1022 return ERROR_OK;
1023 }
1024
1025 int cortex_m3_add_breakpoint(struct target_s *target, breakpoint_t *breakpoint)
1026 {
1027 /* get pointers to arch-specific information */
1028 armv7m_common_t *armv7m = target->arch_info;
1029 cortex_m3_common_t *cortex_m3 = armv7m->arch_info;
1030
1031 if (cortex_m3->auto_bp_type)
1032 {
1033 breakpoint->type = (breakpoint->address < 0x20000000) ? BKPT_HARD : BKPT_SOFT;
1034 #ifdef ARMV7_GDB_HACKS
1035 if (breakpoint->length != 2) {
1036 /* XXX Hack: Replace all breakpoints with length != 2 with
1037 * a hardware breakpoint. */
1038 breakpoint->type = BKPT_HARD;
1039 breakpoint->length = 2;
1040 }
1041 #endif
1042 }
1043
1044 if ((breakpoint->type == BKPT_HARD) && (breakpoint->address >= 0x20000000))
1045 {
1046 LOG_INFO("flash patch comparator requested outside code memory region");
1047 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
1048 }
1049
1050 if ((breakpoint->type == BKPT_SOFT) && (breakpoint->address < 0x20000000))
1051 {
1052 LOG_INFO("soft breakpoint requested in code (flash) memory region");
1053 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
1054 }
1055
1056 if ((breakpoint->type == BKPT_HARD) && (cortex_m3->fp_code_available < 1))
1057 {
1058 LOG_INFO("no flash patch comparator unit available for hardware breakpoint");
1059 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
1060 }
1061
1062 if ((breakpoint->length != 2))
1063 {
1064 LOG_INFO("only breakpoints of two bytes length supported");
1065 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
1066 }
1067
1068 if (breakpoint->type == BKPT_HARD)
1069 cortex_m3->fp_code_available--;
1070 cortex_m3_set_breakpoint(target, breakpoint);
1071
1072 return ERROR_OK;
1073 }
1074
1075 int cortex_m3_remove_breakpoint(struct target_s *target, breakpoint_t *breakpoint)
1076 {
1077 /* get pointers to arch-specific information */
1078 armv7m_common_t *armv7m = target->arch_info;
1079 cortex_m3_common_t *cortex_m3 = armv7m->arch_info;
1080
1081 if (target->state != TARGET_HALTED)
1082 {
1083 LOG_WARNING("target not halted");
1084 return ERROR_TARGET_NOT_HALTED;
1085 }
1086
1087 if (cortex_m3->auto_bp_type)
1088 {
1089 breakpoint->type = (breakpoint->address < 0x20000000) ? BKPT_HARD : BKPT_SOFT;
1090 }
1091
1092 if (breakpoint->set)
1093 {
1094 cortex_m3_unset_breakpoint(target, breakpoint);
1095 }
1096
1097 if (breakpoint->type == BKPT_HARD)
1098 cortex_m3->fp_code_available++;
1099
1100 return ERROR_OK;
1101 }
1102
1103 int cortex_m3_set_watchpoint(struct target_s *target, watchpoint_t *watchpoint)
1104 {
1105 int dwt_num = 0;
1106 uint32_t mask, temp;
1107
1108 /* get pointers to arch-specific information */
1109 armv7m_common_t *armv7m = target->arch_info;
1110 cortex_m3_common_t *cortex_m3 = armv7m->arch_info;
1111 cortex_m3_dwt_comparator_t * comparator_list = cortex_m3->dwt_comparator_list;
1112
1113 if (watchpoint->set)
1114 {
1115 LOG_WARNING("watchpoint (%d) already set", watchpoint->unique_id );
1116 return ERROR_OK;
1117 }
1118
1119 if (watchpoint->mask == 0xffffffffu)
1120 {
1121 while (comparator_list[dwt_num].used && (dwt_num < cortex_m3->dwt_num_comp))
1122 dwt_num++;
1123 if (dwt_num >= cortex_m3->dwt_num_comp)
1124 {
1125 LOG_DEBUG("ERROR Can not find free DWT Comparator");
1126 LOG_WARNING("ERROR Can not find free DWT Comparator");
1127 return -1;
1128 }
1129 watchpoint->set = dwt_num + 1;
1130 mask = 0;
1131 temp = watchpoint->length;
1132 while (temp > 1)
1133 {
1134 temp = temp / 2;
1135 mask++;
1136 }
1137 comparator_list[dwt_num].used = 1;
1138 comparator_list[dwt_num].comp = watchpoint->address;
1139 comparator_list[dwt_num].mask = mask;
1140 comparator_list[dwt_num].function = watchpoint->rw + 5;
1141 target_write_u32(target, comparator_list[dwt_num].dwt_comparator_address, comparator_list[dwt_num].comp);
1142 target_write_u32(target, comparator_list[dwt_num].dwt_comparator_address | 0x4, comparator_list[dwt_num].mask);
1143 target_write_u32(target, comparator_list[dwt_num].dwt_comparator_address | 0x8, comparator_list[dwt_num].function);
1144 LOG_DEBUG("dwt_num %i 0x%" PRIx32 " 0x%" PRIx32 " 0x%" PRIx32 "", dwt_num, comparator_list[dwt_num].comp, comparator_list[dwt_num].mask, comparator_list[dwt_num].function);
1145 }
1146 else
1147 {
1148 /* Move this test to add_watchpoint */
1149 LOG_WARNING("Cannot watch data values (id: %d)",
1150 watchpoint->unique_id );
1151 return ERROR_OK;
1152 }
1153 LOG_DEBUG("Watchpoint (ID: %d) address: 0x%08" PRIx32 " set=%d ",
1154 watchpoint->unique_id, watchpoint->address, watchpoint->set );
1155 return ERROR_OK;
1156
1157 }
1158
1159 int cortex_m3_unset_watchpoint(struct target_s *target, watchpoint_t *watchpoint)
1160 {
1161 /* get pointers to arch-specific information */
1162 armv7m_common_t *armv7m = target->arch_info;
1163 cortex_m3_common_t *cortex_m3 = armv7m->arch_info;
1164 cortex_m3_dwt_comparator_t * comparator_list = cortex_m3->dwt_comparator_list;
1165 int dwt_num;
1166
1167 if (!watchpoint->set)
1168 {
1169 LOG_WARNING("watchpoint (wpid: %d) not set", watchpoint->unique_id );
1170 return ERROR_OK;
1171 }
1172
1173 LOG_DEBUG("Watchpoint (ID: %d) address: 0x%08" PRIx32 " set=%d ",
1174 watchpoint->unique_id, watchpoint->address,watchpoint->set );
1175
1176 dwt_num = watchpoint->set - 1;
1177
1178 if ((dwt_num < 0) || (dwt_num >= cortex_m3->dwt_num_comp))
1179 {
1180 LOG_DEBUG("Invalid DWT Comparator number in watchpoint");
1181 return ERROR_OK;
1182 }
1183 comparator_list[dwt_num].used = 0;
1184 comparator_list[dwt_num].function = 0;
1185 target_write_u32(target, comparator_list[dwt_num].dwt_comparator_address | 0x8, comparator_list[dwt_num].function);
1186
1187 watchpoint->set = 0;
1188
1189 return ERROR_OK;
1190 }
1191
1192 int cortex_m3_add_watchpoint(struct target_s *target, watchpoint_t *watchpoint)
1193 {
1194 /* get pointers to arch-specific information */
1195 armv7m_common_t *armv7m = target->arch_info;
1196 cortex_m3_common_t *cortex_m3 = armv7m->arch_info;
1197
1198 if (target->state != TARGET_HALTED)
1199 {
1200 LOG_WARNING("target not halted");
1201 return ERROR_TARGET_NOT_HALTED;
1202 }
1203
1204 if (cortex_m3->dwt_comp_available < 1)
1205 {
1206 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
1207 }
1208
1209 if ((watchpoint->length != 1) && (watchpoint->length != 2) && (watchpoint->length != 4))
1210 {
1211 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
1212 }
1213
1214 cortex_m3->dwt_comp_available--;
1215 LOG_DEBUG("dwt_comp_available: %d", cortex_m3->dwt_comp_available);
1216
1217 return ERROR_OK;
1218 }
1219
1220 int cortex_m3_remove_watchpoint(struct target_s *target, watchpoint_t *watchpoint)
1221 {
1222 /* get pointers to arch-specific information */
1223 armv7m_common_t *armv7m = target->arch_info;
1224 cortex_m3_common_t *cortex_m3 = armv7m->arch_info;
1225
1226 if (target->state != TARGET_HALTED)
1227 {
1228 LOG_WARNING("target not halted");
1229 return ERROR_TARGET_NOT_HALTED;
1230 }
1231
1232 if (watchpoint->set)
1233 {
1234 cortex_m3_unset_watchpoint(target, watchpoint);
1235 }
1236
1237 cortex_m3->dwt_comp_available++;
1238 LOG_DEBUG("dwt_comp_available: %d", cortex_m3->dwt_comp_available);
1239
1240 return ERROR_OK;
1241 }
1242
1243 void cortex_m3_enable_watchpoints(struct target_s *target)
1244 {
1245 watchpoint_t *watchpoint = target->watchpoints;
1246
1247 /* set any pending watchpoints */
1248 while (watchpoint)
1249 {
1250 if (watchpoint->set == 0)
1251 cortex_m3_set_watchpoint(target, watchpoint);
1252 watchpoint = watchpoint->next;
1253 }
1254 }
1255
1256 int cortex_m3_load_core_reg_u32(struct target_s *target, enum armv7m_regtype type, uint32_t num, uint32_t * value)
1257 {
1258 int retval;
1259 /* get pointers to arch-specific information */
1260 armv7m_common_t *armv7m = target->arch_info;
1261 swjdp_common_t *swjdp = &armv7m->swjdp_info;
1262
1263 if ((type == ARMV7M_REGISTER_CORE_GP) && (num <= ARMV7M_PSP))
1264 {
1265 /* read a normal core register */
1266 retval = cortexm3_dap_read_coreregister_u32(swjdp, value, num);
1267
1268 if (retval != ERROR_OK)
1269 {
1270 LOG_ERROR("JTAG failure %i",retval);
1271 return ERROR_JTAG_DEVICE_ERROR;
1272 }
1273 LOG_DEBUG("load from core reg %i value 0x%" PRIx32 "",(int)num,*value);
1274 }
1275 else if (type == ARMV7M_REGISTER_CORE_SP) /* Special purpose core register */
1276 {
1277 /* read other registers */
1278 cortexm3_dap_read_coreregister_u32(swjdp, value, 20);
1279
1280 switch (num)
1281 {
1282 case 19:
1283 *value = buf_get_u32((uint8_t*)value, 0, 8);
1284 break;
1285
1286 case 20:
1287 *value = buf_get_u32((uint8_t*)value, 8, 8);
1288 break;
1289
1290 case 21:
1291 *value = buf_get_u32((uint8_t*)value, 16, 8);
1292 break;
1293
1294 case 22:
1295 *value = buf_get_u32((uint8_t*)value, 24, 8);
1296 break;
1297 }
1298
1299 LOG_DEBUG("load from special reg %i value 0x%" PRIx32 "", (int)num, *value);
1300 }
1301 else
1302 {
1303 return ERROR_INVALID_ARGUMENTS;
1304 }
1305
1306 return ERROR_OK;
1307 }
1308
1309 int cortex_m3_store_core_reg_u32(struct target_s *target, enum armv7m_regtype type, uint32_t num, uint32_t value)
1310 {
1311 int retval;
1312 uint32_t reg;
1313
1314 /* get pointers to arch-specific information */
1315 armv7m_common_t *armv7m = target->arch_info;
1316 swjdp_common_t *swjdp = &armv7m->swjdp_info;
1317
1318 #ifdef ARMV7_GDB_HACKS
1319 /* If the LR register is being modified, make sure it will put us
1320 * in "thumb" mode, or an INVSTATE exception will occur. This is a
1321 * hack to deal with the fact that gdb will sometimes "forge"
1322 * return addresses, and doesn't set the LSB correctly (i.e., when
1323 * printing expressions containing function calls, it sets LR = 0.) */
1324
1325 if (num == 14)
1326 value |= 0x01;
1327 #endif
1328
1329 if ((type == ARMV7M_REGISTER_CORE_GP) && (num <= ARMV7M_PSP))
1330 {
1331 retval = cortexm3_dap_write_coreregister_u32(swjdp, value, num);
1332 if (retval != ERROR_OK)
1333 {
1334 LOG_ERROR("JTAG failure %i", retval);
1335 armv7m->core_cache->reg_list[num].dirty = armv7m->core_cache->reg_list[num].valid;
1336 return ERROR_JTAG_DEVICE_ERROR;
1337 }
1338 LOG_DEBUG("write core reg %i value 0x%" PRIx32 "", (int)num, value);
1339 }
1340 else if (type == ARMV7M_REGISTER_CORE_SP) /* Special purpose core register */
1341 {
1342 /* write other registers */
1343
1344 cortexm3_dap_read_coreregister_u32(swjdp, &reg, 20);
1345
1346 switch (num)
1347 {
1348 case 19:
1349 buf_set_u32((uint8_t*)&reg, 0, 8, value);
1350 break;
1351
1352 case 20:
1353 buf_set_u32((uint8_t*)&reg, 8, 8, value);
1354 break;
1355
1356 case 21:
1357 buf_set_u32((uint8_t*)&reg, 16, 8, value);
1358 break;
1359
1360 case 22:
1361 buf_set_u32((uint8_t*)&reg, 24, 8, value);
1362 break;
1363 }
1364
1365 cortexm3_dap_write_coreregister_u32(swjdp, reg, 20);
1366
1367 LOG_DEBUG("write special reg %i value 0x%" PRIx32 " ", (int)num, value);
1368 }
1369 else
1370 {
1371 return ERROR_INVALID_ARGUMENTS;
1372 }
1373
1374 return ERROR_OK;
1375 }
1376
1377 int cortex_m3_read_memory(struct target_s *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer)
1378 {
1379 /* get pointers to arch-specific information */
1380 armv7m_common_t *armv7m = target->arch_info;
1381 swjdp_common_t *swjdp = &armv7m->swjdp_info;
1382 int retval;
1383
1384 /* sanitize arguments */
1385 if (((size != 4) && (size != 2) && (size != 1)) || (count == 0) || !(buffer))
1386 return ERROR_INVALID_ARGUMENTS;
1387
1388 /* cortex_m3 handles unaligned memory access */
1389
1390 switch (size)
1391 {
1392 case 4:
1393 retval = mem_ap_read_buf_u32(swjdp, buffer, 4 * count, address);
1394 break;
1395 case 2:
1396 retval = mem_ap_read_buf_u16(swjdp, buffer, 2 * count, address);
1397 break;
1398 case 1:
1399 retval = mem_ap_read_buf_u8(swjdp, buffer, count, address);
1400 break;
1401 default:
1402 LOG_ERROR("BUG: we shouldn't get here");
1403 exit(-1);
1404 }
1405
1406 return retval;
1407 }
1408
1409 int cortex_m3_write_memory(struct target_s *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer)
1410 {
1411 /* get pointers to arch-specific information */
1412 armv7m_common_t *armv7m = target->arch_info;
1413 swjdp_common_t *swjdp = &armv7m->swjdp_info;
1414 int retval;
1415
1416 /* sanitize arguments */
1417 if (((size != 4) && (size != 2) && (size != 1)) || (count == 0) || !(buffer))
1418 return ERROR_INVALID_ARGUMENTS;
1419
1420 switch (size)
1421 {
1422 case 4:
1423 retval = mem_ap_write_buf_u32(swjdp, buffer, 4 * count, address);
1424 break;
1425 case 2:
1426 retval = mem_ap_write_buf_u16(swjdp, buffer, 2 * count, address);
1427 break;
1428 case 1:
1429 retval = mem_ap_write_buf_u8(swjdp, buffer, count, address);
1430 break;
1431 default:
1432 LOG_ERROR("BUG: we shouldn't get here");
1433 exit(-1);
1434 }
1435
1436 return retval;
1437 }
1438
1439 int cortex_m3_bulk_write_memory(target_t *target, uint32_t address, uint32_t count, uint8_t *buffer)
1440 {
1441 return cortex_m3_write_memory(target, address, 4, count, buffer);
1442 }
1443
1444 void cortex_m3_build_reg_cache(target_t *target)
1445 {
1446 armv7m_build_reg_cache(target);
1447 }
1448
1449 int cortex_m3_init_target(struct command_context_s *cmd_ctx, struct target_s *target)
1450 {
1451 cortex_m3_build_reg_cache(target);
1452 return ERROR_OK;
1453 }
1454
1455 int cortex_m3_examine(struct target_s *target)
1456 {
1457 int retval;
1458 uint32_t cpuid, fpcr, dwtcr, ictr;
1459 int i;
1460
1461 /* get pointers to arch-specific information */
1462 armv7m_common_t *armv7m = target->arch_info;
1463 cortex_m3_common_t *cortex_m3 = armv7m->arch_info;
1464 swjdp_common_t *swjdp = &armv7m->swjdp_info;
1465
1466 if ((retval = ahbap_debugport_init(swjdp)) != ERROR_OK)
1467 return retval;
1468
1469 if (!target_was_examined(target))
1470 {
1471 target_set_examined(target);
1472
1473 /* Read from Device Identification Registers */
1474 if ((retval = target_read_u32(target, CPUID, &cpuid)) != ERROR_OK)
1475 return retval;
1476
1477 if (((cpuid >> 4) & 0xc3f) == 0xc23) {
1478 LOG_DEBUG("CORTEX-M3 processor detected");
1479 if (((cpuid >> 20) & 0xf) >= 2) {
1480 armv7m->has_spec20 = true;
1481 LOG_DEBUG("r2p0 or later detected");
1482 }
1483 } else
1484 LOG_WARNING("not a CORTEX-M3 processor?");
1485 LOG_DEBUG("cpuid: 0x%8.8" PRIx32 "", cpuid);
1486
1487 target_read_u32(target, NVIC_ICTR, &ictr);
1488 cortex_m3->intlinesnum = (ictr & 0x1F) + 1;
1489 cortex_m3->intsetenable = calloc(cortex_m3->intlinesnum, 4);
1490 for (i = 0; i < cortex_m3->intlinesnum; i++)
1491 {
1492 target_read_u32(target, NVIC_ISE0 + 4 * i, cortex_m3->intsetenable + i);
1493 LOG_DEBUG("interrupt enable[%i] = 0x%8.8" PRIx32 "", i, cortex_m3->intsetenable[i]);
1494 }
1495
1496 /* Setup FPB */
1497 target_read_u32(target, FP_CTRL, &fpcr);
1498 cortex_m3->auto_bp_type = 1;
1499 cortex_m3->fp_num_code = ((fpcr >> 8) & 0x70) | ((fpcr >> 4) & 0xF); /* bits [14:12] and [7:4] */
1500 cortex_m3->fp_num_lit = (fpcr >> 8) & 0xF;
1501 cortex_m3->fp_code_available = cortex_m3->fp_num_code;
1502 cortex_m3->fp_comparator_list = calloc(cortex_m3->fp_num_code + cortex_m3->fp_num_lit, sizeof(cortex_m3_fp_comparator_t));
1503 cortex_m3->fpb_enabled = fpcr & 1;
1504 for (i = 0; i < cortex_m3->fp_num_code + cortex_m3->fp_num_lit; i++)
1505 {
1506 cortex_m3->fp_comparator_list[i].type = (i < cortex_m3->fp_num_code) ? FPCR_CODE : FPCR_LITERAL;
1507 cortex_m3->fp_comparator_list[i].fpcr_address = FP_COMP0 + 4 * i;
1508 }
1509 LOG_DEBUG("FPB fpcr 0x%" PRIx32 ", numcode %i, numlit %i", fpcr, cortex_m3->fp_num_code, cortex_m3->fp_num_lit);
1510
1511 /* Setup DWT */
1512 target_read_u32(target, DWT_CTRL, &dwtcr);
1513 cortex_m3->dwt_num_comp = (dwtcr >> 28) & 0xF;
1514 cortex_m3->dwt_comp_available = cortex_m3->dwt_num_comp;
1515 cortex_m3->dwt_comparator_list = calloc(cortex_m3->dwt_num_comp, sizeof(cortex_m3_dwt_comparator_t));
1516 for (i = 0; i < cortex_m3->dwt_num_comp; i++)
1517 {
1518 cortex_m3->dwt_comparator_list[i].dwt_comparator_address = DWT_COMP0 + 0x10 * i;
1519 }
1520 }
1521
1522 return ERROR_OK;
1523 }
1524
1525 int cortex_m3_quit(void)
1526 {
1527
1528 return ERROR_OK;
1529 }
1530
1531 int cortex_m3_dcc_read(swjdp_common_t *swjdp, uint8_t *value, uint8_t *ctrl)
1532 {
1533 uint16_t dcrdr;
1534
1535 mem_ap_read_buf_u16(swjdp, (uint8_t*)&dcrdr, 1, DCB_DCRDR);
1536 *ctrl = (uint8_t)dcrdr;
1537 *value = (uint8_t)(dcrdr >> 8);
1538
1539 LOG_DEBUG("data 0x%x ctrl 0x%x", *value, *ctrl);
1540
1541 /* write ack back to software dcc register
1542 * signify we have read data */
1543 if (dcrdr & (1 << 0))
1544 {
1545 dcrdr = 0;
1546 mem_ap_write_buf_u16(swjdp, (uint8_t*)&dcrdr, 1, DCB_DCRDR);
1547 }
1548
1549 return ERROR_OK;
1550 }
1551
1552 int cortex_m3_target_request_data(target_t *target, uint32_t size, uint8_t *buffer)
1553 {
1554 armv7m_common_t *armv7m = target->arch_info;
1555 swjdp_common_t *swjdp = &armv7m->swjdp_info;
1556 uint8_t data;
1557 uint8_t ctrl;
1558 uint32_t i;
1559
1560 for (i = 0; i < (size * 4); i++)
1561 {
1562 cortex_m3_dcc_read(swjdp, &data, &ctrl);
1563 buffer[i] = data;
1564 }
1565
1566 return ERROR_OK;
1567 }
1568
1569 int cortex_m3_handle_target_request(void *priv)
1570 {
1571 target_t *target = priv;
1572 if (!target_was_examined(target))
1573 return ERROR_OK;
1574 armv7m_common_t *armv7m = target->arch_info;
1575 swjdp_common_t *swjdp = &armv7m->swjdp_info;
1576
1577 if (!target->dbg_msg_enabled)
1578 return ERROR_OK;
1579
1580 if (target->state == TARGET_RUNNING)
1581 {
1582 uint8_t data;
1583 uint8_t ctrl;
1584
1585 cortex_m3_dcc_read(swjdp, &data, &ctrl);
1586
1587 /* check if we have data */
1588 if (ctrl & (1 << 0))
1589 {
1590 uint32_t request;
1591
1592 /* we assume target is quick enough */
1593 request = data;
1594 cortex_m3_dcc_read(swjdp, &data, &ctrl);
1595 request |= (data << 8);
1596 cortex_m3_dcc_read(swjdp, &data, &ctrl);
1597 request |= (data << 16);
1598 cortex_m3_dcc_read(swjdp, &data, &ctrl);
1599 request |= (data << 24);
1600 target_request(target, request);
1601 }
1602 }
1603
1604 return ERROR_OK;
1605 }
1606
1607 int cortex_m3_init_arch_info(target_t *target, cortex_m3_common_t *cortex_m3, jtag_tap_t *tap)
1608 {
1609 int retval;
1610 armv7m_common_t *armv7m;
1611 armv7m = &cortex_m3->armv7m;
1612
1613 armv7m_init_arch_info(target, armv7m);
1614
1615 /* prepare JTAG information for the new target */
1616 cortex_m3->jtag_info.tap = tap;
1617 cortex_m3->jtag_info.scann_size = 4;
1618
1619 armv7m->swjdp_info.dp_select_value = -1;
1620 armv7m->swjdp_info.ap_csw_value = -1;
1621 armv7m->swjdp_info.ap_tar_value = -1;
1622 armv7m->swjdp_info.jtag_info = &cortex_m3->jtag_info;
1623 armv7m->swjdp_info.memaccess_tck = 8;
1624 armv7m->swjdp_info.tar_autoincr_block = (1 << 12); /* Cortex-M3 has 4096 bytes autoincrement range */
1625
1626 /* initialize arch-specific breakpoint handling */
1627
1628 cortex_m3->common_magic = CORTEX_M3_COMMON_MAGIC;
1629 cortex_m3->arch_info = NULL;
1630
1631 /* register arch-specific functions */
1632 armv7m->examine_debug_reason = cortex_m3_examine_debug_reason;
1633
1634 armv7m->pre_debug_entry = NULL;
1635 armv7m->post_debug_entry = NULL;
1636
1637 armv7m->pre_restore_context = NULL;
1638 armv7m->post_restore_context = NULL;
1639
1640 armv7m->arch_info = cortex_m3;
1641 armv7m->load_core_reg_u32 = cortex_m3_load_core_reg_u32;
1642 armv7m->store_core_reg_u32 = cortex_m3_store_core_reg_u32;
1643
1644 target_register_timer_callback(cortex_m3_handle_target_request, 1, 1, target);
1645
1646 if ((retval = arm_jtag_setup_connection(&cortex_m3->jtag_info)) != ERROR_OK)
1647 {
1648 return retval;
1649 }
1650
1651 return ERROR_OK;
1652 }
1653
1654 int cortex_m3_target_create(struct target_s *target, Jim_Interp *interp)
1655 {
1656 cortex_m3_common_t *cortex_m3 = calloc(1,sizeof(cortex_m3_common_t));
1657
1658 cortex_m3_init_arch_info(target, cortex_m3, target->tap);
1659
1660 return ERROR_OK;
1661 }
1662
1663 /*
1664 * REVISIT Thumb2 disassembly should work for all ARMv7 cores, as well
1665 * as at least ARM-1156T2. The interesting thing about Cortex-M is
1666 * that *only* Thumb2 disassembly matters. There are also some small
1667 * additions to Thumb2 that are specific to ARMv7-M.
1668 */
1669 static int
1670 handle_cortex_m3_disassemble_command(struct command_context_s *cmd_ctx,
1671 char *cmd, char **args, int argc)
1672 {
1673 int retval = ERROR_OK;
1674 target_t *target = get_current_target(cmd_ctx);
1675 uint32_t address;
1676 unsigned long count;
1677 arm_instruction_t cur_instruction;
1678
1679 if (argc != 2) {
1680 command_print(cmd_ctx,
1681 "usage: cortex_m3 disassemble <address> <count>");
1682 return ERROR_OK;
1683 }
1684
1685 errno = 0;
1686 address = strtoul(args[0], NULL, 0);
1687 if (errno)
1688 return ERROR_FAIL;
1689 count = strtoul(args[1], NULL, 0);
1690 if (errno)
1691 return ERROR_FAIL;
1692
1693 while (count--) {
1694 retval = thumb2_opcode(target, address, &cur_instruction);
1695 if (retval != ERROR_OK)
1696 return retval;
1697 command_print(cmd_ctx, "%s", cur_instruction.text);
1698 address += cur_instruction.instruction_size;
1699 }
1700
1701 return ERROR_OK;
1702 }
1703
1704 int cortex_m3_register_commands(struct command_context_s *cmd_ctx)
1705 {
1706 int retval;
1707 command_t *cortex_m3_cmd;
1708
1709 retval = armv7m_register_commands(cmd_ctx);
1710
1711 cortex_m3_cmd = register_command(cmd_ctx, NULL, "cortex_m3",
1712 NULL, COMMAND_ANY, "cortex_m3 specific commands");
1713
1714 register_command(cmd_ctx, cortex_m3_cmd, "disassemble",
1715 handle_cortex_m3_disassemble_command, COMMAND_EXEC,
1716 "disassemble Thumb2 instructions <address> <count>");
1717 register_command(cmd_ctx, cortex_m3_cmd, "maskisr",
1718 handle_cortex_m3_mask_interrupts_command, COMMAND_EXEC,
1719 "mask cortex_m3 interrupts ['on'|'off']");
1720
1721 return retval;
1722 }
1723
1724 int handle_cortex_m3_mask_interrupts_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
1725 {
1726 target_t *target = get_current_target(cmd_ctx);
1727 armv7m_common_t *armv7m = target->arch_info;
1728 cortex_m3_common_t *cortex_m3 = armv7m->arch_info;
1729
1730 if (target->state != TARGET_HALTED)
1731 {
1732 command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd);
1733 return ERROR_OK;
1734 }
1735
1736 if (argc > 0)
1737 {
1738 if (!strcmp(args[0], "on"))
1739 {
1740 cortex_m3_write_debug_halt_mask(target, C_HALT | C_MASKINTS, 0);
1741 }
1742 else if (!strcmp(args[0], "off"))
1743 {
1744 cortex_m3_write_debug_halt_mask(target, C_HALT, C_MASKINTS);
1745 }
1746 else
1747 {
1748 command_print(cmd_ctx, "usage: cortex_m3 maskisr ['on'|'off']");
1749 }
1750 }
1751
1752 command_print(cmd_ctx, "cortex_m3 interrupt mask %s",
1753 (cortex_m3->dcb_dhcsr & C_MASKINTS) ? "on" : "off");
1754
1755 return ERROR_OK;
1756 }

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)