stlink: better handle target reset/events
[openocd.git] / src / target / stm32_stlink.c
1 /***************************************************************************
2 * Copyright (C) 2011 by Mathias Kuester *
3 * Mathias Kuester <kesmtp@freenet.de> *
4 * *
5 * Copyright (C) 2011 by Spencer Oliver *
6 * spen@spen-soft.co.uk *
7 * *
8 * This program is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation; either version 2 of the License, or *
11 * (at your option) any later version. *
12 * *
13 * This program is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU General Public License *
19 * along with this program; if not, write to the *
20 * Free Software Foundation, Inc., *
21 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
22 ***************************************************************************/
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include "jtag/jtag.h"
28 #include "jtag/stlink/stlink_interface.h"
29 #include "jtag/stlink/stlink_layout.h"
30 #include "register.h"
31 #include "algorithm.h"
32 #include "target.h"
33 #include "breakpoints.h"
34 #include "target_type.h"
35 #include "armv7m.h"
36 #include "cortex_m.h"
37
38 static inline struct stlink_interface_s *target_to_stlink(struct target *target)
39 {
40 return target->tap->priv;
41 }
42
43 static int stm32_stlink_load_core_reg_u32(struct target *target,
44 enum armv7m_regtype type,
45 uint32_t num, uint32_t *value)
46 {
47 int retval;
48 struct stlink_interface_s *stlink_if = target_to_stlink(target);
49
50 LOG_DEBUG("%s", __func__);
51
52 /* NOTE: we "know" here that the register identifiers used
53 * in the v7m header match the Cortex-M3 Debug Core Register
54 * Selector values for R0..R15, xPSR, MSP, and PSP.
55 */
56 switch (num) {
57 case 0 ... 18:
58 /* read a normal core register */
59 retval =
60 stlink_if->layout->api->read_reg(stlink_if->fd, num, value);
61
62 if (retval != ERROR_OK) {
63 LOG_ERROR("JTAG failure %i", retval);
64 return ERROR_JTAG_DEVICE_ERROR;
65 }
66 LOG_DEBUG("load from core reg %i value 0x%" PRIx32 "",
67 (int)num, *value);
68 break;
69
70 case ARMV7M_PRIMASK:
71 case ARMV7M_BASEPRI:
72 case ARMV7M_FAULTMASK:
73 case ARMV7M_CONTROL:
74 /* Cortex-M3 packages these four registers as bitfields
75 * in one Debug Core register. So say r0 and r2 docs;
76 * it was removed from r1 docs, but still works.
77 */
78 retval =
79 stlink_if->layout->api->read_reg(stlink_if->fd, 20, value);
80
81 switch (num) {
82 case ARMV7M_PRIMASK:
83 *value = buf_get_u32((uint8_t *) value, 0, 1);
84 break;
85
86 case ARMV7M_BASEPRI:
87 *value = buf_get_u32((uint8_t *) value, 8, 8);
88 break;
89
90 case ARMV7M_FAULTMASK:
91 *value = buf_get_u32((uint8_t *) value, 16, 1);
92 break;
93
94 case ARMV7M_CONTROL:
95 *value = buf_get_u32((uint8_t *) value, 24, 2);
96 break;
97 }
98
99 LOG_DEBUG("load from special reg %i value 0x%" PRIx32 "",
100 (int)num, *value);
101 break;
102
103 default:
104 return ERROR_COMMAND_SYNTAX_ERROR;
105 }
106
107 return ERROR_OK;
108 }
109
110 static int stm32_stlink_store_core_reg_u32(struct target *target,
111 enum armv7m_regtype type,
112 uint32_t num, uint32_t value)
113 {
114 int retval;
115 uint32_t reg;
116 struct armv7m_common *armv7m = target_to_armv7m(target);
117 struct stlink_interface_s *stlink_if = target_to_stlink(target);
118
119 LOG_DEBUG("%s", __func__);
120
121 #ifdef ARMV7_GDB_HACKS
122 /* If the LR register is being modified, make sure it will put us
123 * in "thumb" mode, or an INVSTATE exception will occur. This is a
124 * hack to deal with the fact that gdb will sometimes "forge"
125 * return addresses, and doesn't set the LSB correctly (i.e., when
126 * printing expressions containing function calls, it sets LR = 0.)
127 * Valid exception return codes have bit 0 set too.
128 */
129 if (num == ARMV7M_R14)
130 value |= 0x01;
131 #endif
132
133 /* NOTE: we "know" here that the register identifiers used
134 * in the v7m header match the Cortex-M3 Debug Core Register
135 * Selector values for R0..R15, xPSR, MSP, and PSP.
136 */
137 switch (num) {
138 case 0 ... 18:
139 retval = stlink_if->layout->api->write_reg(stlink_if->fd, num, value);
140
141 if (retval != ERROR_OK) {
142 struct reg *r;
143
144 LOG_ERROR("JTAG failure");
145 r = armv7m->core_cache->reg_list + num;
146 r->dirty = r->valid;
147 return ERROR_JTAG_DEVICE_ERROR;
148 }
149 LOG_DEBUG("write core reg %i value 0x%" PRIx32 "", (int)num, value);
150 break;
151
152 case ARMV7M_PRIMASK:
153 case ARMV7M_BASEPRI:
154 case ARMV7M_FAULTMASK:
155 case ARMV7M_CONTROL:
156 /* Cortex-M3 packages these four registers as bitfields
157 * in one Debug Core register. So say r0 and r2 docs;
158 * it was removed from r1 docs, but still works.
159 */
160
161 stlink_if->layout->api->read_reg(stlink_if->fd, 20, &reg);
162
163 switch (num) {
164 case ARMV7M_PRIMASK:
165 buf_set_u32((uint8_t *) &reg, 0, 1, value);
166 break;
167
168 case ARMV7M_BASEPRI:
169 buf_set_u32((uint8_t *) &reg, 8, 8, value);
170 break;
171
172 case ARMV7M_FAULTMASK:
173 buf_set_u32((uint8_t *) &reg, 16, 1, value);
174 break;
175
176 case ARMV7M_CONTROL:
177 buf_set_u32((uint8_t *) &reg, 24, 2, value);
178 break;
179 }
180
181 stlink_if->layout->api->write_reg(stlink_if->fd, 20, reg);
182
183 LOG_DEBUG("write special reg %i value 0x%" PRIx32 " ", (int)num, value);
184 break;
185
186 default:
187 return ERROR_COMMAND_SYNTAX_ERROR;
188 }
189
190 return ERROR_OK;
191 }
192
193 static int stm32_stlink_examine_debug_reason(struct target *target)
194 {
195 if ((target->debug_reason != DBG_REASON_DBGRQ)
196 && (target->debug_reason != DBG_REASON_SINGLESTEP)) {
197 target->debug_reason = DBG_REASON_BREAKPOINT;
198 }
199
200 return ERROR_OK;
201 }
202
203 static int stm32_stlink_init_arch_info(struct target *target,
204 struct cortex_m3_common *cortex_m3,
205 struct jtag_tap *tap)
206 {
207 struct armv7m_common *armv7m;
208
209 LOG_DEBUG("%s", __func__);
210
211 armv7m = &cortex_m3->armv7m;
212 armv7m_init_arch_info(target, armv7m);
213
214 armv7m->load_core_reg_u32 = stm32_stlink_load_core_reg_u32;
215 armv7m->store_core_reg_u32 = stm32_stlink_store_core_reg_u32;
216
217 armv7m->examine_debug_reason = stm32_stlink_examine_debug_reason;
218
219 return ERROR_OK;
220 }
221
222 static int stm32_stlink_init_target(struct command_context *cmd_ctx,
223 struct target *target)
224 {
225 LOG_DEBUG("%s", __func__);
226
227 armv7m_build_reg_cache(target);
228
229 return ERROR_OK;
230 }
231
232 static int stm32_stlink_target_create(struct target *target,
233 Jim_Interp *interp)
234 {
235 LOG_DEBUG("%s", __func__);
236
237 struct cortex_m3_common *cortex_m3 = calloc(1, sizeof(struct cortex_m3_common));
238
239 if (!cortex_m3)
240 return ERROR_COMMAND_SYNTAX_ERROR;
241
242 stm32_stlink_init_arch_info(target, cortex_m3, target->tap);
243
244 return ERROR_OK;
245 }
246
247 static int stm32_stlink_examine(struct target *target)
248 {
249 int retval, i;
250 uint32_t cpuid, fpcr;
251 struct cortex_m3_common *cortex_m3 = target_to_cm3(target);
252
253 LOG_DEBUG("%s", __func__);
254
255 if (target->tap->hasidcode == false) {
256 LOG_ERROR("no IDCODE present on device");
257
258 return ERROR_COMMAND_SYNTAX_ERROR;
259 }
260
261 if (!target_was_examined(target)) {
262 target_set_examined(target);
263
264 LOG_INFO("IDCODE %x", target->tap->idcode);
265
266 /* Read from Device Identification Registers */
267 retval = target_read_u32(target, CPUID, &cpuid);
268 if (retval != ERROR_OK)
269 return retval;
270
271 if (((cpuid >> 4) & 0xc3f) == 0xc23)
272 LOG_DEBUG("Cortex-M3 r%" PRId8 "p%" PRId8 " processor detected",
273 (uint8_t)((cpuid >> 20) & 0xf), (uint8_t)((cpuid >> 0) & 0xf));
274 LOG_DEBUG("cpuid: 0x%8.8" PRIx32 "", cpuid);
275
276 /* Setup FPB */
277 target_read_u32(target, FP_CTRL, &fpcr);
278 cortex_m3->auto_bp_type = 1;
279 cortex_m3->fp_num_code = ((fpcr >> 8) & 0x70) |
280 ((fpcr >> 4) & 0xF); /* bits [14:12] and [7:4] */
281 cortex_m3->fp_num_lit = (fpcr >> 8) & 0xF;
282 cortex_m3->fp_code_available = cortex_m3->fp_num_code;
283 cortex_m3->fp_comparator_list = calloc(cortex_m3->fp_num_code +
284 cortex_m3->fp_num_lit, sizeof(struct cortex_m3_fp_comparator));
285 cortex_m3->fpb_enabled = fpcr & 1;
286 for (i = 0; i < cortex_m3->fp_num_code + cortex_m3->fp_num_lit; i++) {
287 cortex_m3->fp_comparator_list[i].type =
288 (i < cortex_m3->fp_num_code) ? FPCR_CODE : FPCR_LITERAL;
289 cortex_m3->fp_comparator_list[i].fpcr_address = FP_COMP0 + 4 * i;
290 }
291 LOG_DEBUG("FPB fpcr 0x%" PRIx32 ", numcode %i, numlit %i", fpcr,
292 cortex_m3->fp_num_code, cortex_m3->fp_num_lit);
293
294 /* Setup DWT */
295 cortex_m3_dwt_setup(cortex_m3, target);
296
297 /* These hardware breakpoints only work for code in flash! */
298 LOG_INFO("%s: hardware has %d breakpoints, %d watchpoints",
299 target_name(target),
300 cortex_m3->fp_num_code,
301 cortex_m3->dwt_num_comp);
302 }
303
304 return ERROR_OK;
305 }
306
307 static int stm32_stlink_load_context(struct target *target)
308 {
309 struct armv7m_common *armv7m = target_to_armv7m(target);
310 int num_regs = armv7m->core_cache->num_regs;
311
312 for (int i = 0; i < num_regs; i++) {
313 if (!armv7m->core_cache->reg_list[i].valid)
314 armv7m->read_core_reg(target, i);
315 }
316
317 return ERROR_OK;
318 }
319
320 static int stlink_debug_entry(struct target *target)
321 {
322 struct armv7m_common *armv7m = target_to_armv7m(target);
323 struct arm *arm = &armv7m->arm;
324 struct reg *r;
325 uint32_t xPSR;
326 int retval;
327
328 retval = armv7m->examine_debug_reason(target);
329 if (retval != ERROR_OK)
330 return retval;
331
332 stm32_stlink_load_context(target);
333
334 r = armv7m->core_cache->reg_list + ARMV7M_xPSR;
335 xPSR = buf_get_u32(r->value, 0, 32);
336
337 /* Are we in an exception handler */
338 if (xPSR & 0x1FF) {
339 armv7m->core_mode = ARMV7M_MODE_HANDLER;
340 armv7m->exception_number = (xPSR & 0x1FF);
341
342 arm->core_mode = ARM_MODE_HANDLER;
343 arm->map = armv7m_msp_reg_map;
344 } else {
345 unsigned control = buf_get_u32(armv7m->core_cache
346 ->reg_list[ARMV7M_CONTROL].value, 0, 2);
347
348 /* is this thread privileged? */
349 armv7m->core_mode = control & 1;
350 arm->core_mode = armv7m->core_mode
351 ? ARM_MODE_USER_THREAD
352 : ARM_MODE_THREAD;
353
354 /* which stack is it using? */
355 if (control & 2)
356 arm->map = armv7m_psp_reg_map;
357 else
358 arm->map = armv7m_msp_reg_map;
359
360 armv7m->exception_number = 0;
361 }
362
363 LOG_DEBUG("entered debug state in core mode: %s at PC 0x%" PRIx32 ", target->state: %s",
364 armv7m_mode_strings[armv7m->core_mode],
365 *(uint32_t *)(arm->pc->value),
366 target_state_name(target));
367
368 return retval;
369 }
370
371 static int stm32_stlink_poll(struct target *target)
372 {
373 enum target_state state;
374 struct stlink_interface_s *stlink_if = target_to_stlink(target);
375 struct armv7m_common *armv7m = target_to_armv7m(target);
376
377 state = stlink_if->layout->api->state(stlink_if->fd);
378
379 if (state == TARGET_UNKNOWN) {
380 LOG_ERROR("jtag status contains invalid mode value - communication failure");
381 return ERROR_TARGET_FAILURE;
382 }
383
384 if (target->state == state)
385 return ERROR_OK;
386
387 if (state == TARGET_HALTED) {
388 target->state = state;
389
390 stlink_debug_entry(target);
391
392 target_call_event_callbacks(target, TARGET_EVENT_HALTED);
393 LOG_DEBUG("halted: PC: 0x%x", buf_get_u32(armv7m->arm.pc->value, 0, 32));
394 }
395
396 return ERROR_OK;
397 }
398
399 static int stm32_stlink_assert_reset(struct target *target)
400 {
401 int res;
402 struct stlink_interface_s *stlink_if = target_to_stlink(target);
403 struct armv7m_common *armv7m = target_to_armv7m(target);
404
405 LOG_DEBUG("%s", __func__);
406
407 res = stlink_if->layout->api->reset(stlink_if->fd);
408
409 if (res != ERROR_OK)
410 return res;
411
412 /* virtual assert reset, we need it for the internal
413 * jtag state machine
414 */
415 jtag_add_reset(1, 1);
416
417 /* registers are now invalid */
418 register_cache_invalidate(armv7m->core_cache);
419
420 if (target->reset_halt) {
421 target->state = TARGET_RESET;
422 target->debug_reason = DBG_REASON_DBGRQ;
423 } else {
424 target->state = TARGET_HALTED;
425 }
426
427 return ERROR_OK;
428 }
429
430 static int stm32_stlink_deassert_reset(struct target *target)
431 {
432 int res;
433
434 LOG_DEBUG("%s", __func__);
435
436 /* virtual deassert reset, we need it for the internal
437 * jtag state machine
438 */
439 jtag_add_reset(0, 0);
440
441 if (!target->reset_halt) {
442 res = target_resume(target, 1, 0, 0, 0);
443
444 if (res != ERROR_OK)
445 return res;
446 }
447
448 return ERROR_OK;
449 }
450
451 static int stm32_stlink_soft_reset_halt(struct target *target)
452 {
453 LOG_DEBUG("%s", __func__);
454 return ERROR_OK;
455 }
456
457 static int stm32_stlink_halt(struct target *target)
458 {
459 int res;
460 struct stlink_interface_s *stlink_if = target_to_stlink(target);
461
462 LOG_DEBUG("%s", __func__);
463
464 if (target->state == TARGET_HALTED) {
465 LOG_DEBUG("target was already halted");
466 return ERROR_OK;
467 }
468
469 if (target->state == TARGET_UNKNOWN) {
470 LOG_WARNING
471 ("target was in unknown state when halt was requested");
472 }
473
474 res = stlink_if->layout->api->halt(stlink_if->fd);
475
476 if (res != ERROR_OK)
477 return res;
478
479 target->debug_reason = DBG_REASON_DBGRQ;
480
481 return ERROR_OK;
482 }
483
484 static int stm32_stlink_resume(struct target *target, int current,
485 uint32_t address, int handle_breakpoints,
486 int debug_execution)
487 {
488 int res;
489 struct stlink_interface_s *stlink_if = target_to_stlink(target);
490 struct armv7m_common *armv7m = target_to_armv7m(target);
491 uint32_t resume_pc;
492 struct breakpoint *breakpoint = NULL;
493 struct reg *pc;
494
495 LOG_DEBUG("%s %d %x %d %d", __func__, current, address,
496 handle_breakpoints, debug_execution);
497
498 if (target->state != TARGET_HALTED) {
499 LOG_WARNING("target not halted");
500 return ERROR_TARGET_NOT_HALTED;
501 }
502
503 pc = armv7m->arm.pc;
504 if (!current) {
505 buf_set_u32(pc->value, 0, 32, address);
506 pc->dirty = true;
507 pc->valid = true;
508 }
509
510 if (!breakpoint_find(target, buf_get_u32(pc->value, 0, 32))
511 && !debug_execution) {
512 armv7m_maybe_skip_bkpt_inst(target, NULL);
513 }
514
515 resume_pc = buf_get_u32(pc->value, 0, 32);
516
517 armv7m_restore_context(target);
518
519 /* registers are now invalid */
520 register_cache_invalidate(armv7m->core_cache);
521
522 /* the front-end may request us not to handle breakpoints */
523 if (handle_breakpoints) {
524 /* Single step past breakpoint at current address */
525 breakpoint = breakpoint_find(target, resume_pc);
526 if (breakpoint) {
527 LOG_DEBUG("unset breakpoint at 0x%8.8" PRIx32 " (ID: %d)",
528 breakpoint->address,
529 breakpoint->unique_id);
530 cortex_m3_unset_breakpoint(target, breakpoint);
531
532 res = stlink_if->layout->api->step(stlink_if->fd);
533
534 if (res != ERROR_OK)
535 return res;
536
537 cortex_m3_set_breakpoint(target, breakpoint);
538 }
539 }
540
541 res = stlink_if->layout->api->run(stlink_if->fd);
542
543 if (res != ERROR_OK)
544 return res;
545
546 target->state = TARGET_RUNNING;
547
548 target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
549
550 return ERROR_OK;
551 }
552
553 static int stm32_stlink_step(struct target *target, int current,
554 uint32_t address, int handle_breakpoints)
555 {
556 int res;
557 struct stlink_interface_s *stlink_if = target_to_stlink(target);
558 struct armv7m_common *armv7m = target_to_armv7m(target);
559 struct breakpoint *breakpoint = NULL;
560 struct reg *pc = armv7m->arm.pc;
561 bool bkpt_inst_found = false;
562
563 LOG_DEBUG("%s", __func__);
564
565 if (target->state != TARGET_HALTED) {
566 LOG_WARNING("target not halted");
567 return ERROR_TARGET_NOT_HALTED;
568 }
569
570 if (!current) {
571 buf_set_u32(pc->value, 0, 32, address);
572 pc->dirty = true;
573 pc->valid = true;
574 }
575
576 uint32_t pc_value = buf_get_u32(pc->value, 0, 32);
577
578 /* the front-end may request us not to handle breakpoints */
579 if (handle_breakpoints) {
580 breakpoint = breakpoint_find(target, pc_value);
581 if (breakpoint)
582 cortex_m3_unset_breakpoint(target, breakpoint);
583 }
584
585 armv7m_maybe_skip_bkpt_inst(target, &bkpt_inst_found);
586
587 target->debug_reason = DBG_REASON_SINGLESTEP;
588
589 armv7m_restore_context(target);
590
591 target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
592
593 res = stlink_if->layout->api->step(stlink_if->fd);
594
595 if (res != ERROR_OK)
596 return res;
597
598 /* registers are now invalid */
599 register_cache_invalidate(armv7m->core_cache);
600
601 if (breakpoint)
602 cortex_m3_set_breakpoint(target, breakpoint);
603
604 target->debug_reason = DBG_REASON_SINGLESTEP;
605 target_call_event_callbacks(target, TARGET_EVENT_HALTED);
606
607 stlink_debug_entry(target);
608
609 LOG_INFO("halted: PC: 0x%x", buf_get_u32(armv7m->arm.pc->value, 0, 32));
610
611 return ERROR_OK;
612 }
613
614 static int stm32_stlink_read_memory(struct target *target, uint32_t address,
615 uint32_t size, uint32_t count,
616 uint8_t *buffer)
617 {
618 int res;
619 uint32_t buffer_threshold = 128;
620 uint32_t addr_increment = 4;
621 uint8_t *dst = buffer;
622 uint32_t c;
623 struct stlink_interface_s *stlink_if = target_to_stlink(target);
624
625 if (!count || !buffer)
626 return ERROR_COMMAND_SYNTAX_ERROR;
627
628 LOG_DEBUG("%s %x %d %d", __func__, address, size, count);
629
630 /* prepare byte count, buffer threshold
631 * and address increment for none 32bit access
632 */
633 if (size != 4) {
634 count *= size;
635 buffer_threshold = 64;
636 addr_increment = 1;
637 }
638
639 while (count) {
640 if (count > buffer_threshold)
641 c = buffer_threshold;
642 else
643 c = count;
644
645 if (size != 4)
646 res =
647 stlink_if->layout->api->read_mem8(stlink_if->fd, address,
648 c, dst);
649 else
650 res =
651 stlink_if->layout->api->read_mem32(stlink_if->fd, address,
652 c, (uint32_t *)dst);
653
654 if (res != ERROR_OK)
655 return res;
656
657 address += (c * addr_increment);
658 dst += (c * addr_increment);
659 count -= c;
660 }
661
662 return ERROR_OK;
663 }
664
665 static int stm32_stlink_write_memory(struct target *target, uint32_t address,
666 uint32_t size, uint32_t count,
667 const uint8_t *buffer)
668 {
669 int res;
670 uint32_t buffer_threshold = 128;
671 uint32_t addr_increment = 4;
672 const uint8_t *dst = buffer;
673 uint32_t c;
674 struct stlink_interface_s *stlink_if = target_to_stlink(target);
675
676 if (!count || !buffer)
677 return ERROR_COMMAND_SYNTAX_ERROR;
678
679 LOG_DEBUG("%s %x %d %d", __func__, address, size, count);
680
681 /* prepare byte count, buffer threshold
682 * and address increment for none 32bit access
683 */
684 if (size != 4) {
685 count *= size;
686 buffer_threshold = 64;
687 addr_increment = 1;
688 }
689
690 while (count) {
691 if (count > buffer_threshold)
692 c = buffer_threshold;
693 else
694 c = count;
695
696 if (size != 4)
697 res =
698 stlink_if->layout->api->write_mem8(stlink_if->fd, address,
699 c, dst);
700 else
701 res =
702 stlink_if->layout->api->write_mem32(stlink_if->fd, address,
703 c, (uint32_t *)dst);
704
705 if (res != ERROR_OK)
706 return res;
707
708 address += (c * addr_increment);
709 dst += (c * addr_increment);
710 count -= c;
711 }
712
713 return ERROR_OK;
714 }
715
716 static int stm32_stlink_bulk_write_memory(struct target *target,
717 uint32_t address, uint32_t count,
718 const uint8_t *buffer)
719 {
720 return stm32_stlink_write_memory(target, address, 4, count, buffer);
721 }
722
723 struct target_type stm32_stlink_target = {
724 .name = "stm32_stlink",
725
726 .init_target = stm32_stlink_init_target,
727 .target_create = stm32_stlink_target_create,
728 .examine = stm32_stlink_examine,
729
730 .poll = stm32_stlink_poll,
731 .arch_state = armv7m_arch_state,
732
733 .assert_reset = stm32_stlink_assert_reset,
734 .deassert_reset = stm32_stlink_deassert_reset,
735 .soft_reset_halt = stm32_stlink_soft_reset_halt,
736
737 .halt = stm32_stlink_halt,
738 .resume = stm32_stlink_resume,
739 .step = stm32_stlink_step,
740
741 .get_gdb_reg_list = armv7m_get_gdb_reg_list,
742
743 .read_memory = stm32_stlink_read_memory,
744 .write_memory = stm32_stlink_write_memory,
745 .bulk_write_memory = stm32_stlink_bulk_write_memory,
746
747 .run_algorithm = armv7m_run_algorithm,
748 .start_algorithm = armv7m_start_algorithm,
749 .wait_algorithm = armv7m_wait_algorithm,
750
751 .add_breakpoint = cortex_m3_add_breakpoint,
752 .remove_breakpoint = cortex_m3_remove_breakpoint,
753 .add_watchpoint = cortex_m3_add_watchpoint,
754 .remove_watchpoint = cortex_m3_remove_watchpoint,
755 };

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)