- Added support for native MinGW builds (thanks to Spencer Oliver and Michael Fischer...
[openocd.git] / src / target / arm_disassembler.c
1 /***************************************************************************
2 * Copyright (C) 2006 by Dominic Rath *
3 * Dominic.Rath@gmx.de *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include "arm_disassembler.h"
25
26 #include "log.h"
27
28 #include <string.h>
29
30 /* textual represenation of the condition field */
31 /* ALways (default) is ommitted (empty string) */
32 char *arm_condition_strings[] =
33 {
34 "EQ", "NE", "CS", "CC", "MI", "PL", "VS", "VC", "HI", "LS", "GE", "LT", "GT", "LE", "", "NV"
35 };
36
37 /* make up for C's missing ROR */
38 u32 ror(u32 value, int places)
39 {
40 return (value >> places) | (value << (32 - places));
41 }
42
43 int evaluate_pld(u32 opcode, u32 address, arm_instruction_t *instruction)
44 {
45 /* PLD */
46 if ((opcode & 0x0d70f0000) == 0x0550f000)
47 {
48 instruction->type = ARM_PLD;
49
50 snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tPLD ...TODO...", address, opcode);
51
52 return ERROR_OK;
53 }
54 else
55 {
56 instruction->type = ARM_UNDEFINED_INSTRUCTION;
57 return ERROR_OK;
58 }
59
60 ERROR("should never reach this point");
61 return -1;
62 }
63
64 int evaluate_swi(u32 opcode, u32 address, arm_instruction_t *instruction)
65 {
66 instruction->type = ARM_SWI;
67
68 snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tSWI 0x%6.6x", address, opcode, (opcode & 0xffffff));
69
70 return ERROR_OK;
71 }
72
73 int evaluate_blx_imm(u32 opcode, u32 address, arm_instruction_t *instruction)
74 {
75 int offset;
76 u32 immediate;
77 u32 target_address;
78
79 instruction->type = ARM_BLX;
80 immediate = opcode & 0x00ffffff;
81
82 /* sign extend 24-bit immediate */
83 if (immediate & 0x00800000)
84 offset = 0xff000000 | immediate;
85 else
86 offset = immediate;
87
88 /* shift two bits left */
89 offset <<= 2;
90
91 /* odd/event halfword */
92 if (opcode & 0x01000000)
93 offset |= 0x2;
94
95 target_address = address + 8 + offset;
96
97 snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tBLX 0x%8.8x", address, opcode, target_address);
98
99 instruction->info.b_bl_bx_blx.reg_operand = -1;
100 instruction->info.b_bl_bx_blx.target_address = target_address;
101
102 return ERROR_OK;
103 }
104
105 int evaluate_b_bl(u32 opcode, u32 address, arm_instruction_t *instruction)
106 {
107 u8 L;
108 u32 immediate;
109 int offset;
110 u32 target_address;
111
112 immediate = opcode & 0x00ffffff;
113 L = (opcode & 0x01000000) >> 24;
114
115 /* sign extend 24-bit immediate */
116 if (immediate & 0x00800000)
117 offset = 0xff000000 | immediate;
118 else
119 offset = immediate;
120
121 /* shift two bits left */
122 offset <<= 2;
123
124 target_address = address + 8 + offset;
125
126 if (L)
127 instruction->type = ARM_BL;
128 else
129 instruction->type = ARM_B;
130
131 snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tB%s%s 0x%8.8x", address, opcode,
132 (L) ? "L" : "", COND(opcode), target_address);
133
134 instruction->info.b_bl_bx_blx.reg_operand = -1;
135 instruction->info.b_bl_bx_blx.target_address = target_address;
136
137 return ERROR_OK;
138 }
139
140 /* Coprocessor load/store and double register transfers */
141 /* both normal and extended instruction space (condition field b1111) */
142 int evaluate_ldc_stc_mcrr_mrrc(u32 opcode, u32 address, arm_instruction_t *instruction)
143 {
144 u8 cp_num = (opcode & 0xf00) >> 8;
145
146 /* MCRR or MRRC */
147 if (((opcode & 0x0ff00000) == 0x0c400000) || ((opcode & 0x0ff00000) == 0x0c400000))
148 {
149 u8 cp_opcode, Rd, Rn, CRm;
150 char *mnemonic;
151
152 cp_opcode = (opcode & 0xf0) >> 4;
153 Rd = (opcode & 0xf000) >> 12;
154 Rn = (opcode & 0xf0000) >> 16;
155 CRm = (opcode & 0xf);
156
157 /* MCRR */
158 if ((opcode & 0x0ff00000) == 0x0c400000)
159 {
160 instruction->type = ARM_MCRR;
161 mnemonic = "MCRR";
162 }
163
164 /* MRRC */
165 if ((opcode & 0x0ff00000) == 0x0c500000)
166 {
167 instruction->type = ARM_MRRC;
168 mnemonic = "MRRC";
169 }
170
171 snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s p%i, %x, r%i, r%i, c%i",
172 address, opcode, mnemonic, COND(opcode), cp_num, cp_opcode, Rd, Rn, CRm);
173 }
174 else /* LDC or STC */
175 {
176 u8 CRd, Rn, offset;
177 u8 U, N;
178 char *mnemonic;
179 char addressing_mode[32];
180
181 CRd = (opcode & 0xf000) >> 12;
182 Rn = (opcode & 0xf0000) >> 16;
183 offset = (opcode & 0xff);
184
185 /* load/store */
186 if (opcode & 0x00100000)
187 {
188 instruction->type = ARM_LDC;
189 mnemonic = "LDC";
190 }
191 else
192 {
193 instruction->type = ARM_STC;
194 mnemonic = "STC";
195 }
196
197 U = (opcode & 0x00800000) >> 23;
198 N = (opcode & 0x00400000) >> 22;
199
200 /* addressing modes */
201 if ((opcode & 0x01200000) == 0x01000000) /* immediate offset */
202 snprintf(addressing_mode, 32, "[r%i, #%s0x%2.2x*4]", Rn, (U) ? "" : "-", offset);
203 else if ((opcode & 0x01200000) == 0x01200000) /* immediate pre-indexed */
204 snprintf(addressing_mode, 32, "[r%i, #%s0x%2.2x*4]!", Rn, (U) ? "" : "-", offset);
205 else if ((opcode & 0x01200000) == 0x00200000) /* immediate post-indexed */
206 snprintf(addressing_mode, 32, "[r%i], #%s0x%2.2x*4", Rn, (U) ? "" : "-", offset);
207 else if ((opcode & 0x01200000) == 0x00000000) /* unindexed */
208 snprintf(addressing_mode, 32, "[r%i], #0x%2.2x", Rn, offset);
209
210 snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s%s p%i, c%i, %s",
211 address, opcode, mnemonic, ((opcode & 0xf0000000) == 0xf0000000) ? COND(opcode) : "2",
212 (N) ? "L" : "",
213 cp_num, CRd, addressing_mode);
214 }
215
216 return ERROR_OK;
217 }
218
219 /* Coprocessor data processing instructions */
220 /* Coprocessor register transfer instructions */
221 /* both normal and extended instruction space (condition field b1111) */
222 int evaluate_cdp_mcr_mrc(u32 opcode, u32 address, arm_instruction_t *instruction)
223 {
224 char* cond;
225 char* mnemonic;
226 u8 cp_num, opcode_1, CRd_Rd, CRn, CRm, opcode_2;
227
228 cond = ((opcode & 0xf0000000) == 0xf0000000) ? "2" : COND(opcode);
229 cp_num = (opcode & 0xf00) >> 8;
230 CRd_Rd = (opcode & 0xf000) >> 12;
231 CRn = (opcode & 0xf0000) >> 16;
232 CRm = (opcode & 0xf);
233 opcode_2 = (opcode & 0xe0) >> 5;
234
235 /* CDP or MRC/MCR */
236 if (opcode & 0x00000010) /* bit 4 set -> MRC/MCR */
237 {
238 if (opcode & 0x00100000) /* bit 20 set -> MRC */
239 {
240 instruction->type = ARM_MRC;
241 mnemonic = "MRC";
242 }
243 else /* bit 20 not set -> MCR */
244 {
245 instruction->type = ARM_MCR;
246 mnemonic = "MCR";
247 }
248
249 opcode_1 = (opcode & 0x00e00000) >> 21;
250
251 snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s p%i, 0x%2.2x, r%i, c%i, c%i, 0x%2.2x",
252 address, opcode, mnemonic, cond,
253 cp_num, opcode_1, CRd_Rd, CRn, CRm, opcode_2);
254 }
255 else /* bit 4 not set -> CDP */
256 {
257 instruction->type = ARM_CDP;
258 mnemonic = "CDP";
259
260 opcode_1 = (opcode & 0x00f00000) >> 20;
261
262 snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s p%i, 0x%2.2x, c%i, c%i, c%i, 0x%2.2x",
263 address, opcode, mnemonic, cond,
264 cp_num, opcode_1, CRd_Rd, CRn, CRm, opcode_2);
265 }
266
267 return ERROR_OK;
268 }
269
270 /* Load/store instructions */
271 int evaluate_load_store(u32 opcode, u32 address, arm_instruction_t *instruction)
272 {
273 u8 I, P, U, B, W, L;
274 u8 Rn, Rd;
275 char *operation; /* "LDR" or "STR" */
276 char *suffix; /* "", "B", "T", "BT" */
277 char offset[32];
278
279 /* examine flags */
280 I = (opcode & 0x02000000) >> 25;
281 P = (opcode & 0x01000000) >> 24;
282 U = (opcode & 0x00800000) >> 23;
283 B = (opcode & 0x00400000) >> 22;
284 W = (opcode & 0x00200000) >> 21;
285 L = (opcode & 0x00100000) >> 20;
286
287 /* target register */
288 Rd = (opcode & 0xf000) >> 12;
289
290 /* base register */
291 Rn = (opcode & 0xf0000) >> 16;
292
293 instruction->info.load_store.Rd = Rd;
294 instruction->info.load_store.Rn = Rn;
295 instruction->info.load_store.U = U;
296
297 /* determine operation */
298 if (L)
299 operation = "LDR";
300 else
301 operation = "STR";
302
303 /* determine instruction type and suffix */
304 if (B)
305 {
306 if ((P == 0) && (W == 1))
307 {
308 if (L)
309 instruction->type = ARM_LDRBT;
310 else
311 instruction->type = ARM_STRBT;
312 suffix = "BT";
313 }
314 else
315 {
316 if (L)
317 instruction->type = ARM_LDRB;
318 else
319 instruction->type = ARM_STRB;
320 suffix = "B";
321 }
322 }
323 else
324 {
325 if ((P == 0) && (W == 1))
326 {
327 if (L)
328 instruction->type = ARM_LDRT;
329 else
330 instruction->type = ARM_STRT;
331 suffix = "T";
332 }
333 else
334 {
335 if (L)
336 instruction->type = ARM_LDR;
337 else
338 instruction->type = ARM_STR;
339 suffix = "";
340 }
341 }
342
343 if (!I) /* #+-<offset_12> */
344 {
345 u32 offset_12 = (opcode & 0xfff);
346 snprintf(offset, 32, "#%s0x%x", (U) ? "" : "-", offset_12);
347
348 instruction->info.load_store.offset_mode = 0;
349 instruction->info.load_store.offset.offset = offset_12;
350 }
351 else /* either +-<Rm> or +-<Rm>, <shift>, #<shift_imm> */
352 {
353 u8 shift_imm, shift;
354 u8 Rm;
355
356 shift_imm = (opcode & 0xf80) >> 7;
357 shift = (opcode & 0x60) >> 5;
358 Rm = (opcode & 0xf);
359
360 /* LSR encodes a shift by 32 bit as 0x0 */
361 if ((shift == 0x1) && (shift_imm == 0x0))
362 shift_imm = 0x20;
363
364 /* ASR encodes a shift by 32 bit as 0x0 */
365 if ((shift == 0x2) && (shift_imm == 0x0))
366 shift_imm = 0x20;
367
368 /* ROR by 32 bit is actually a RRX */
369 if ((shift == 0x3) && (shift_imm == 0x0))
370 shift = 0x4;
371
372 instruction->info.load_store.offset_mode = 1;
373 instruction->info.load_store.offset.reg.Rm = Rm;
374 instruction->info.load_store.offset.reg.shift = shift;
375 instruction->info.load_store.offset.reg.shift_imm = shift_imm;
376
377 if ((shift_imm == 0x0) && (shift == 0x0)) /* +-<Rm> */
378 {
379 snprintf(offset, 32, "%sr%i", (U) ? "" : "-", Rm);
380 }
381 else /* +-<Rm>, <Shift>, #<shift_imm> */
382 {
383 switch (shift)
384 {
385 case 0x0: /* LSL */
386 snprintf(offset, 32, "%sr%i, LSL #0x%x", (U) ? "" : "-", Rm, shift_imm);
387 break;
388 case 0x1: /* LSR */
389 snprintf(offset, 32, "%sr%i, LSR #0x%x", (U) ? "" : "-", Rm, shift_imm);
390 break;
391 case 0x2: /* ASR */
392 snprintf(offset, 32, "%sr%i, ASR #0x%x", (U) ? "" : "-", Rm, shift_imm);
393 break;
394 case 0x3: /* ROR */
395 snprintf(offset, 32, "%sr%i, ROR #0x%x", (U) ? "" : "-", Rm, shift_imm);
396 break;
397 case 0x4: /* RRX */
398 snprintf(offset, 32, "%sr%i, RRX", (U) ? "" : "-", Rm);
399 break;
400 }
401 }
402 }
403
404 if (P == 1)
405 {
406 if (W == 0) /* offset */
407 {
408 snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, [r%i, %s]",
409 address, opcode, operation, COND(opcode), suffix,
410 Rd, Rn, offset);
411
412 instruction->info.load_store.index_mode = 0;
413 }
414 else /* pre-indexed */
415 {
416 snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, [r%i, %s]!",
417 address, opcode, operation, COND(opcode), suffix,
418 Rd, Rn, offset);
419
420 instruction->info.load_store.index_mode = 1;
421 }
422 }
423 else /* post-indexed */
424 {
425 snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, [r%i], %s",
426 address, opcode, operation, COND(opcode), suffix,
427 Rd, Rn, offset);
428
429 instruction->info.load_store.index_mode = 2;
430 }
431
432 return ERROR_OK;
433 }
434
435 /* Miscellaneous load/store instructions */
436 int evaluate_misc_load_store(u32 opcode, u32 address, arm_instruction_t *instruction)
437 {
438 u8 P, U, I, W, L, S, H;
439 u8 Rn, Rd;
440 char *operation; /* "LDR" or "STR" */
441 char *suffix; /* "H", "SB", "SH", "D" */
442 char offset[32];
443
444 /* examine flags */
445 P = (opcode & 0x01000000) >> 24;
446 U = (opcode & 0x00800000) >> 23;
447 I = (opcode & 0x00400000) >> 22;
448 W = (opcode & 0x00200000) >> 21;
449 L = (opcode & 0x00100000) >> 20;
450 S = (opcode & 0x00000040) >> 6;
451 H = (opcode & 0x00000020) >> 5;
452
453 /* target register */
454 Rd = (opcode & 0xf000) >> 12;
455
456 /* base register */
457 Rn = (opcode & 0xf0000) >> 16;
458
459 instruction->info.load_store.Rd = Rd;
460 instruction->info.load_store.Rn = Rn;
461 instruction->info.load_store.U = U;
462
463 /* determine instruction type and suffix */
464 if (S) /* signed */
465 {
466 if (L) /* load */
467 {
468 if (H)
469 {
470 operation = "LDR";
471 instruction->type = ARM_LDRSH;
472 suffix = "SH";
473 }
474 else
475 {
476 operation = "LDR";
477 instruction->type = ARM_LDRSB;
478 suffix = "SB";
479 }
480 }
481 else /* there are no signed stores, so this is used to encode double-register load/stores */
482 {
483 suffix = "D";
484 if (H)
485 {
486 operation = "STR";
487 instruction->type = ARM_STRD;
488 }
489 else
490 {
491 operation = "LDR";
492 instruction->type = ARM_LDRD;
493 }
494 }
495 }
496 else /* unsigned */
497 {
498 suffix = "H";
499 if (L) /* load */
500 {
501 operation = "LDR";
502 instruction->type = ARM_LDRH;
503 }
504 else /* store */
505 {
506 operation = "STR";
507 instruction->type = ARM_STRH;
508 }
509 }
510
511 if (I) /* Immediate offset/index (#+-<offset_8>)*/
512 {
513 u32 offset_8 = ((opcode & 0xf00) >> 4) | (opcode & 0xf);
514 snprintf(offset, 32, "#%s0x%x", (U) ? "" : "-", offset_8);
515
516 instruction->info.load_store.offset_mode = 0;
517 instruction->info.load_store.offset.offset = offset_8;
518 }
519 else /* Register offset/index (+-<Rm>) */
520 {
521 u8 Rm;
522 Rm = (opcode & 0xf);
523 snprintf(offset, 32, "%sr%i", (U) ? "" : "-", Rm);
524
525 instruction->info.load_store.offset_mode = 1;
526 instruction->info.load_store.offset.reg.Rm = Rm;
527 instruction->info.load_store.offset.reg.shift = 0x0;
528 instruction->info.load_store.offset.reg.shift_imm = 0x0;
529 }
530
531 if (P == 1)
532 {
533 if (W == 0) /* offset */
534 {
535 snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, [r%i, %s]",
536 address, opcode, operation, COND(opcode), suffix,
537 Rd, Rn, offset);
538
539 instruction->info.load_store.index_mode = 0;
540 }
541 else /* pre-indexed */
542 {
543 snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, [r%i, %s]!",
544 address, opcode, operation, COND(opcode), suffix,
545 Rd, Rn, offset);
546
547 instruction->info.load_store.index_mode = 1;
548 }
549 }
550 else /* post-indexed */
551 {
552 snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, [r%i], %s",
553 address, opcode, operation, COND(opcode), suffix,
554 Rd, Rn, offset);
555
556 instruction->info.load_store.index_mode = 2;
557 }
558
559 return ERROR_OK;
560 }
561
562 /* Load/store multiples instructions */
563 int evaluate_ldm_stm(u32 opcode, u32 address, arm_instruction_t *instruction)
564 {
565 u8 P, U, S, W, L, Rn;
566 u32 register_list;
567 char *addressing_mode;
568 char *mnemonic;
569 char reg_list[69];
570 char *reg_list_p;
571 int i;
572 int first_reg = 1;
573
574 P = (opcode & 0x01000000) >> 24;
575 U = (opcode & 0x00800000) >> 23;
576 S = (opcode & 0x00400000) >> 22;
577 W = (opcode & 0x00200000) >> 21;
578 L = (opcode & 0x00100000) >> 20;
579 register_list = (opcode & 0xffff);
580 Rn = (opcode & 0xf0000) >> 16;
581
582 instruction->info.load_store_multiple.Rn = Rn;
583 instruction->info.load_store_multiple.register_list = register_list;
584 instruction->info.load_store_multiple.S = S;
585 instruction->info.load_store_multiple.W = W;
586
587 if (L)
588 {
589 instruction->type = ARM_LDM;
590 mnemonic = "LDM";
591 }
592 else
593 {
594 instruction->type = ARM_STM;
595 mnemonic = "STM";
596 }
597
598 if (P)
599 {
600 if (U)
601 {
602 instruction->info.load_store_multiple.addressing_mode = 1;
603 addressing_mode = "IB";
604 }
605 else
606 {
607 instruction->info.load_store_multiple.addressing_mode = 3;
608 addressing_mode = "DB";
609 }
610 }
611 else
612 {
613 if (U)
614 {
615 instruction->info.load_store_multiple.addressing_mode = 0;
616 addressing_mode = "IA";
617 }
618 else
619 {
620 instruction->info.load_store_multiple.addressing_mode = 2;
621 addressing_mode = "DA";
622 }
623 }
624
625 reg_list_p = reg_list;
626 for (i = 0; i <= 15; i++)
627 {
628 if ((register_list >> i) & 1)
629 {
630 if (first_reg)
631 {
632 first_reg = 0;
633 reg_list_p += snprintf(reg_list_p, (reg_list + 69 - reg_list_p), "r%i", i);
634 }
635 else
636 {
637 reg_list_p += snprintf(reg_list_p, (reg_list + 69 - reg_list_p), ", r%i", i);
638 }
639 }
640 }
641
642 snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i%s, {%s}%s",
643 address, opcode, mnemonic, COND(opcode), addressing_mode,
644 Rn, (W) ? "!" : "", reg_list, (S) ? "^" : "");
645
646 return ERROR_OK;
647 }
648
649 /* Multiplies, extra load/stores */
650 int evaluate_mul_and_extra_ld_st(u32 opcode, u32 address, arm_instruction_t *instruction)
651 {
652 /* Multiply (accumulate) (long) and Swap/swap byte */
653 if ((opcode & 0x000000f0) == 0x00000090)
654 {
655 /* Multiply (accumulate) */
656 if ((opcode & 0x0f800000) == 0x00000000)
657 {
658 u8 Rm, Rs, Rn, Rd, S;
659 Rm = opcode & 0xf;
660 Rs = (opcode & 0xf00) >> 8;
661 Rn = (opcode & 0xf000) >> 12;
662 Rd = (opcode & 0xf0000) >> 16;
663 S = (opcode & 0x00100000) >> 20;
664
665 /* examine A bit (accumulate) */
666 if (opcode & 0x00200000)
667 {
668 instruction->type = ARM_MLA;
669 snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tMLA%s%s r%i, r%i, r%i, r%i",
670 address, opcode, COND(opcode), (S) ? "S" : "", Rd, Rm, Rs, Rn);
671 }
672 else
673 {
674 instruction->type = ARM_MUL;
675 snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tMUL%s%s r%i, r%i, r%i",
676 address, opcode, COND(opcode), (S) ? "S" : "", Rd, Rm, Rs);
677 }
678
679 return ERROR_OK;
680 }
681
682 /* Multiply (accumulate) long */
683 if ((opcode & 0x0f800000) == 0x00800000)
684 {
685 char* mnemonic;
686 u8 Rm, Rs, RdHi, RdLow, S;
687 Rm = opcode & 0xf;
688 Rs = (opcode & 0xf00) >> 8;
689 RdHi = (opcode & 0xf000) >> 12;
690 RdLow = (opcode & 0xf0000) >> 16;
691 S = (opcode & 0x00100000) >> 20;
692
693 switch ((opcode & 0x00600000) >> 21)
694 {
695 case 0x0:
696 instruction->type = ARM_UMULL;
697 mnemonic = "UMULL";
698 break;
699 case 0x1:
700 instruction->type = ARM_UMLAL;
701 mnemonic = "UMLAL";
702 break;
703 case 0x2:
704 instruction->type = ARM_SMULL;
705 mnemonic = "SMULL";
706 break;
707 case 0x3:
708 instruction->type = ARM_SMLAL;
709 mnemonic = "SMLAL";
710 break;
711 }
712
713 snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, r%i, r%i, r%i",
714 address, opcode, mnemonic, COND(opcode), (S) ? "S" : "",
715 RdLow, RdHi, Rm, Rs);
716
717 return ERROR_OK;
718 }
719
720 /* Swap/swap byte */
721 if ((opcode & 0x0f800000) == 0x01000000)
722 {
723 u8 Rm, Rd, Rn;
724 Rm = opcode & 0xf;
725 Rd = (opcode & 0xf000) >> 12;
726 Rn = (opcode & 0xf0000) >> 16;
727
728 /* examine B flag */
729 instruction->type = (opcode & 0x00400000) ? ARM_SWPB : ARM_SWP;
730
731 snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s r%i, r%i, [r%i]",
732 address, opcode, (opcode & 0x00400000) ? "SWPB" : "SWP", COND(opcode), Rd, Rm, Rn);
733 return ERROR_OK;
734 }
735
736 }
737
738 return evaluate_misc_load_store(opcode, address, instruction);
739 }
740
741 int evaluate_mrs_msr(u32 opcode, u32 address, arm_instruction_t *instruction)
742 {
743 int R = (opcode & 0x00400000) >> 22;
744 char *PSR = (R) ? "SPSR" : "CPSR";
745
746 /* Move register to status register (MSR) */
747 if (opcode & 0x00200000)
748 {
749 instruction->type = ARM_MSR;
750
751 /* immediate variant */
752 if (opcode & 0x02000000)
753 {
754 u8 immediate = (opcode & 0xff);
755 u8 rotate = (opcode & 0xf00);
756
757 snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tMSR%s %s_%s%s%s%s, 0x%8.8x",
758 address, opcode, COND(opcode), PSR,
759 (opcode & 0x10000) ? "c" : "",
760 (opcode & 0x20000) ? "x" : "",
761 (opcode & 0x40000) ? "s" : "",
762 (opcode & 0x80000) ? "f" : "",
763 ror(immediate, (rotate * 2))
764 );
765 }
766 else /* register variant */
767 {
768 u8 Rm = opcode & 0xf;
769 snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tMSR%s %s_%s%s%s%s, r%i",
770 address, opcode, COND(opcode), PSR,
771 (opcode & 0x10000) ? "c" : "",
772 (opcode & 0x20000) ? "x" : "",
773 (opcode & 0x40000) ? "s" : "",
774 (opcode & 0x80000) ? "f" : "",
775 Rm
776 );
777 }
778
779 }
780 else /* Move status register to register (MRS) */
781 {
782 u8 Rd;
783
784 instruction->type = ARM_MRS;
785 Rd = (opcode & 0x0000f000) >> 12;
786
787 snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tMRS%s r%i, %s",
788 address, opcode, COND(opcode), Rd, PSR);
789 }
790
791 return ERROR_OK;
792 }
793
794 /* Miscellaneous instructions */
795 int evaluate_misc_instr(u32 opcode, u32 address, arm_instruction_t *instruction)
796 {
797 /* MRS/MSR */
798 if ((opcode & 0x000000f0) == 0x00000000)
799 {
800 evaluate_mrs_msr(opcode, address, instruction);
801 }
802
803 /* BX */
804 if ((opcode & 0x006000f0) == 0x00200010)
805 {
806 u8 Rm;
807 instruction->type = ARM_BX;
808 Rm = opcode & 0xf;
809
810 snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tBX%s r%i",
811 address, opcode, COND(opcode), Rm);
812
813 instruction->info.b_bl_bx_blx.reg_operand = Rm;
814 instruction->info.b_bl_bx_blx.target_address = -1;
815 }
816
817 /* CLZ */
818 if ((opcode & 0x0060000f0) == 0x00300010)
819 {
820 u8 Rm, Rd;
821 instruction->type = ARM_CLZ;
822 Rm = opcode & 0xf;
823 Rd = (opcode & 0xf000) >> 12;
824
825 snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tCLZ%s r%i, r%i",
826 address, opcode, COND(opcode), Rd, Rm);
827 }
828
829 /* BLX */
830 if ((opcode & 0x0060000f0) == 0x00200030)
831 {
832 u8 Rm;
833 instruction->type = ARM_BLX;
834 Rm = opcode & 0xf;
835
836 snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tBLX%s r%i",
837 address, opcode, COND(opcode), Rm);
838 }
839
840 /* Enhanced DSP add/subtracts */
841 if ((opcode & 0x0000000f0) == 0x00000050)
842 {
843 u8 Rm, Rd, Rn;
844 char *mnemonic;
845 Rm = opcode & 0xf;
846 Rd = (opcode & 0xf000) >> 12;
847 Rn = (opcode & 0xf0000) >> 16;
848
849 switch ((opcode & 0x00600000) >> 21)
850 {
851 case 0x0:
852 instruction->type = ARM_QADD;
853 mnemonic = "QADD";
854 break;
855 case 0x1:
856 instruction->type = ARM_QSUB;
857 mnemonic = "QSUB";
858 break;
859 case 0x2:
860 instruction->type = ARM_QDADD;
861 mnemonic = "QDADD";
862 break;
863 case 0x3:
864 instruction->type = ARM_QDSUB;
865 mnemonic = "QDSUB";
866 break;
867 }
868
869 snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s r%i, r%i, r%i",
870 address, opcode, mnemonic, COND(opcode), Rd, Rm, Rn);
871 }
872
873 /* Software breakpoints */
874 if ((opcode & 0x0000000f0) == 0x00000070)
875 {
876 u32 immediate;
877 instruction->type = ARM_BKPT;
878 immediate = ((opcode & 0x000fff00) >> 4) | (opcode & 0xf);
879
880 snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tBKPT 0x%4.4x",
881 address, opcode, immediate);
882 }
883
884 /* Enhanced DSP multiplies */
885 if ((opcode & 0x000000090) == 0x00000080)
886 {
887 int x = (opcode & 0x20) >> 5;
888 int y = (opcode & 0x40) >> 6;
889
890 /* SMLA<x><y> */
891 if ((opcode & 0x00600000) == 0x00000000)
892 {
893 u8 Rd, Rm, Rs, Rn;
894 instruction->type = ARM_SMLAxy;
895 Rd = (opcode & 0xf0000) >> 16;
896 Rm = (opcode & 0xf);
897 Rs = (opcode & 0xf00) >> 8;
898 Rn = (opcode & 0xf000) >> 12;
899
900 snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tSMLA%s%s%s r%i, r%i, r%i, r%i",
901 address, opcode, (x) ? "T" : "B", (y) ? "T" : "B", COND(opcode),
902 Rd, Rm, Rs, Rn);
903 }
904
905 /* SMLAL<x><y> */
906 if ((opcode & 0x00600000) == 0x00400000)
907 {
908 u8 RdLow, RdHi, Rm, Rs;
909 instruction->type = ARM_SMLAxy;
910 RdHi = (opcode & 0xf0000) >> 16;
911 RdLow = (opcode & 0xf000) >> 12;
912 Rm = (opcode & 0xf);
913 Rs = (opcode & 0xf00) >> 8;
914
915 snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tSMLA%s%s%s r%i, r%i, r%i, r%i",
916 address, opcode, (x) ? "T" : "B", (y) ? "T" : "B", COND(opcode),
917 RdLow, RdHi, Rm, Rs);
918 }
919
920 /* SMLAW<y> */
921 if (((opcode & 0x00600000) == 0x00100000) && (x == 0))
922 {
923 u8 Rd, Rm, Rs, Rn;
924 instruction->type = ARM_SMLAWy;
925 Rd = (opcode & 0xf0000) >> 16;
926 Rm = (opcode & 0xf);
927 Rs = (opcode & 0xf00) >> 8;
928 Rn = (opcode & 0xf000) >> 12;
929
930 snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tSMLAW%s%s r%i, r%i, r%i, r%i",
931 address, opcode, (y) ? "T" : "B", COND(opcode),
932 Rd, Rm, Rs, Rn);
933 }
934
935 /* SMUL<x><y> */
936 if ((opcode & 0x00600000) == 0x00300000)
937 {
938 u8 Rd, Rm, Rs;
939 instruction->type = ARM_SMULxy;
940 Rd = (opcode & 0xf0000) >> 16;
941 Rm = (opcode & 0xf);
942 Rs = (opcode & 0xf00) >> 8;
943
944 snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tSMULW%s%s%s r%i, r%i, r%i",
945 address, opcode, (x) ? "T" : "B", (y) ? "T" : "B", COND(opcode),
946 Rd, Rm, Rs);
947 }
948
949 /* SMULW<y> */
950 if (((opcode & 0x00600000) == 0x00100000) && (x == 1))
951 {
952 u8 Rd, Rm, Rs;
953 instruction->type = ARM_SMULWy;
954 Rd = (opcode & 0xf0000) >> 16;
955 Rm = (opcode & 0xf);
956 Rs = (opcode & 0xf00) >> 8;
957
958 snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tSMULW%s%s r%i, r%i, r%i",
959 address, opcode, (y) ? "T" : "B", COND(opcode),
960 Rd, Rm, Rs);
961 }
962 }
963
964 return ERROR_OK;
965 }
966
967 int evaluate_data_proc(u32 opcode, u32 address, arm_instruction_t *instruction)
968 {
969 u8 I, op, S, Rn, Rd;
970 char *mnemonic;
971 char shifter_operand[32];
972
973 I = (opcode & 0x02000000) >> 25;
974 op = (opcode & 0x01e00000) >> 21;
975 S = (opcode & 0x00100000) >> 20;
976
977 Rd = (opcode & 0xf000) >> 12;
978 Rn = (opcode & 0xf0000) >> 16;
979
980 instruction->info.data_proc.Rd = Rd;
981 instruction->info.data_proc.Rn = Rn;
982 instruction->info.data_proc.S = S;
983
984 switch (op)
985 {
986 case 0x0:
987 instruction->type = ARM_AND;
988 mnemonic = "AND";
989 break;
990 case 0x1:
991 instruction->type = ARM_EOR;
992 mnemonic = "EOR";
993 break;
994 case 0x2:
995 instruction->type = ARM_SUB;
996 mnemonic = "SUB";
997 break;
998 case 0x3:
999 instruction->type = ARM_RSB;
1000 mnemonic = "RSB";
1001 break;
1002 case 0x4:
1003 instruction->type = ARM_ADD;
1004 mnemonic = "ADD";
1005 break;
1006 case 0x5:
1007 instruction->type = ARM_ADC;
1008 mnemonic = "ADC";
1009 break;
1010 case 0x6:
1011 instruction->type = ARM_SBC;
1012 mnemonic = "SBC";
1013 break;
1014 case 0x7:
1015 instruction->type = ARM_RSC;
1016 mnemonic = "RSC";
1017 break;
1018 case 0x8:
1019 instruction->type = ARM_TST;
1020 mnemonic = "TST";
1021 break;
1022 case 0x9:
1023 instruction->type = ARM_TEQ;
1024 mnemonic = "TEQ";
1025 break;
1026 case 0xa:
1027 instruction->type = ARM_CMP;
1028 mnemonic = "CMP";
1029 break;
1030 case 0xb:
1031 instruction->type = ARM_CMN;
1032 mnemonic = "CMN";
1033 break;
1034 case 0xc:
1035 instruction->type = ARM_ORR;
1036 mnemonic = "ORR";
1037 break;
1038 case 0xd:
1039 instruction->type = ARM_MOV;
1040 mnemonic = "MOV";
1041 break;
1042 case 0xe:
1043 instruction->type = ARM_BIC;
1044 mnemonic = "BIC";
1045 break;
1046 case 0xf:
1047 instruction->type = ARM_MVN;
1048 mnemonic = "MVN";
1049 break;
1050 }
1051
1052 if (I) /* immediate shifter operand (#<immediate>)*/
1053 {
1054 u8 immed_8 = opcode & 0xff;
1055 u8 rotate_imm = (opcode & 0xf00) >> 8;
1056 u32 immediate;
1057
1058 immediate = ror(immed_8, rotate_imm * 2);
1059
1060 snprintf(shifter_operand, 32, "#0x%x", immediate);
1061
1062 instruction->info.data_proc.variant = 0;
1063 instruction->info.data_proc.shifter_operand.immediate.immediate = immediate;
1064 }
1065 else /* register-based shifter operand */
1066 {
1067 u8 shift, Rm;
1068 shift = (opcode & 0x60) >> 5;
1069 Rm = (opcode & 0xf);
1070
1071 if ((opcode & 0x10) != 0x10) /* Immediate shifts ("<Rm>" or "<Rm>, <shift> #<shift_immediate>") */
1072 {
1073 u8 shift_imm;
1074 shift_imm = (opcode & 0xf80) >> 7;
1075
1076 instruction->info.data_proc.variant = 1;
1077 instruction->info.data_proc.shifter_operand.immediate_shift.Rm = Rm;
1078 instruction->info.data_proc.shifter_operand.immediate_shift.shift_imm = shift_imm;
1079 instruction->info.data_proc.shifter_operand.immediate_shift.shift = shift;
1080
1081 if ((shift_imm == 0x0) && (shift == 0x0))
1082 {
1083 snprintf(shifter_operand, 32, "r%i", Rm);
1084 }
1085 else
1086 {
1087 if (shift == 0x0) /* LSL */
1088 {
1089 snprintf(shifter_operand, 32, "r%i, LSL #0x%x", Rm, shift_imm);
1090 }
1091 else if (shift == 0x1) /* LSR */
1092 {
1093 if (shift_imm == 0x0)
1094 shift_imm = 0x32;
1095 snprintf(shifter_operand, 32, "r%i, LSR #0x%x", Rm, shift_imm);
1096 }
1097 else if (shift == 0x2) /* ASR */
1098 {
1099 if (shift_imm == 0x0)
1100 shift_imm = 0x32;
1101 snprintf(shifter_operand, 32, "r%i, ASR #0x%x", Rm, shift_imm);
1102 }
1103 else if (shift == 0x3) /* ROR or RRX */
1104 {
1105 if (shift_imm == 0x0) /* RRX */
1106 snprintf(shifter_operand, 32, "r%i, RRX", Rm);
1107 else
1108 snprintf(shifter_operand, 32, "r%i, ROR #0x%x", Rm, shift_imm);
1109 }
1110 }
1111 }
1112 else /* Register shifts ("<Rm>, <shift> <Rs>") */
1113 {
1114 u8 Rs = (opcode & 0xf00) >> 8;
1115
1116 instruction->info.data_proc.variant = 2;
1117 instruction->info.data_proc.shifter_operand.register_shift.Rm = Rm;
1118 instruction->info.data_proc.shifter_operand.register_shift.Rs = Rs;
1119 instruction->info.data_proc.shifter_operand.register_shift.shift = shift;
1120
1121 if (shift == 0x0) /* LSL */
1122 {
1123 snprintf(shifter_operand, 32, "r%i, LSL r%i", Rm, Rs);
1124 }
1125 else if (shift == 0x1) /* LSR */
1126 {
1127 snprintf(shifter_operand, 32, "r%i, LSR r%i", Rm, Rs);
1128 }
1129 else if (shift == 0x2) /* ASR */
1130 {
1131 snprintf(shifter_operand, 32, "r%i, ASR r%i", Rm, Rs);
1132 }
1133 else if (shift == 0x3) /* ROR or RRX */
1134 {
1135 snprintf(shifter_operand, 32, "r%i, ROR r%i", Rm, Rs);
1136 }
1137 }
1138 }
1139
1140 if ((op < 0x8) || (op == 0xc) || (op == 0xe)) /* <opcode3>{<cond>}{S} <Rd>, <Rn>, <shifter_operand> */
1141 {
1142 snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, r%i, %s",
1143 address, opcode, mnemonic, COND(opcode),
1144 (S) ? "S" : "", Rd, Rn, shifter_operand);
1145 }
1146 else if ((op == 0xd) || (op == 0xf)) /* <opcode1>{<cond>}{S} <Rd>, <shifter_operand> */
1147 {
1148 snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, %s",
1149 address, opcode, mnemonic, COND(opcode),
1150 (S) ? "S" : "", Rd, shifter_operand);
1151 }
1152 else /* <opcode2>{<cond>} <Rn>, <shifter_operand> */
1153 {
1154 snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s r%i, %s",
1155 address, opcode, mnemonic, COND(opcode),
1156 Rn, shifter_operand);
1157 }
1158
1159 return ERROR_OK;
1160 }
1161
1162 int evaluate_opcode(u32 opcode, u32 address, arm_instruction_t *instruction)
1163 {
1164 /* clear fields, to avoid confusion */
1165 memset(instruction, 0, sizeof(arm_instruction_t));
1166 instruction->opcode = opcode;
1167
1168 /* catch opcodes with condition field [31:28] = b1111 */
1169 if ((opcode & 0xf0000000) == 0xf0000000)
1170 {
1171 /* Undefined instruction (or ARMv5E cache preload PLD) */
1172 if ((opcode & 0x08000000) == 0x00000000)
1173 return evaluate_pld(opcode, address, instruction);
1174
1175 /* Undefined instruction */
1176 if ((opcode & 0x0e000000) == 0x08000000)
1177 {
1178 instruction->type = ARM_UNDEFINED_INSTRUCTION;
1179 snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tUNDEFINED INSTRUCTION", address, opcode);
1180 return ERROR_OK;
1181 }
1182
1183 /* Branch and branch with link and change to Thumb */
1184 if ((opcode & 0x0e000000) == 0x0a000000)
1185 return evaluate_blx_imm(opcode, address, instruction);
1186
1187 /* Extended coprocessor opcode space (ARMv5 and higher )*/
1188 /* Coprocessor load/store and double register transfers */
1189 if ((opcode & 0x0e000000) == 0x0c000000)
1190 return evaluate_ldc_stc_mcrr_mrrc(opcode, address, instruction);
1191
1192 /* Coprocessor data processing */
1193 if ((opcode & 0x0f000100) == 0x0c000000)
1194 return evaluate_cdp_mcr_mrc(opcode, address, instruction);
1195
1196 /* Coprocessor register transfers */
1197 if ((opcode & 0x0f000010) == 0x0c000010)
1198 return evaluate_cdp_mcr_mrc(opcode, address, instruction);
1199
1200 /* Undefined instruction */
1201 if ((opcode & 0x0f000000) == 0x0f000000)
1202 {
1203 instruction->type = ARM_UNDEFINED_INSTRUCTION;
1204 snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tUNDEFINED INSTRUCTION", address, opcode);
1205 return ERROR_OK;
1206 }
1207 }
1208
1209 /* catch opcodes with [27:25] = b000 */
1210 if ((opcode & 0x0e000000) == 0x00000000)
1211 {
1212 /* Multiplies, extra load/stores */
1213 if ((opcode & 0x00000090) == 0x00000090)
1214 return evaluate_mul_and_extra_ld_st(opcode, address, instruction);
1215
1216 /* Miscellaneous instructions */
1217 if ((opcode & 0x0f900000) == 0x01000000)
1218 return evaluate_misc_instr(opcode, address, instruction);
1219
1220 return evaluate_data_proc(opcode, address, instruction);
1221 }
1222
1223 /* catch opcodes with [27:25] = b001 */
1224 if ((opcode & 0x0e000000) == 0x02000000)
1225 {
1226 /* Undefined instruction */
1227 if ((opcode & 0x0fb00000) == 0x03000000)
1228 {
1229 instruction->type = ARM_UNDEFINED_INSTRUCTION;
1230 snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tUNDEFINED INSTRUCTION", address, opcode);
1231 return ERROR_OK;
1232 }
1233
1234 /* Move immediate to status register */
1235 if ((opcode & 0x0fb00000) == 0x03200000)
1236 return evaluate_mrs_msr(opcode, address, instruction);
1237
1238 return evaluate_data_proc(opcode, address, instruction);
1239
1240 }
1241
1242 /* catch opcodes with [27:25] = b010 */
1243 if ((opcode & 0x0e000000) == 0x04000000)
1244 {
1245 /* Load/store immediate offset */
1246 return evaluate_load_store(opcode, address, instruction);
1247 }
1248
1249 /* catch opcodes with [27:25] = b011 */
1250 if ((opcode & 0x0e000000) == 0x04000000)
1251 {
1252 /* Undefined instruction */
1253 if ((opcode & 0x00000010) == 0x00000010)
1254 {
1255 instruction->type = ARM_UNDEFINED_INSTRUCTION;
1256 snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tUNDEFINED INSTRUCTION", address, opcode);
1257 return ERROR_OK;
1258 }
1259
1260 /* Load/store register offset */
1261 return evaluate_load_store(opcode, address, instruction);
1262
1263 }
1264
1265 /* catch opcodes with [27:25] = b100 */
1266 if ((opcode & 0x0e000000) == 0x08000000)
1267 {
1268 /* Load/store multiple */
1269 return evaluate_ldm_stm(opcode, address, instruction);
1270 }
1271
1272 /* catch opcodes with [27:25] = b101 */
1273 if ((opcode & 0x0e000000) == 0x0a000000)
1274 {
1275 /* Branch and branch with link */
1276 return evaluate_b_bl(opcode, address, instruction);
1277 }
1278
1279 /* catch opcodes with [27:25] = b110 */
1280 if ((opcode & 0x0e000000) == 0x0a000000)
1281 {
1282 /* Coprocessor load/store and double register transfers */
1283 return evaluate_ldc_stc_mcrr_mrrc(opcode, address, instruction);
1284 }
1285
1286 /* catch opcodes with [27:25] = b111 */
1287 if ((opcode & 0x0e000000) == 0x0e000000)
1288 {
1289 /* Software interrupt */
1290 if ((opcode & 0x0f000000) == 0x0f000000)
1291 return evaluate_swi(opcode, address, instruction);
1292
1293 /* Coprocessor data processing */
1294 if ((opcode & 0x0f000010) == 0x0e000000)
1295 return evaluate_cdp_mcr_mrc(opcode, address, instruction);
1296
1297 /* Coprocessor register transfers */
1298 if ((opcode & 0x0f000010) == 0x0e000010)
1299 return evaluate_cdp_mcr_mrc(opcode, address, instruction);
1300 }
1301
1302 ERROR("should never reach this point");
1303 return -1;
1304 }

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)