1 /***************************************************************************
2 * Copyright (C) 2006 by Dominic Rath *
3 * Dominic.Rath@gmx.de *
5 * Copyright (C) 2008 by Hongtao Zheng *
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. *
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. *
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 ***************************************************************************/
28 #include "arm_disassembler.h"
29 #include "arm_simulator.h"
30 #include "binarybuffer.h"
33 static uint32_t arm_shift(uint8_t shift
, uint32_t Rm
,
34 uint32_t shift_amount
, uint8_t *carry
)
36 uint32_t return_value
= 0;
39 if (shift
== 0x0) /* LSL */
41 if ((shift_amount
> 0) && (shift_amount
<= 32))
43 return_value
= Rm
<< shift_amount
;
44 *carry
= Rm
>> (32 - shift_amount
);
46 else if (shift_amount
> 32)
51 else /* (shift_amount == 0) */
56 else if (shift
== 0x1) /* LSR */
58 if ((shift_amount
> 0) && (shift_amount
<= 32))
60 return_value
= Rm
>> shift_amount
;
61 *carry
= (Rm
>> (shift_amount
- 1)) & 1;
63 else if (shift_amount
> 32)
68 else /* (shift_amount == 0) */
73 else if (shift
== 0x2) /* ASR */
75 if ((shift_amount
> 0) && (shift_amount
<= 32))
77 /* C right shifts of unsigned values are guaranteed to
78 * be logical (shift in zeroes); simulate an arithmetic
79 * shift (shift in signed-bit) by adding the sign bit
82 return_value
= Rm
>> shift_amount
;
84 return_value
|= 0xffffffff << (32 - shift_amount
);
86 else if (shift_amount
> 32)
90 return_value
= 0xffffffff;
99 else /* (shift_amount == 0) */
104 else if (shift
== 0x3) /* ROR */
106 if (shift_amount
== 0)
112 shift_amount
= shift_amount
% 32;
113 return_value
= (Rm
>> shift_amount
) | (Rm
<< (32 - shift_amount
));
114 *carry
= (return_value
>> 31) & 0x1;
117 else if (shift
== 0x4) /* RRX */
119 return_value
= Rm
>> 1;
129 static uint32_t arm_shifter_operand(struct arm_sim_interface
*sim
,
130 int variant
, union arm_shifter_operand shifter_operand
,
131 uint8_t *shifter_carry_out
)
133 uint32_t return_value
;
134 int instruction_size
;
136 if (sim
->get_state(sim
) == ARMV4_5_STATE_ARM
)
137 instruction_size
= 4;
139 instruction_size
= 2;
141 *shifter_carry_out
= sim
->get_cpsr(sim
, 29, 1);
143 if (variant
== 0) /* 32-bit immediate */
145 return_value
= shifter_operand
.immediate
.immediate
;
147 else if (variant
== 1) /* immediate shift */
149 uint32_t Rm
= sim
->get_reg_mode(sim
, shifter_operand
.immediate_shift
.Rm
);
151 /* adjust RM in case the PC is being read */
152 if (shifter_operand
.immediate_shift
.Rm
== 15)
153 Rm
+= 2 * instruction_size
;
155 return_value
= arm_shift(shifter_operand
.immediate_shift
.shift
,
156 Rm
, shifter_operand
.immediate_shift
.shift_imm
,
159 else if (variant
== 2) /* register shift */
161 uint32_t Rm
= sim
->get_reg_mode(sim
, shifter_operand
.register_shift
.Rm
);
162 uint32_t Rs
= sim
->get_reg_mode(sim
, shifter_operand
.register_shift
.Rs
);
164 /* adjust RM in case the PC is being read */
165 if (shifter_operand
.register_shift
.Rm
== 15)
166 Rm
+= 2 * instruction_size
;
168 return_value
= arm_shift(shifter_operand
.immediate_shift
.shift
,
169 Rm
, Rs
, shifter_carry_out
);
173 LOG_ERROR("BUG: shifter_operand.variant not 0, 1 or 2");
174 return_value
= 0xffffffff;
180 static int pass_condition(uint32_t cpsr
, uint32_t opcode
)
182 switch ((opcode
& 0xf0000000) >> 28)
185 if (cpsr
& 0x40000000)
190 if (!(cpsr
& 0x40000000))
195 if (cpsr
& 0x20000000)
200 if (!(cpsr
& 0x20000000))
205 if (cpsr
& 0x80000000)
210 if (!(cpsr
& 0x80000000))
215 if (cpsr
& 0x10000000)
220 if (!(cpsr
& 0x10000000))
225 if ((cpsr
& 0x20000000) && !(cpsr
& 0x40000000))
230 if (!(cpsr
& 0x20000000) || (cpsr
& 0x40000000))
235 if (((cpsr
& 0x80000000) && (cpsr
& 0x10000000))
236 || (!(cpsr
& 0x80000000) && !(cpsr
& 0x10000000)))
241 if (((cpsr
& 0x80000000) && !(cpsr
& 0x10000000))
242 || (!(cpsr
& 0x80000000) && (cpsr
& 0x10000000)))
247 if (!(cpsr
& 0x40000000) &&
248 (((cpsr
& 0x80000000) && (cpsr
& 0x10000000))
249 || (!(cpsr
& 0x80000000) && !(cpsr
& 0x10000000))))
254 if ((cpsr
& 0x40000000) ||
255 ((cpsr
& 0x80000000) && !(cpsr
& 0x10000000))
256 || (!(cpsr
& 0x80000000) && (cpsr
& 0x10000000)))
266 LOG_ERROR("BUG: should never get here");
270 static int thumb_pass_branch_condition(uint32_t cpsr
, uint16_t opcode
)
272 return pass_condition(cpsr
, (opcode
& 0x0f00) << 20);
275 /* simulate a single step (if possible)
276 * if the dry_run_pc argument is provided, no state is changed,
277 * but the new pc is stored in the variable pointed at by the argument
279 int arm_simulate_step_core(struct target
*target
,
280 uint32_t *dry_run_pc
, struct arm_sim_interface
*sim
)
282 uint32_t current_pc
= sim
->get_reg(sim
, 15);
283 struct arm_instruction instruction
;
284 int instruction_size
;
285 int retval
= ERROR_OK
;
287 if (sim
->get_state(sim
) == ARMV4_5_STATE_ARM
)
291 /* get current instruction, and identify it */
292 if ((retval
= target_read_u32(target
, current_pc
, &opcode
)) != ERROR_OK
)
296 if ((retval
= arm_evaluate_opcode(opcode
, current_pc
, &instruction
)) != ERROR_OK
)
300 instruction_size
= 4;
302 /* check condition code (for all instructions) */
303 if (!pass_condition(sim
->get_cpsr(sim
, 0, 32), opcode
))
307 *dry_run_pc
= current_pc
+ instruction_size
;
311 sim
->set_reg(sim
, 15, current_pc
+ instruction_size
);
321 retval
= target_read_u16(target
, current_pc
, &opcode
);
322 if (retval
!= ERROR_OK
)
324 retval
= thumb_evaluate_opcode(opcode
, current_pc
, &instruction
);
325 if (retval
!= ERROR_OK
)
327 instruction_size
= 2;
329 /* check condition code (only for branch (1) instructions) */
330 if ((opcode
& 0xf000) == 0xd000
331 && !thumb_pass_branch_condition(
332 sim
->get_cpsr(sim
, 0, 32), opcode
))
336 *dry_run_pc
= current_pc
+ instruction_size
;
340 sim
->set_reg(sim
, 15, current_pc
+ instruction_size
);
346 /* Deal with 32-bit BL/BLX */
347 if ((opcode
& 0xf800) == 0xf000) {
348 uint32_t high
= instruction
.info
.b_bl_bx_blx
.target_address
;
349 retval
= target_read_u16(target
, current_pc
+2, &opcode
);
350 if (retval
!= ERROR_OK
)
352 retval
= thumb_evaluate_opcode(opcode
, current_pc
, &instruction
);
353 if (retval
!= ERROR_OK
)
355 instruction
.info
.b_bl_bx_blx
.target_address
+= high
;
359 /* examine instruction type */
361 /* branch instructions */
362 if ((instruction
.type
>= ARM_B
) && (instruction
.type
<= ARM_BLX
))
366 if (instruction
.info
.b_bl_bx_blx
.reg_operand
== -1)
368 target
= instruction
.info
.b_bl_bx_blx
.target_address
;
372 target
= sim
->get_reg_mode(sim
, instruction
.info
.b_bl_bx_blx
.reg_operand
);
373 if (instruction
.info
.b_bl_bx_blx
.reg_operand
== 15)
375 target
+= 2 * instruction_size
;
381 *dry_run_pc
= target
& ~1;
386 if (instruction
.type
== ARM_B
)
388 sim
->set_reg(sim
, 15, target
);
390 else if (instruction
.type
== ARM_BL
)
392 uint32_t old_pc
= sim
->get_reg(sim
, 15);
393 int T
= (sim
->get_state(sim
) == ARMV4_5_STATE_THUMB
);
394 sim
->set_reg_mode(sim
, 14, old_pc
+ 4 + T
);
395 sim
->set_reg(sim
, 15, target
);
397 else if (instruction
.type
== ARM_BX
)
401 sim
->set_state(sim
, ARMV4_5_STATE_THUMB
);
405 sim
->set_state(sim
, ARMV4_5_STATE_ARM
);
407 sim
->set_reg(sim
, 15, target
& 0xfffffffe);
409 else if (instruction
.type
== ARM_BLX
)
411 uint32_t old_pc
= sim
->get_reg(sim
, 15);
412 int T
= (sim
->get_state(sim
) == ARMV4_5_STATE_THUMB
);
413 sim
->set_reg_mode(sim
, 14, old_pc
+ 4 + T
);
417 sim
->set_state(sim
, ARMV4_5_STATE_THUMB
);
421 sim
->set_state(sim
, ARMV4_5_STATE_ARM
);
423 sim
->set_reg(sim
, 15, target
& 0xfffffffe);
429 /* data processing instructions, except compare instructions (CMP, CMN, TST, TEQ) */
430 else if (((instruction
.type
>= ARM_AND
) && (instruction
.type
<= ARM_RSC
))
431 || ((instruction
.type
>= ARM_ORR
) && (instruction
.type
<= ARM_MVN
)))
433 uint32_t Rd
, Rn
, shifter_operand
;
434 uint8_t C
= sim
->get_cpsr(sim
, 29, 1);
438 /* ARM_MOV and ARM_MVN does not use Rn */
439 if ((instruction
.type
!= ARM_MOV
) && (instruction
.type
!= ARM_MVN
))
440 Rn
= sim
->get_reg_mode(sim
, instruction
.info
.data_proc
.Rn
);
444 shifter_operand
= arm_shifter_operand(sim
,
445 instruction
.info
.data_proc
.variant
,
446 instruction
.info
.data_proc
.shifter_operand
,
449 /* adjust Rn in case the PC is being read */
450 if (instruction
.info
.data_proc
.Rn
== 15)
451 Rn
+= 2 * instruction_size
;
453 if (instruction
.type
== ARM_AND
)
454 Rd
= Rn
& shifter_operand
;
455 else if (instruction
.type
== ARM_EOR
)
456 Rd
= Rn
^ shifter_operand
;
457 else if (instruction
.type
== ARM_SUB
)
458 Rd
= Rn
- shifter_operand
;
459 else if (instruction
.type
== ARM_RSB
)
460 Rd
= shifter_operand
- Rn
;
461 else if (instruction
.type
== ARM_ADD
)
462 Rd
= Rn
+ shifter_operand
;
463 else if (instruction
.type
== ARM_ADC
)
464 Rd
= Rn
+ shifter_operand
+ (C
& 1);
465 else if (instruction
.type
== ARM_SBC
)
466 Rd
= Rn
- shifter_operand
- (C
& 1) ? 0 : 1;
467 else if (instruction
.type
== ARM_RSC
)
468 Rd
= shifter_operand
- Rn
- (C
& 1) ? 0 : 1;
469 else if (instruction
.type
== ARM_ORR
)
470 Rd
= Rn
| shifter_operand
;
471 else if (instruction
.type
== ARM_BIC
)
472 Rd
= Rn
& ~(shifter_operand
);
473 else if (instruction
.type
== ARM_MOV
)
474 Rd
= shifter_operand
;
475 else if (instruction
.type
== ARM_MVN
)
476 Rd
= ~shifter_operand
;
478 LOG_WARNING("unhandled instruction type");
482 if (instruction
.info
.data_proc
.Rd
== 15)
483 *dry_run_pc
= Rd
& ~1;
485 *dry_run_pc
= current_pc
+ instruction_size
;
491 if (instruction
.info
.data_proc
.Rd
== 15) {
492 sim
->set_reg_mode(sim
, 15, Rd
& ~1);
494 sim
->set_state(sim
, ARMV4_5_STATE_THUMB
);
496 sim
->set_state(sim
, ARMV4_5_STATE_ARM
);
499 sim
->set_reg_mode(sim
, instruction
.info
.data_proc
.Rd
, Rd
);
500 LOG_WARNING("no updating of flags yet");
503 /* compare instructions (CMP, CMN, TST, TEQ) */
504 else if ((instruction
.type
>= ARM_TST
) && (instruction
.type
<= ARM_CMN
))
508 *dry_run_pc
= current_pc
+ instruction_size
;
513 LOG_WARNING("no updating of flags yet");
516 /* load register instructions */
517 else if ((instruction
.type
>= ARM_LDR
) && (instruction
.type
<= ARM_LDRSH
))
519 uint32_t load_address
= 0, modified_address
= 0, load_value
;
520 uint32_t Rn
= sim
->get_reg_mode(sim
, instruction
.info
.load_store
.Rn
);
522 /* adjust Rn in case the PC is being read */
523 if (instruction
.info
.load_store
.Rn
== 15)
524 Rn
+= 2 * instruction_size
;
526 if (instruction
.info
.load_store
.offset_mode
== 0)
528 if (instruction
.info
.load_store
.U
)
529 modified_address
= Rn
+ instruction
.info
.load_store
.offset
.offset
;
531 modified_address
= Rn
- instruction
.info
.load_store
.offset
.offset
;
533 else if (instruction
.info
.load_store
.offset_mode
== 1)
536 uint32_t Rm
= sim
->get_reg_mode(sim
,
537 instruction
.info
.load_store
.offset
.reg
.Rm
);
538 uint8_t shift
= instruction
.info
.load_store
.offset
.reg
.shift
;
539 uint8_t shift_imm
= instruction
.info
.load_store
.offset
.reg
.shift_imm
;
540 uint8_t carry
= sim
->get_cpsr(sim
, 29, 1);
542 offset
= arm_shift(shift
, Rm
, shift_imm
, &carry
);
544 if (instruction
.info
.load_store
.U
)
545 modified_address
= Rn
+ offset
;
547 modified_address
= Rn
- offset
;
551 LOG_ERROR("BUG: offset_mode neither 0 (offset) nor 1 (scaled register)");
554 if (instruction
.info
.load_store
.index_mode
== 0)
557 * we load from the modified address, but don't change
558 * the base address register
560 load_address
= modified_address
;
561 modified_address
= Rn
;
563 else if (instruction
.info
.load_store
.index_mode
== 1)
566 * we load from the modified address, and write it
567 * back to the base address register
569 load_address
= modified_address
;
571 else if (instruction
.info
.load_store
.index_mode
== 2)
574 * we load from the unmodified address, and write the
575 * modified address back
580 if ((!dry_run_pc
) || (instruction
.info
.load_store
.Rd
== 15))
582 retval
= target_read_u32(target
, load_address
, &load_value
);
583 if (retval
!= ERROR_OK
)
589 if (instruction
.info
.load_store
.Rd
== 15)
590 *dry_run_pc
= load_value
& ~1;
592 *dry_run_pc
= current_pc
+ instruction_size
;
597 if ((instruction
.info
.load_store
.index_mode
== 1) ||
598 (instruction
.info
.load_store
.index_mode
== 2))
600 sim
->set_reg_mode(sim
, instruction
.info
.load_store
.Rn
, modified_address
);
603 if (instruction
.info
.load_store
.Rd
== 15) {
604 sim
->set_reg_mode(sim
, 15, load_value
& ~1);
606 sim
->set_state(sim
, ARMV4_5_STATE_THUMB
);
608 sim
->set_state(sim
, ARMV4_5_STATE_ARM
);
611 sim
->set_reg_mode(sim
, instruction
.info
.load_store
.Rd
, load_value
);
614 /* load multiple instruction */
615 else if (instruction
.type
== ARM_LDM
)
618 uint32_t Rn
= sim
->get_reg_mode(sim
, instruction
.info
.load_store_multiple
.Rn
);
619 uint32_t load_values
[16];
622 for (i
= 0; i
< 16; i
++)
624 if (instruction
.info
.load_store_multiple
.register_list
& (1 << i
))
628 switch (instruction
.info
.load_store_multiple
.addressing_mode
)
630 case 0: /* Increment after */
633 case 1: /* Increment before */
636 case 2: /* Decrement after */
637 Rn
= Rn
- (bits_set
* 4) + 4;
639 case 3: /* Decrement before */
640 Rn
= Rn
- (bits_set
* 4);
644 for (i
= 0; i
< 16; i
++)
646 if (instruction
.info
.load_store_multiple
.register_list
& (1 << i
))
648 if ((!dry_run_pc
) || (i
== 15))
650 target_read_u32(target
, Rn
, &load_values
[i
]);
658 if (instruction
.info
.load_store_multiple
.register_list
& 0x8000)
660 *dry_run_pc
= load_values
[15] & ~1;
666 enum armv4_5_mode mode
= sim
->get_mode(sim
);
669 if (instruction
.info
.load_store_multiple
.S
)
671 if (instruction
.info
.load_store_multiple
.register_list
& 0x8000)
674 mode
= ARMV4_5_MODE_USR
;
677 for (i
= 0; i
< 16; i
++)
679 if (instruction
.info
.load_store_multiple
.register_list
& (1 << i
))
682 uint32_t val
= load_values
[i
];
683 sim
->set_reg_mode(sim
, i
, val
& ~1);
685 sim
->set_state(sim
, ARMV4_5_STATE_THUMB
);
687 sim
->set_state(sim
, ARMV4_5_STATE_ARM
);
689 sim
->set_reg_mode(sim
, i
, load_values
[i
]);
696 uint32_t spsr
= sim
->get_reg_mode(sim
, 16);
697 sim
->set_reg(sim
, ARMV4_5_CPSR
, spsr
);
700 /* base register writeback */
701 if (instruction
.info
.load_store_multiple
.W
)
702 sim
->set_reg_mode(sim
, instruction
.info
.load_store_multiple
.Rn
, Rn
);
704 if (instruction
.info
.load_store_multiple
.register_list
& 0x8000)
708 /* store multiple instruction */
709 else if (instruction
.type
== ARM_STM
)
715 /* STM wont affect PC (advance by instruction size */
719 uint32_t Rn
= sim
->get_reg_mode(sim
,
720 instruction
.info
.load_store_multiple
.Rn
);
722 enum armv4_5_mode mode
= sim
->get_mode(sim
);
724 for (i
= 0; i
< 16; i
++)
726 if (instruction
.info
.load_store_multiple
.register_list
& (1 << i
))
730 if (instruction
.info
.load_store_multiple
.S
)
732 mode
= ARMV4_5_MODE_USR
;
735 switch (instruction
.info
.load_store_multiple
.addressing_mode
)
737 case 0: /* Increment after */
740 case 1: /* Increment before */
743 case 2: /* Decrement after */
744 Rn
= Rn
- (bits_set
* 4) + 4;
746 case 3: /* Decrement before */
747 Rn
= Rn
- (bits_set
* 4);
751 for (i
= 0; i
< 16; i
++)
753 if (instruction
.info
.load_store_multiple
.register_list
& (1 << i
))
755 target_write_u32(target
, Rn
, sim
->get_reg_mode(sim
, i
));
760 /* base register writeback */
761 if (instruction
.info
.load_store_multiple
.W
)
762 sim
->set_reg_mode(sim
,
763 instruction
.info
.load_store_multiple
.Rn
, Rn
);
767 else if (!dry_run_pc
)
769 /* the instruction wasn't handled, but we're supposed to simulate it
771 LOG_ERROR("Unimplemented instruction, could not simulate it.");
777 *dry_run_pc
= current_pc
+ instruction_size
;
782 sim
->set_reg(sim
, 15, current_pc
+ instruction_size
);
788 static uint32_t armv4_5_get_reg(struct arm_sim_interface
*sim
, int reg
)
790 struct arm
*armv4_5
= (struct arm
*)sim
->user_data
;
792 return buf_get_u32(armv4_5
->core_cache
->reg_list
[reg
].value
, 0, 32);
795 static void armv4_5_set_reg(struct arm_sim_interface
*sim
, int reg
, uint32_t value
)
797 struct arm
*armv4_5
= (struct arm
*)sim
->user_data
;
799 buf_set_u32(armv4_5
->core_cache
->reg_list
[reg
].value
, 0, 32, value
);
802 static uint32_t armv4_5_get_reg_mode(struct arm_sim_interface
*sim
, int reg
)
804 struct arm
*armv4_5
= (struct arm
*)sim
->user_data
;
806 return buf_get_u32(ARMV4_5_CORE_REG_MODE(armv4_5
->core_cache
,
807 armv4_5
->core_mode
, reg
).value
, 0, 32);
810 static void armv4_5_set_reg_mode(struct arm_sim_interface
*sim
, int reg
, uint32_t value
)
812 struct arm
*armv4_5
= (struct arm
*)sim
->user_data
;
814 buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5
->core_cache
,
815 armv4_5
->core_mode
, reg
).value
, 0, 32, value
);
818 static uint32_t armv4_5_get_cpsr(struct arm_sim_interface
*sim
, int pos
, int bits
)
820 struct arm
*armv4_5
= (struct arm
*)sim
->user_data
;
822 return buf_get_u32(armv4_5
->core_cache
->reg_list
[ARMV4_5_CPSR
].value
, pos
, bits
);
825 static enum armv4_5_state
armv4_5_get_state(struct arm_sim_interface
*sim
)
827 struct arm
*armv4_5
= (struct arm
*)sim
->user_data
;
829 return armv4_5
->core_state
;
832 static void armv4_5_set_state(struct arm_sim_interface
*sim
, enum armv4_5_state mode
)
834 struct arm
*armv4_5
= (struct arm
*)sim
->user_data
;
836 armv4_5
->core_state
= mode
;
840 static enum armv4_5_mode
armv4_5_get_mode(struct arm_sim_interface
*sim
)
842 struct arm
*armv4_5
= (struct arm
*)sim
->user_data
;
844 return armv4_5
->core_mode
;
849 int arm_simulate_step(struct target
*target
, uint32_t *dry_run_pc
)
851 struct armv4_5_common_s
*armv4_5
= target_to_armv4_5(target
);
852 struct arm_sim_interface sim
;
854 sim
.user_data
= armv4_5
;
855 sim
.get_reg
= &armv4_5_get_reg
;
856 sim
.set_reg
= &armv4_5_set_reg
;
857 sim
.get_reg_mode
= &armv4_5_get_reg_mode
;
858 sim
.set_reg_mode
= &armv4_5_set_reg_mode
;
859 sim
.get_cpsr
= &armv4_5_get_cpsr
;
860 sim
.get_mode
= &armv4_5_get_mode
;
861 sim
.get_state
= &armv4_5_get_state
;
862 sim
.set_state
= &armv4_5_set_state
;
864 return arm_simulate_step_core(target
, dry_run_pc
, &sim
);
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)