jtag: linuxgpiod: drop extra parenthesis
[openocd.git] / src / target / mips32.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2
3 /***************************************************************************
4 * Copyright (C) 2008 by Spencer Oliver *
5 * spen@spen-soft.co.uk *
6 * *
7 * Copyright (C) 2008 by David T.L. Wong *
8 * *
9 * Copyright (C) 2007,2008 Øyvind Harboe *
10 * oyvind.harboe@zylin.com *
11 * *
12 * Copyright (C) 2011 by Drasko DRASKOVIC *
13 * drasko.draskovic@gmail.com *
14 ***************************************************************************/
15
16 #ifdef HAVE_CONFIG_H
17 #include "config.h"
18 #endif
19
20 #include "mips32.h"
21 #include "breakpoints.h"
22 #include "algorithm.h"
23 #include "register.h"
24
25 static const char *mips_isa_strings[] = {
26 "MIPS32", "MIPS16", "", "MICRO MIPS32",
27 };
28
29 #define MIPS32_GDB_DUMMY_FP_REG 1
30
31 /*
32 * GDB registers
33 * based on gdb-7.6.2/gdb/features/mips-{fpu,cp0,cpu}.xml
34 */
35 static const struct {
36 unsigned id;
37 const char *name;
38 enum reg_type type;
39 const char *group;
40 const char *feature;
41 int flag;
42 } mips32_regs[] = {
43 { 0, "r0", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 },
44 { 1, "r1", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 },
45 { 2, "r2", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 },
46 { 3, "r3", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 },
47 { 4, "r4", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 },
48 { 5, "r5", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 },
49 { 6, "r6", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 },
50 { 7, "r7", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 },
51 { 8, "r8", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 },
52 { 9, "r9", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 },
53 { 10, "r10", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 },
54 { 11, "r11", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 },
55 { 12, "r12", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 },
56 { 13, "r13", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 },
57 { 14, "r14", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 },
58 { 15, "r15", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 },
59 { 16, "r16", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 },
60 { 17, "r17", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 },
61 { 18, "r18", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 },
62 { 19, "r19", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 },
63 { 20, "r20", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 },
64 { 21, "r21", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 },
65 { 22, "r22", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 },
66 { 23, "r23", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 },
67 { 24, "r24", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 },
68 { 25, "r25", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 },
69 { 26, "r26", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 },
70 { 27, "r27", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 },
71 { 28, "r28", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 },
72 { 29, "r29", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 },
73 { 30, "r30", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 },
74 { 31, "r31", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 },
75 { 32, "status", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cp0", 0 },
76 { 33, "lo", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 },
77 { 34, "hi", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 },
78 { 35, "badvaddr", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cp0", 0 },
79 { 36, "cause", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cp0", 0 },
80 { 37, "pc", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 },
81
82 { 38, "f0", REG_TYPE_IEEE_SINGLE, NULL,
83 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG },
84 { 39, "f1", REG_TYPE_IEEE_SINGLE, NULL,
85 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG },
86 { 40, "f2", REG_TYPE_IEEE_SINGLE, NULL,
87 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG },
88 { 41, "f3", REG_TYPE_IEEE_SINGLE, NULL,
89 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG },
90 { 42, "f4", REG_TYPE_IEEE_SINGLE, NULL,
91 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG },
92 { 43, "f5", REG_TYPE_IEEE_SINGLE, NULL,
93 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG },
94 { 44, "f6", REG_TYPE_IEEE_SINGLE, NULL,
95 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG },
96 { 45, "f7", REG_TYPE_IEEE_SINGLE, NULL,
97 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG },
98 { 46, "f8", REG_TYPE_IEEE_SINGLE, NULL,
99 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG },
100 { 47, "f9", REG_TYPE_IEEE_SINGLE, NULL,
101 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG },
102 { 48, "f10", REG_TYPE_IEEE_SINGLE, NULL,
103 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG },
104 { 49, "f11", REG_TYPE_IEEE_SINGLE, NULL,
105 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG },
106 { 50, "f12", REG_TYPE_IEEE_SINGLE, NULL,
107 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG },
108 { 51, "f13", REG_TYPE_IEEE_SINGLE, NULL,
109 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG },
110 { 52, "f14", REG_TYPE_IEEE_SINGLE, NULL,
111 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG },
112 { 53, "f15", REG_TYPE_IEEE_SINGLE, NULL,
113 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG },
114 { 54, "f16", REG_TYPE_IEEE_SINGLE, NULL,
115 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG },
116 { 55, "f17", REG_TYPE_IEEE_SINGLE, NULL,
117 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG },
118 { 56, "f18", REG_TYPE_IEEE_SINGLE, NULL,
119 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG },
120 { 57, "f19", REG_TYPE_IEEE_SINGLE, NULL,
121 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG },
122 { 58, "f20", REG_TYPE_IEEE_SINGLE, NULL,
123 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG },
124 { 59, "f21", REG_TYPE_IEEE_SINGLE, NULL,
125 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG },
126 { 60, "f22", REG_TYPE_IEEE_SINGLE, NULL,
127 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG },
128 { 61, "f23", REG_TYPE_IEEE_SINGLE, NULL,
129 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG },
130 { 62, "f24", REG_TYPE_IEEE_SINGLE, NULL,
131 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG },
132 { 63, "f25", REG_TYPE_IEEE_SINGLE, NULL,
133 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG },
134 { 64, "f26", REG_TYPE_IEEE_SINGLE, NULL,
135 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG },
136 { 65, "f27", REG_TYPE_IEEE_SINGLE, NULL,
137 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG },
138 { 66, "f28", REG_TYPE_IEEE_SINGLE, NULL,
139 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG },
140 { 67, "f29", REG_TYPE_IEEE_SINGLE, NULL,
141 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG },
142 { 68, "f30", REG_TYPE_IEEE_SINGLE, NULL,
143 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG },
144 { 69, "f31", REG_TYPE_IEEE_SINGLE, NULL,
145 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG },
146 { 70, "fcsr", REG_TYPE_INT, "float",
147 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG },
148 { 71, "fir", REG_TYPE_INT, "float",
149 "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG },
150 };
151
152
153 #define MIPS32_NUM_REGS ARRAY_SIZE(mips32_regs)
154
155 static uint8_t mips32_gdb_dummy_fp_value[] = {0, 0, 0, 0};
156
157 static int mips32_get_core_reg(struct reg *reg)
158 {
159 int retval;
160 struct mips32_core_reg *mips32_reg = reg->arch_info;
161 struct target *target = mips32_reg->target;
162 struct mips32_common *mips32_target = target_to_mips32(target);
163
164 if (target->state != TARGET_HALTED)
165 return ERROR_TARGET_NOT_HALTED;
166
167 retval = mips32_target->read_core_reg(target, mips32_reg->num);
168
169 return retval;
170 }
171
172 static int mips32_set_core_reg(struct reg *reg, uint8_t *buf)
173 {
174 struct mips32_core_reg *mips32_reg = reg->arch_info;
175 struct target *target = mips32_reg->target;
176 uint32_t value = buf_get_u32(buf, 0, 32);
177
178 if (target->state != TARGET_HALTED)
179 return ERROR_TARGET_NOT_HALTED;
180
181 buf_set_u32(reg->value, 0, 32, value);
182 reg->dirty = true;
183 reg->valid = true;
184
185 return ERROR_OK;
186 }
187
188 static int mips32_read_core_reg(struct target *target, unsigned int num)
189 {
190 uint32_t reg_value;
191
192 /* get pointers to arch-specific information */
193 struct mips32_common *mips32 = target_to_mips32(target);
194
195 if (num >= MIPS32_NUM_REGS)
196 return ERROR_COMMAND_SYNTAX_ERROR;
197
198 reg_value = mips32->core_regs[num];
199 buf_set_u32(mips32->core_cache->reg_list[num].value, 0, 32, reg_value);
200 mips32->core_cache->reg_list[num].valid = true;
201 mips32->core_cache->reg_list[num].dirty = false;
202
203 return ERROR_OK;
204 }
205
206 static int mips32_write_core_reg(struct target *target, unsigned int num)
207 {
208 uint32_t reg_value;
209
210 /* get pointers to arch-specific information */
211 struct mips32_common *mips32 = target_to_mips32(target);
212
213 if (num >= MIPS32_NUM_REGS)
214 return ERROR_COMMAND_SYNTAX_ERROR;
215
216 reg_value = buf_get_u32(mips32->core_cache->reg_list[num].value, 0, 32);
217 mips32->core_regs[num] = reg_value;
218 LOG_DEBUG("write core reg %i value 0x%" PRIx32 "", num, reg_value);
219 mips32->core_cache->reg_list[num].valid = true;
220 mips32->core_cache->reg_list[num].dirty = false;
221
222 return ERROR_OK;
223 }
224
225 int mips32_get_gdb_reg_list(struct target *target, struct reg **reg_list[],
226 int *reg_list_size, enum target_register_class reg_class)
227 {
228 /* get pointers to arch-specific information */
229 struct mips32_common *mips32 = target_to_mips32(target);
230 unsigned int i;
231
232 /* include floating point registers */
233 *reg_list_size = MIPS32_NUM_REGS;
234 *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size));
235
236 for (i = 0; i < MIPS32_NUM_REGS; i++)
237 (*reg_list)[i] = &mips32->core_cache->reg_list[i];
238
239 return ERROR_OK;
240 }
241
242 int mips32_save_context(struct target *target)
243 {
244 unsigned int i;
245
246 /* get pointers to arch-specific information */
247 struct mips32_common *mips32 = target_to_mips32(target);
248 struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
249
250 /* read core registers */
251 mips32_pracc_read_regs(ejtag_info, mips32->core_regs);
252
253 for (i = 0; i < MIPS32_NUM_REGS; i++) {
254 if (!mips32->core_cache->reg_list[i].valid)
255 mips32->read_core_reg(target, i);
256 }
257
258 return ERROR_OK;
259 }
260
261 int mips32_restore_context(struct target *target)
262 {
263 unsigned int i;
264
265 /* get pointers to arch-specific information */
266 struct mips32_common *mips32 = target_to_mips32(target);
267 struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
268
269 for (i = 0; i < MIPS32_NUM_REGS; i++) {
270 if (mips32->core_cache->reg_list[i].dirty)
271 mips32->write_core_reg(target, i);
272 }
273
274 /* write core regs */
275 mips32_pracc_write_regs(ejtag_info, mips32->core_regs);
276
277 return ERROR_OK;
278 }
279
280 int mips32_arch_state(struct target *target)
281 {
282 struct mips32_common *mips32 = target_to_mips32(target);
283
284 LOG_USER("target halted in %s mode due to %s, pc: 0x%8.8" PRIx32 "",
285 mips_isa_strings[mips32->isa_mode],
286 debug_reason_name(target),
287 buf_get_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 32));
288
289 return ERROR_OK;
290 }
291
292 static const struct reg_arch_type mips32_reg_type = {
293 .get = mips32_get_core_reg,
294 .set = mips32_set_core_reg,
295 };
296
297 struct reg_cache *mips32_build_reg_cache(struct target *target)
298 {
299 /* get pointers to arch-specific information */
300 struct mips32_common *mips32 = target_to_mips32(target);
301
302 int num_regs = MIPS32_NUM_REGS;
303 struct reg_cache **cache_p = register_get_last_cache_p(&target->reg_cache);
304 struct reg_cache *cache = malloc(sizeof(struct reg_cache));
305 struct reg *reg_list = calloc(num_regs, sizeof(struct reg));
306 struct mips32_core_reg *arch_info = malloc(sizeof(struct mips32_core_reg) * num_regs);
307 struct reg_feature *feature;
308 int i;
309
310 /* Build the process context cache */
311 cache->name = "mips32 registers";
312 cache->next = NULL;
313 cache->reg_list = reg_list;
314 cache->num_regs = num_regs;
315 (*cache_p) = cache;
316 mips32->core_cache = cache;
317
318 for (i = 0; i < num_regs; i++) {
319 arch_info[i].num = mips32_regs[i].id;
320 arch_info[i].target = target;
321 arch_info[i].mips32_common = mips32;
322
323 reg_list[i].name = mips32_regs[i].name;
324 reg_list[i].size = 32;
325
326 if (mips32_regs[i].flag == MIPS32_GDB_DUMMY_FP_REG) {
327 reg_list[i].value = mips32_gdb_dummy_fp_value;
328 reg_list[i].valid = true;
329 reg_list[i].arch_info = NULL;
330 register_init_dummy(&reg_list[i]);
331 } else {
332 reg_list[i].value = calloc(1, 4);
333 reg_list[i].valid = false;
334 reg_list[i].type = &mips32_reg_type;
335 reg_list[i].arch_info = &arch_info[i];
336
337 reg_list[i].reg_data_type = calloc(1, sizeof(struct reg_data_type));
338 if (reg_list[i].reg_data_type)
339 reg_list[i].reg_data_type->type = mips32_regs[i].type;
340 else
341 LOG_ERROR("unable to allocate reg type list");
342 }
343
344 reg_list[i].dirty = false;
345
346 reg_list[i].group = mips32_regs[i].group;
347 reg_list[i].number = i;
348 reg_list[i].exist = true;
349 reg_list[i].caller_save = true; /* gdb defaults to true */
350
351 feature = calloc(1, sizeof(struct reg_feature));
352 if (feature) {
353 feature->name = mips32_regs[i].feature;
354 reg_list[i].feature = feature;
355 } else
356 LOG_ERROR("unable to allocate feature list");
357 }
358
359 return cache;
360 }
361
362 int mips32_init_arch_info(struct target *target, struct mips32_common *mips32, struct jtag_tap *tap)
363 {
364 target->arch_info = mips32;
365 mips32->common_magic = MIPS32_COMMON_MAGIC;
366 mips32->fast_data_area = NULL;
367 mips32->isa_imp = MIPS32_ONLY; /* default */
368
369 /* has breakpoint/watchpoint unit been scanned */
370 mips32->bp_scanned = 0;
371 mips32->data_break_list = NULL;
372
373 mips32->ejtag_info.tap = tap;
374 mips32->read_core_reg = mips32_read_core_reg;
375 mips32->write_core_reg = mips32_write_core_reg;
376 /* if unknown endianness defaults to little endian, 1 */
377 mips32->ejtag_info.endianness = target->endianness == TARGET_BIG_ENDIAN ? 0 : 1;
378 mips32->ejtag_info.scan_delay = MIPS32_SCAN_DELAY_LEGACY_MODE;
379 mips32->ejtag_info.mode = 0; /* Initial default value */
380 mips32->ejtag_info.isa = 0; /* isa on debug mips32, updated by poll function */
381 mips32->ejtag_info.config_regs = 0; /* no config register read */
382 return ERROR_OK;
383 }
384
385 /* run to exit point. return error if exit point was not reached. */
386 static int mips32_run_and_wait(struct target *target, target_addr_t entry_point,
387 int timeout_ms, target_addr_t exit_point, struct mips32_common *mips32)
388 {
389 uint32_t pc;
390 int retval;
391 /* This code relies on the target specific resume() and poll()->debug_entry()
392 * sequence to write register values to the processor and the read them back */
393 retval = target_resume(target, 0, entry_point, 0, 1);
394 if (retval != ERROR_OK)
395 return retval;
396
397 retval = target_wait_state(target, TARGET_HALTED, timeout_ms);
398 /* If the target fails to halt due to the breakpoint, force a halt */
399 if (retval != ERROR_OK || target->state != TARGET_HALTED) {
400 retval = target_halt(target);
401 if (retval != ERROR_OK)
402 return retval;
403 retval = target_wait_state(target, TARGET_HALTED, 500);
404 if (retval != ERROR_OK)
405 return retval;
406 return ERROR_TARGET_TIMEOUT;
407 }
408
409 pc = buf_get_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 32);
410 if (exit_point && (pc != exit_point)) {
411 LOG_DEBUG("failed algorithm halted at 0x%" PRIx32 " ", pc);
412 return ERROR_TARGET_TIMEOUT;
413 }
414
415 return ERROR_OK;
416 }
417
418 int mips32_run_algorithm(struct target *target, int num_mem_params,
419 struct mem_param *mem_params, int num_reg_params,
420 struct reg_param *reg_params, target_addr_t entry_point,
421 target_addr_t exit_point, int timeout_ms, void *arch_info)
422 {
423 struct mips32_common *mips32 = target_to_mips32(target);
424 struct mips32_algorithm *mips32_algorithm_info = arch_info;
425 enum mips32_isa_mode isa_mode = mips32->isa_mode;
426
427 uint32_t context[MIPS32_NUM_REGS];
428 int retval = ERROR_OK;
429
430 LOG_DEBUG("Running algorithm");
431
432 /* NOTE: mips32_run_algorithm requires that each algorithm uses a software breakpoint
433 * at the exit point */
434
435 if (mips32->common_magic != MIPS32_COMMON_MAGIC) {
436 LOG_ERROR("current target isn't a MIPS32 target");
437 return ERROR_TARGET_INVALID;
438 }
439
440 if (target->state != TARGET_HALTED) {
441 LOG_WARNING("target not halted");
442 return ERROR_TARGET_NOT_HALTED;
443 }
444
445 /* refresh core register cache */
446 for (unsigned int i = 0; i < MIPS32_NUM_REGS; i++) {
447 if (!mips32->core_cache->reg_list[i].valid)
448 mips32->read_core_reg(target, i);
449 context[i] = buf_get_u32(mips32->core_cache->reg_list[i].value, 0, 32);
450 }
451
452 for (int i = 0; i < num_mem_params; i++) {
453 if (mem_params[i].direction == PARAM_IN)
454 continue;
455 retval = target_write_buffer(target, mem_params[i].address,
456 mem_params[i].size, mem_params[i].value);
457 if (retval != ERROR_OK)
458 return retval;
459 }
460
461 for (int i = 0; i < num_reg_params; i++) {
462 if (reg_params[i].direction == PARAM_IN)
463 continue;
464
465 struct reg *reg = register_get_by_name(mips32->core_cache, reg_params[i].reg_name, false);
466
467 if (!reg) {
468 LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name);
469 return ERROR_COMMAND_SYNTAX_ERROR;
470 }
471
472 if (reg->size != reg_params[i].size) {
473 LOG_ERROR("BUG: register '%s' size doesn't match reg_params[i].size",
474 reg_params[i].reg_name);
475 return ERROR_COMMAND_SYNTAX_ERROR;
476 }
477
478 mips32_set_core_reg(reg, reg_params[i].value);
479 }
480
481 mips32->isa_mode = mips32_algorithm_info->isa_mode;
482
483 retval = mips32_run_and_wait(target, entry_point, timeout_ms, exit_point, mips32);
484
485 if (retval != ERROR_OK)
486 return retval;
487
488 for (int i = 0; i < num_mem_params; i++) {
489 if (mem_params[i].direction != PARAM_OUT) {
490 retval = target_read_buffer(target, mem_params[i].address, mem_params[i].size,
491 mem_params[i].value);
492 if (retval != ERROR_OK)
493 return retval;
494 }
495 }
496
497 for (int i = 0; i < num_reg_params; i++) {
498 if (reg_params[i].direction != PARAM_OUT) {
499 struct reg *reg = register_get_by_name(mips32->core_cache, reg_params[i].reg_name, false);
500 if (!reg) {
501 LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name);
502 return ERROR_COMMAND_SYNTAX_ERROR;
503 }
504
505 if (reg->size != reg_params[i].size) {
506 LOG_ERROR("BUG: register '%s' size doesn't match reg_params[i].size",
507 reg_params[i].reg_name);
508 return ERROR_COMMAND_SYNTAX_ERROR;
509 }
510
511 buf_set_u32(reg_params[i].value, 0, 32, buf_get_u32(reg->value, 0, 32));
512 }
513 }
514
515 /* restore everything we saved before */
516 for (unsigned int i = 0; i < MIPS32_NUM_REGS; i++) {
517 uint32_t regvalue;
518 regvalue = buf_get_u32(mips32->core_cache->reg_list[i].value, 0, 32);
519 if (regvalue != context[i]) {
520 LOG_DEBUG("restoring register %s with value 0x%8.8" PRIx32,
521 mips32->core_cache->reg_list[i].name, context[i]);
522 buf_set_u32(mips32->core_cache->reg_list[i].value,
523 0, 32, context[i]);
524 mips32->core_cache->reg_list[i].valid = true;
525 mips32->core_cache->reg_list[i].dirty = true;
526 }
527 }
528
529 mips32->isa_mode = isa_mode;
530
531 return ERROR_OK;
532 }
533
534 int mips32_examine(struct target *target)
535 {
536 struct mips32_common *mips32 = target_to_mips32(target);
537
538 if (!target_was_examined(target)) {
539 target_set_examined(target);
540
541 /* we will configure later */
542 mips32->bp_scanned = 0;
543 mips32->num_inst_bpoints = 0;
544 mips32->num_data_bpoints = 0;
545 mips32->num_inst_bpoints_avail = 0;
546 mips32->num_data_bpoints_avail = 0;
547 }
548
549 return ERROR_OK;
550 }
551
552 static int mips32_configure_ibs(struct target *target)
553 {
554 struct mips32_common *mips32 = target_to_mips32(target);
555 struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
556 int retval, i;
557 uint32_t bpinfo;
558
559 /* get number of inst breakpoints */
560 retval = target_read_u32(target, ejtag_info->ejtag_ibs_addr, &bpinfo);
561 if (retval != ERROR_OK)
562 return retval;
563
564 mips32->num_inst_bpoints = (bpinfo >> 24) & 0x0F;
565 mips32->num_inst_bpoints_avail = mips32->num_inst_bpoints;
566 mips32->inst_break_list = calloc(mips32->num_inst_bpoints,
567 sizeof(struct mips32_comparator));
568
569 for (i = 0; i < mips32->num_inst_bpoints; i++)
570 mips32->inst_break_list[i].reg_address =
571 ejtag_info->ejtag_iba0_addr +
572 (ejtag_info->ejtag_iba_step_size * i);
573
574 /* clear IBIS reg */
575 retval = target_write_u32(target, ejtag_info->ejtag_ibs_addr, 0);
576 return retval;
577 }
578
579 static int mips32_configure_dbs(struct target *target)
580 {
581 struct mips32_common *mips32 = target_to_mips32(target);
582 struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
583 int retval, i;
584 uint32_t bpinfo;
585
586 /* get number of data breakpoints */
587 retval = target_read_u32(target, ejtag_info->ejtag_dbs_addr, &bpinfo);
588 if (retval != ERROR_OK)
589 return retval;
590
591 mips32->num_data_bpoints = (bpinfo >> 24) & 0x0F;
592 mips32->num_data_bpoints_avail = mips32->num_data_bpoints;
593 mips32->data_break_list = calloc(mips32->num_data_bpoints,
594 sizeof(struct mips32_comparator));
595
596 for (i = 0; i < mips32->num_data_bpoints; i++)
597 mips32->data_break_list[i].reg_address =
598 ejtag_info->ejtag_dba0_addr +
599 (ejtag_info->ejtag_dba_step_size * i);
600
601 /* clear DBIS reg */
602 retval = target_write_u32(target, ejtag_info->ejtag_dbs_addr, 0);
603 return retval;
604 }
605
606 int mips32_configure_break_unit(struct target *target)
607 {
608 /* get pointers to arch-specific information */
609 struct mips32_common *mips32 = target_to_mips32(target);
610 struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
611 int retval;
612 uint32_t dcr;
613
614 if (mips32->bp_scanned)
615 return ERROR_OK;
616
617 /* get info about breakpoint support */
618 retval = target_read_u32(target, EJTAG_DCR, &dcr);
619 if (retval != ERROR_OK)
620 return retval;
621
622 /* EJTAG 2.0 defines IB and DB bits in IMP instead of DCR. */
623 if (ejtag_info->ejtag_version == EJTAG_VERSION_20) {
624 ejtag_info->debug_caps = dcr & EJTAG_DCR_ENM;
625 if (!(ejtag_info->impcode & EJTAG_V20_IMP_NOIB))
626 ejtag_info->debug_caps |= EJTAG_DCR_IB;
627 if (!(ejtag_info->impcode & EJTAG_V20_IMP_NODB))
628 ejtag_info->debug_caps |= EJTAG_DCR_DB;
629 } else
630 /* keep debug caps for later use */
631 ejtag_info->debug_caps = dcr & (EJTAG_DCR_ENM
632 | EJTAG_DCR_IB | EJTAG_DCR_DB);
633
634
635 if (ejtag_info->debug_caps & EJTAG_DCR_IB) {
636 retval = mips32_configure_ibs(target);
637 if (retval != ERROR_OK)
638 return retval;
639 }
640
641 if (ejtag_info->debug_caps & EJTAG_DCR_DB) {
642 retval = mips32_configure_dbs(target);
643 if (retval != ERROR_OK)
644 return retval;
645 }
646
647 /* check if target endianness settings matches debug control register */
648 if (((ejtag_info->debug_caps & EJTAG_DCR_ENM)
649 && (target->endianness == TARGET_LITTLE_ENDIAN)) ||
650 (!(ejtag_info->debug_caps & EJTAG_DCR_ENM)
651 && (target->endianness == TARGET_BIG_ENDIAN)))
652 LOG_WARNING("DCR endianness settings does not match target settings");
653
654 LOG_DEBUG("DCR 0x%" PRIx32 " numinst %i numdata %i", dcr, mips32->num_inst_bpoints,
655 mips32->num_data_bpoints);
656
657 mips32->bp_scanned = 1;
658
659 return ERROR_OK;
660 }
661
662 int mips32_enable_interrupts(struct target *target, int enable)
663 {
664 int retval;
665 int update = 0;
666 uint32_t dcr;
667
668 /* read debug control register */
669 retval = target_read_u32(target, EJTAG_DCR, &dcr);
670 if (retval != ERROR_OK)
671 return retval;
672
673 if (enable) {
674 if (!(dcr & EJTAG_DCR_INTE)) {
675 /* enable interrupts */
676 dcr |= EJTAG_DCR_INTE;
677 update = 1;
678 }
679 } else {
680 if (dcr & EJTAG_DCR_INTE) {
681 /* disable interrupts */
682 dcr &= ~EJTAG_DCR_INTE;
683 update = 1;
684 }
685 }
686
687 if (update) {
688 retval = target_write_u32(target, EJTAG_DCR, dcr);
689 if (retval != ERROR_OK)
690 return retval;
691 }
692
693 return ERROR_OK;
694 }
695
696 /* read config to config3 cp0 registers and log isa implementation */
697 int mips32_read_config_regs(struct target *target)
698 {
699 struct mips32_common *mips32 = target_to_mips32(target);
700 struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
701
702 if (ejtag_info->config_regs == 0)
703 for (int i = 0; i != 4; i++) {
704 int retval = mips32_cp0_read(ejtag_info, &ejtag_info->config[i], 16, i);
705 if (retval != ERROR_OK) {
706 LOG_ERROR("isa info not available, failed to read cp0 config register: %" PRId32, i);
707 ejtag_info->config_regs = 0;
708 return retval;
709 }
710 ejtag_info->config_regs = i + 1;
711 if ((ejtag_info->config[i] & (1 << 31)) == 0)
712 break; /* no more config registers implemented */
713 }
714 else
715 return ERROR_OK; /* already successfully read */
716
717 LOG_DEBUG("read %"PRIu32" config registers", ejtag_info->config_regs);
718
719 if (ejtag_info->impcode & EJTAG_IMP_MIPS16) {
720 mips32->isa_imp = MIPS32_MIPS16;
721 LOG_USER("MIPS32 with MIPS16 support implemented");
722
723 } else if (ejtag_info->config_regs >= 4) { /* config3 implemented */
724 unsigned isa_imp = (ejtag_info->config[3] & MIPS32_CONFIG3_ISA_MASK) >> MIPS32_CONFIG3_ISA_SHIFT;
725 if (isa_imp == 1) {
726 mips32->isa_imp = MMIPS32_ONLY;
727 LOG_USER("MICRO MIPS32 only implemented");
728
729 } else if (isa_imp != 0) {
730 mips32->isa_imp = MIPS32_MMIPS32;
731 LOG_USER("MIPS32 and MICRO MIPS32 implemented");
732 }
733 }
734
735 if (mips32->isa_imp == MIPS32_ONLY) /* initial default value */
736 LOG_USER("MIPS32 only implemented");
737
738 return ERROR_OK;
739 }
740 int mips32_checksum_memory(struct target *target, target_addr_t address,
741 uint32_t count, uint32_t *checksum)
742 {
743 struct working_area *crc_algorithm;
744 struct reg_param reg_params[2];
745 struct mips32_algorithm mips32_info;
746
747 struct mips32_common *mips32 = target_to_mips32(target);
748 struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
749
750 /* see contrib/loaders/checksum/mips32.s for src */
751 uint32_t isa = ejtag_info->isa ? 1 : 0;
752
753 uint32_t mips_crc_code[] = {
754 MIPS32_ADDIU(isa, 12, 4, 0), /* addiu $t4, $a0, 0 */
755 MIPS32_ADDIU(isa, 10, 5, 0), /* addiu $t2, $a1, 0 */
756 MIPS32_ADDIU(isa, 4, 0, 0xFFFF), /* addiu $a0, $zero, 0xffff */
757 MIPS32_BEQ(isa, 0, 0, 0x10 << isa), /* beq $zero, $zero, ncomp */
758 MIPS32_ADDIU(isa, 11, 0, 0), /* addiu $t3, $zero, 0 */
759 /* nbyte: */
760 MIPS32_LB(isa, 5, 0, 12), /* lb $a1, ($t4) */
761 MIPS32_ADDI(isa, 12, 12, 1), /* addi $t4, $t4, 1 */
762 MIPS32_SLL(isa, 5, 5, 24), /* sll $a1, $a1, 24 */
763 MIPS32_LUI(isa, 2, 0x04c1), /* lui $v0, 0x04c1 */
764 MIPS32_XOR(isa, 4, 4, 5), /* xor $a0, $a0, $a1 */
765 MIPS32_ORI(isa, 7, 2, 0x1db7), /* ori $a3, $v0, 0x1db7 */
766 MIPS32_ADDU(isa, 6, 0, 0), /* addu $a2, $zero, $zero */
767 /* loop */
768 MIPS32_SLL(isa, 8, 4, 1), /* sll $t0, $a0, 1 */
769 MIPS32_ADDIU(isa, 6, 6, 1), /* addiu $a2, $a2, 1 */
770 MIPS32_SLTI(isa, 4, 4, 0), /* slti $a0, $a0, 0 */
771 MIPS32_XOR(isa, 9, 8, 7), /* xor $t1, $t0, $a3 */
772 MIPS32_MOVN(isa, 8, 9, 4), /* movn $t0, $t1, $a0 */
773 MIPS32_SLTI(isa, 3, 6, 8), /* slti $v1, $a2, 8 */
774 MIPS32_BNE(isa, 3, 0, NEG16(7 << isa)), /* bne $v1, $zero, loop */
775 MIPS32_ADDU(isa, 4, 8, 0), /* addu $a0, $t0, $zero */
776 /* ncomp */
777 MIPS32_BNE(isa, 10, 11, NEG16(16 << isa)), /* bne $t2, $t3, nbyte */
778 MIPS32_ADDIU(isa, 11, 11, 1), /* addiu $t3, $t3, 1 */
779 MIPS32_SDBBP(isa),
780 };
781
782 /* make sure we have a working area */
783 if (target_alloc_working_area(target, sizeof(mips_crc_code), &crc_algorithm) != ERROR_OK)
784 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
785
786 pracc_swap16_array(ejtag_info, mips_crc_code, ARRAY_SIZE(mips_crc_code));
787
788 /* convert mips crc code into a buffer in target endianness */
789 uint8_t mips_crc_code_8[sizeof(mips_crc_code)];
790 target_buffer_set_u32_array(target, mips_crc_code_8,
791 ARRAY_SIZE(mips_crc_code), mips_crc_code);
792
793 int retval = target_write_buffer(target, crc_algorithm->address, sizeof(mips_crc_code), mips_crc_code_8);
794 if (retval != ERROR_OK)
795 return retval;
796
797 mips32_info.common_magic = MIPS32_COMMON_MAGIC;
798 mips32_info.isa_mode = isa ? MIPS32_ISA_MMIPS32 : MIPS32_ISA_MIPS32; /* run isa as in debug mode */
799
800 init_reg_param(&reg_params[0], "r4", 32, PARAM_IN_OUT);
801 buf_set_u32(reg_params[0].value, 0, 32, address);
802
803 init_reg_param(&reg_params[1], "r5", 32, PARAM_OUT);
804 buf_set_u32(reg_params[1].value, 0, 32, count);
805
806 int timeout = 20000 * (1 + (count / (1024 * 1024)));
807
808 retval = target_run_algorithm(target, 0, NULL, 2, reg_params, crc_algorithm->address,
809 crc_algorithm->address + (sizeof(mips_crc_code) - 4), timeout, &mips32_info);
810
811 if (retval == ERROR_OK)
812 *checksum = buf_get_u32(reg_params[0].value, 0, 32);
813
814 destroy_reg_param(&reg_params[0]);
815 destroy_reg_param(&reg_params[1]);
816
817 target_free_working_area(target, crc_algorithm);
818
819 return retval;
820 }
821
822 /** Checks whether a memory region is erased. */
823 int mips32_blank_check_memory(struct target *target,
824 struct target_memory_check_block *blocks, int num_blocks,
825 uint8_t erased_value)
826 {
827 struct working_area *erase_check_algorithm;
828 struct reg_param reg_params[3];
829 struct mips32_algorithm mips32_info;
830
831 struct mips32_common *mips32 = target_to_mips32(target);
832 struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
833
834 if (erased_value != 0xff) {
835 LOG_ERROR("Erase value 0x%02" PRIx8 " not yet supported for MIPS32",
836 erased_value);
837 return ERROR_FAIL;
838 }
839 uint32_t isa = ejtag_info->isa ? 1 : 0;
840 uint32_t erase_check_code[] = {
841 /* nbyte: */
842 MIPS32_LB(isa, 8, 0, 4), /* lb $t0, ($a0) */
843 MIPS32_AND(isa, 6, 6, 8), /* and $a2, $a2, $t0 */
844 MIPS32_ADDIU(isa, 5, 5, NEG16(1)), /* addiu $a1, $a1, -1 */
845 MIPS32_BNE(isa, 5, 0, NEG16(4 << isa)), /* bne $a1, $zero, nbyte */
846 MIPS32_ADDIU(isa, 4, 4, 1), /* addiu $a0, $a0, 1 */
847 MIPS32_SDBBP(isa) /* sdbbp */
848 };
849
850 /* make sure we have a working area */
851 if (target_alloc_working_area(target, sizeof(erase_check_code), &erase_check_algorithm) != ERROR_OK)
852 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
853
854 pracc_swap16_array(ejtag_info, erase_check_code, ARRAY_SIZE(erase_check_code));
855
856 /* convert erase check code into a buffer in target endianness */
857 uint8_t erase_check_code_8[sizeof(erase_check_code)];
858 target_buffer_set_u32_array(target, erase_check_code_8,
859 ARRAY_SIZE(erase_check_code), erase_check_code);
860
861 int retval = target_write_buffer(target, erase_check_algorithm->address,
862 sizeof(erase_check_code), erase_check_code_8);
863 if (retval != ERROR_OK)
864 goto cleanup;
865
866 mips32_info.common_magic = MIPS32_COMMON_MAGIC;
867 mips32_info.isa_mode = isa ? MIPS32_ISA_MMIPS32 : MIPS32_ISA_MIPS32;
868
869 init_reg_param(&reg_params[0], "r4", 32, PARAM_OUT);
870 buf_set_u32(reg_params[0].value, 0, 32, blocks[0].address);
871
872 init_reg_param(&reg_params[1], "r5", 32, PARAM_OUT);
873 buf_set_u32(reg_params[1].value, 0, 32, blocks[0].size);
874
875 init_reg_param(&reg_params[2], "r6", 32, PARAM_IN_OUT);
876 buf_set_u32(reg_params[2].value, 0, 32, erased_value);
877
878 retval = target_run_algorithm(target, 0, NULL, 3, reg_params, erase_check_algorithm->address,
879 erase_check_algorithm->address + (sizeof(erase_check_code) - 4), 10000, &mips32_info);
880
881 if (retval == ERROR_OK)
882 blocks[0].result = buf_get_u32(reg_params[2].value, 0, 32);
883
884 destroy_reg_param(&reg_params[0]);
885 destroy_reg_param(&reg_params[1]);
886 destroy_reg_param(&reg_params[2]);
887
888 cleanup:
889 target_free_working_area(target, erase_check_algorithm);
890
891 if (retval != ERROR_OK)
892 return retval;
893
894 return 1; /* only one block has been checked */
895 }
896
897 static int mips32_verify_pointer(struct command_invocation *cmd,
898 struct mips32_common *mips32)
899 {
900 if (mips32->common_magic != MIPS32_COMMON_MAGIC) {
901 command_print(cmd, "target is not an MIPS32");
902 return ERROR_TARGET_INVALID;
903 }
904 return ERROR_OK;
905 }
906
907 /**
908 * MIPS32 targets expose command interface
909 * to manipulate CP0 registers
910 */
911 COMMAND_HANDLER(mips32_handle_cp0_command)
912 {
913 int retval;
914 struct target *target = get_current_target(CMD_CTX);
915 struct mips32_common *mips32 = target_to_mips32(target);
916 struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
917
918
919 retval = mips32_verify_pointer(CMD, mips32);
920 if (retval != ERROR_OK)
921 return retval;
922
923 if (target->state != TARGET_HALTED) {
924 command_print(CMD, "target must be stopped for \"%s\" command", CMD_NAME);
925 return ERROR_OK;
926 }
927
928 /* two or more argument, access a single register/select (write if third argument is given) */
929 if (CMD_ARGC < 2)
930 return ERROR_COMMAND_SYNTAX_ERROR;
931 else {
932 uint32_t cp0_reg, cp0_sel;
933 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], cp0_reg);
934 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], cp0_sel);
935
936 if (CMD_ARGC == 2) {
937 uint32_t value;
938
939 retval = mips32_cp0_read(ejtag_info, &value, cp0_reg, cp0_sel);
940 if (retval != ERROR_OK) {
941 command_print(CMD,
942 "couldn't access reg %" PRIu32,
943 cp0_reg);
944 return ERROR_OK;
945 }
946 command_print(CMD, "cp0 reg %" PRIu32 ", select %" PRIu32 ": %8.8" PRIx32,
947 cp0_reg, cp0_sel, value);
948
949 } else if (CMD_ARGC == 3) {
950 uint32_t value;
951 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], value);
952 retval = mips32_cp0_write(ejtag_info, value, cp0_reg, cp0_sel);
953 if (retval != ERROR_OK) {
954 command_print(CMD,
955 "couldn't access cp0 reg %" PRIu32 ", select %" PRIu32,
956 cp0_reg, cp0_sel);
957 return ERROR_OK;
958 }
959 command_print(CMD, "cp0 reg %" PRIu32 ", select %" PRIu32 ": %8.8" PRIx32,
960 cp0_reg, cp0_sel, value);
961 }
962 }
963
964 return ERROR_OK;
965 }
966
967 COMMAND_HANDLER(mips32_handle_scan_delay_command)
968 {
969 struct target *target = get_current_target(CMD_CTX);
970 struct mips32_common *mips32 = target_to_mips32(target);
971 struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
972
973 if (CMD_ARGC == 1)
974 COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], ejtag_info->scan_delay);
975 else if (CMD_ARGC > 1)
976 return ERROR_COMMAND_SYNTAX_ERROR;
977
978 command_print(CMD, "scan delay: %d nsec", ejtag_info->scan_delay);
979 if (ejtag_info->scan_delay >= MIPS32_SCAN_DELAY_LEGACY_MODE) {
980 ejtag_info->mode = 0;
981 command_print(CMD, "running in legacy mode");
982 } else {
983 ejtag_info->mode = 1;
984 command_print(CMD, "running in fast queued mode");
985 }
986
987 return ERROR_OK;
988 }
989
990 static const struct command_registration mips32_exec_command_handlers[] = {
991 {
992 .name = "cp0",
993 .handler = mips32_handle_cp0_command,
994 .mode = COMMAND_EXEC,
995 .usage = "regnum select [value]",
996 .help = "display/modify cp0 register",
997 },
998 {
999 .name = "scan_delay",
1000 .handler = mips32_handle_scan_delay_command,
1001 .mode = COMMAND_ANY,
1002 .help = "display/set scan delay in nano seconds",
1003 .usage = "[value]",
1004 },
1005 COMMAND_REGISTRATION_DONE
1006 };
1007
1008 const struct command_registration mips32_command_handlers[] = {
1009 {
1010 .name = "mips32",
1011 .mode = COMMAND_ANY,
1012 .help = "mips32 command group",
1013 .usage = "",
1014 .chain = mips32_exec_command_handlers,
1015 },
1016 COMMAND_REGISTRATION_DONE
1017 };

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)