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"
31 #include "binarybuffer.h"
34 static uint32_t arm_shift(uint8_t shift
, uint32_t Rm
,
35 uint32_t shift_amount
, uint8_t *carry
)
37 uint32_t return_value
= 0;
40 if (shift
== 0x0) /* LSL */
42 if ((shift_amount
> 0) && (shift_amount
<= 32))
44 return_value
= Rm
<< shift_amount
;
45 *carry
= Rm
>> (32 - shift_amount
);
47 else if (shift_amount
> 32)
52 else /* (shift_amount == 0) */
57 else if (shift
== 0x1) /* LSR */
59 if ((shift_amount
> 0) && (shift_amount
<= 32))
61 return_value
= Rm
>> shift_amount
;
62 *carry
= (Rm
>> (shift_amount
- 1)) & 1;
64 else if (shift_amount
> 32)
69 else /* (shift_amount == 0) */
74 else if (shift
== 0x2) /* ASR */
76 if ((shift_amount
> 0) && (shift_amount
<= 32))
78 /* C right shifts of unsigned values are guaranteed to
79 * be logical (shift in zeroes); simulate an arithmetic
80 * shift (shift in signed-bit) by adding the sign bit
83 return_value
= Rm
>> shift_amount
;
85 return_value
|= 0xffffffff << (32 - shift_amount
);
87 else if (shift_amount
> 32)
91 return_value
= 0xffffffff;
100 else /* (shift_amount == 0) */
105 else if (shift
== 0x3) /* ROR */
107 if (shift_amount
== 0)
113 shift_amount
= shift_amount
% 32;
114 return_value
= (Rm
>> shift_amount
) | (Rm
<< (32 - shift_amount
));
115 *carry
= (return_value
>> 31) & 0x1;
118 else if (shift
== 0x4) /* RRX */
120 return_value
= Rm
>> 1;
130 static uint32_t arm_shifter_operand(struct arm_sim_interface
*sim
,
131 int variant
, union arm_shifter_operand shifter_operand
,
132 uint8_t *shifter_carry_out
)
134 uint32_t return_value
;
135 int instruction_size
;
137 if (sim
->get_state(sim
) == ARMV4_5_STATE_ARM
)
138 instruction_size
= 4;
140 instruction_size
= 2;
142 *shifter_carry_out
= sim
->get_cpsr(sim
, 29, 1);
144 if (variant
== 0) /* 32-bit immediate */
146 return_value
= shifter_operand
.immediate
.immediate
;
148 else if (variant
== 1) /* immediate shift */
150 uint32_t Rm
= sim
->get_reg_mode(sim
, shifter_operand
.immediate_shift
.Rm
);
152 /* adjust RM in case the PC is being read */
153 if (shifter_operand
.immediate_shift
.Rm
== 15)
154 Rm
+= 2 * instruction_size
;
156 return_value
= arm_shift(shifter_operand
.immediate_shift
.shift
,
157 Rm
, shifter_operand
.immediate_shift
.shift_imm
,
160 else if (variant
== 2) /* register shift */
162 uint32_t Rm
= sim
->get_reg_mode(sim
, shifter_operand
.register_shift
.Rm
);
163 uint32_t Rs
= sim
->get_reg_mode(sim
, shifter_operand
.register_shift
.Rs
);
165 /* adjust RM in case the PC is being read */
166 if (shifter_operand
.register_shift
.Rm
== 15)
167 Rm
+= 2 * instruction_size
;
169 return_value
= arm_shift(shifter_operand
.immediate_shift
.shift
,
170 Rm
, Rs
, shifter_carry_out
);
174 LOG_ERROR("BUG: shifter_operand.variant not 0, 1 or 2");
175 return_value
= 0xffffffff;
181 static int pass_condition(uint32_t cpsr
, uint32_t opcode
)
183 switch ((opcode
& 0xf0000000) >> 28)
186 if (cpsr
& 0x40000000)
191 if (!(cpsr
& 0x40000000))
196 if (cpsr
& 0x20000000)
201 if (!(cpsr
& 0x20000000))
206 if (cpsr
& 0x80000000)
211 if (!(cpsr
& 0x80000000))
216 if (cpsr
& 0x10000000)
221 if (!(cpsr
& 0x10000000))
226 if ((cpsr
& 0x20000000) && !(cpsr
& 0x40000000))
231 if (!(cpsr
& 0x20000000) || (cpsr
& 0x40000000))
236 if (((cpsr
& 0x80000000) && (cpsr
& 0x10000000))
237 || (!(cpsr
& 0x80000000) && !(cpsr
& 0x10000000)))
242 if (((cpsr
& 0x80000000) && !(cpsr
& 0x10000000))
243 || (!(cpsr
& 0x80000000) && (cpsr
& 0x10000000)))
248 if (!(cpsr
& 0x40000000) &&
249 (((cpsr
& 0x80000000) && (cpsr
& 0x10000000))
250 || (!(cpsr
& 0x80000000) && !(cpsr
& 0x10000000))))
255 if ((cpsr
& 0x40000000) ||
256 ((cpsr
& 0x80000000) && !(cpsr
& 0x10000000))
257 || (!(cpsr
& 0x80000000) && (cpsr
& 0x10000000)))
267 LOG_ERROR("BUG: should never get here");
271 static int thumb_pass_branch_condition(uint32_t cpsr
, uint16_t opcode
)
273 return pass_condition(cpsr
, (opcode
& 0x0f00) << 20);
276 /* simulate a single step (if possible)
277 * if the dry_run_pc argument is provided, no state is changed,
278 * but the new pc is stored in the variable pointed at by the argument
280 int arm_simulate_step_core(target_t
*target
,
281 uint32_t *dry_run_pc
, struct arm_sim_interface
*sim
)
283 uint32_t current_pc
= sim
->get_reg(sim
, 15);
284 arm_instruction_t instruction
;
285 int instruction_size
;
286 int retval
= ERROR_OK
;
288 if (sim
->get_state(sim
) == ARMV4_5_STATE_ARM
)
292 /* get current instruction, and identify it */
293 if ((retval
= target_read_u32(target
, current_pc
, &opcode
)) != ERROR_OK
)
297 if ((retval
= arm_evaluate_opcode(opcode
, current_pc
, &instruction
)) != ERROR_OK
)
301 instruction_size
= 4;
303 /* check condition code (for all instructions) */
304 if (!pass_condition(sim
->get_cpsr(sim
, 0, 32), opcode
))
308 *dry_run_pc
= current_pc
+ instruction_size
;
312 sim
->set_reg(sim
, 15, current_pc
+ instruction_size
);
322 retval
= target_read_u16(target
, current_pc
, &opcode
);
323 if (retval
!= ERROR_OK
)
325 retval
= thumb_evaluate_opcode(opcode
, current_pc
, &instruction
);
326 if (retval
!= ERROR_OK
)
328 instruction_size
= 2;
330 /* check condition code (only for branch (1) instructions) */
331 if ((opcode
& 0xf000) == 0xd000
332 && !thumb_pass_branch_condition(
333 sim
->get_cpsr(sim
, 0, 32), opcode
))
337 *dry_run_pc
= current_pc
+ instruction_size
;
341 sim
->set_reg(sim
, 15, current_pc
+ instruction_size
);
347 /* Deal with 32-bit BL/BLX */
348 if ((opcode
& 0xf800) == 0xf000) {
349 uint32_t high
= instruction
.info
.b_bl_bx_blx
.target_address
;
350 retval
= target_read_u16(target
, current_pc
+2, &opcode
);
351 if (retval
!= ERROR_OK
)
353 retval
= thumb_evaluate_opcode(opcode
, current_pc
, &instruction
);
354 if (retval
!= ERROR_OK
)
356 instruction
.info
.b_bl_bx_blx
.target_address
+= high
;
360 /* examine instruction type */
362 /* branch instructions */
363 if ((instruction
.type
>= ARM_B
) && (instruction
.type
<= ARM_BLX
))
367 if (instruction
.info
.b_bl_bx_blx
.reg_operand
== -1)
369 target
= instruction
.info
.b_bl_bx_blx
.target_address
;
373 target
= sim
->get_reg_mode(sim
, instruction
.info
.b_bl_bx_blx
.reg_operand
);
374 if (instruction
.info
.b_bl_bx_blx
.reg_operand
== 15)
376 target
+= 2 * instruction_size
;
382 *dry_run_pc
= target
& ~1;
387 if (instruction
.type
== ARM_B
)
389 sim
->set_reg(sim
, 15, target
);
391 else if (instruction
.type
== ARM_BL
)
393 uint32_t old_pc
= sim
->get_reg(sim
, 15);
394 int T
= (sim
->get_state(sim
) == ARMV4_5_STATE_THUMB
);
395 sim
->set_reg_mode(sim
, 14, old_pc
+ 4 + T
);
396 sim
->set_reg(sim
, 15, target
);
398 else if (instruction
.type
== ARM_BX
)
402 sim
->set_state(sim
, ARMV4_5_STATE_THUMB
);
406 sim
->set_state(sim
, ARMV4_5_STATE_ARM
);
408 sim
->set_reg(sim
, 15, target
& 0xfffffffe);
410 else if (instruction
.type
== ARM_BLX
)
412 uint32_t old_pc
= sim
->get_reg(sim
, 15);
413 int T
= (sim
->get_state(sim
) == ARMV4_5_STATE_THUMB
);
414 sim
->set_reg_mode(sim
, 14, old_pc
+ 4 + T
);
418 sim
->set_state(sim
, ARMV4_5_STATE_THUMB
);
422 sim
->set_state(sim
, ARMV4_5_STATE_ARM
);
424 sim
->set_reg(sim
, 15, target
& 0xfffffffe);
430 /* data processing instructions, except compare instructions (CMP, CMN, TST, TEQ) */
431 else if (((instruction
.type
>= ARM_AND
) && (instruction
.type
<= ARM_RSC
))
432 || ((instruction
.type
>= ARM_ORR
) && (instruction
.type
<= ARM_MVN
)))
434 uint32_t Rd
, Rn
, shifter_operand
;
435 uint8_t C
= sim
->get_cpsr(sim
, 29, 1);
439 /* ARM_MOV and ARM_MVN does not use Rn */
440 if ((instruction
.type
!= ARM_MOV
) && (instruction
.type
!= ARM_MVN
))
441 Rn
= sim
->get_reg_mode(sim
, instruction
.info
.data_proc
.Rn
);
445 shifter_operand
= arm_shifter_operand(sim
,
446 instruction
.info
.data_proc
.variant
,
447 instruction
.info
.data_proc
.shifter_operand
,
450 /* adjust Rn in case the PC is being read */
451 if (instruction
.info
.data_proc
.Rn
== 15)
452 Rn
+= 2 * instruction_size
;
454 if (instruction
.type
== ARM_AND
)
455 Rd
= Rn
& shifter_operand
;
456 else if (instruction
.type
== ARM_EOR
)
457 Rd
= Rn
^ shifter_operand
;
458 else if (instruction
.type
== ARM_SUB
)
459 Rd
= Rn
- shifter_operand
;
460 else if (instruction
.type
== ARM_RSB
)
461 Rd
= shifter_operand
- Rn
;
462 else if (instruction
.type
== ARM_ADD
)
463 Rd
= Rn
+ shifter_operand
;
464 else if (instruction
.type
== ARM_ADC
)
465 Rd
= Rn
+ shifter_operand
+ (C
& 1);
466 else if (instruction
.type
== ARM_SBC
)
467 Rd
= Rn
- shifter_operand
- (C
& 1) ? 0 : 1;
468 else if (instruction
.type
== ARM_RSC
)
469 Rd
= shifter_operand
- Rn
- (C
& 1) ? 0 : 1;
470 else if (instruction
.type
== ARM_ORR
)
471 Rd
= Rn
| shifter_operand
;
472 else if (instruction
.type
== ARM_BIC
)
473 Rd
= Rn
& ~(shifter_operand
);
474 else if (instruction
.type
== ARM_MOV
)
475 Rd
= shifter_operand
;
476 else if (instruction
.type
== ARM_MVN
)
477 Rd
= ~shifter_operand
;
479 LOG_WARNING("unhandled instruction type");
483 if (instruction
.info
.data_proc
.Rd
== 15)
484 *dry_run_pc
= Rd
& ~1;
486 *dry_run_pc
= current_pc
+ instruction_size
;
492 if (instruction
.info
.data_proc
.Rd
== 15) {
493 sim
->set_reg_mode(sim
, 15, Rd
& ~1);
495 sim
->set_state(sim
, ARMV4_5_STATE_THUMB
);
497 sim
->set_state(sim
, ARMV4_5_STATE_ARM
);
500 sim
->set_reg_mode(sim
, instruction
.info
.data_proc
.Rd
, Rd
);
501 LOG_WARNING("no updating of flags yet");
504 /* compare instructions (CMP, CMN, TST, TEQ) */
505 else if ((instruction
.type
>= ARM_TST
) && (instruction
.type
<= ARM_CMN
))
509 *dry_run_pc
= current_pc
+ instruction_size
;
514 LOG_WARNING("no updating of flags yet");
517 /* load register instructions */
518 else if ((instruction
.type
>= ARM_LDR
) && (instruction
.type
<= ARM_LDRSH
))
520 uint32_t load_address
= 0, modified_address
= 0, load_value
;
521 uint32_t Rn
= sim
->get_reg_mode(sim
, instruction
.info
.load_store
.Rn
);
523 /* adjust Rn in case the PC is being read */
524 if (instruction
.info
.load_store
.Rn
== 15)
525 Rn
+= 2 * instruction_size
;
527 if (instruction
.info
.load_store
.offset_mode
== 0)
529 if (instruction
.info
.load_store
.U
)
530 modified_address
= Rn
+ instruction
.info
.load_store
.offset
.offset
;
532 modified_address
= Rn
- instruction
.info
.load_store
.offset
.offset
;
534 else if (instruction
.info
.load_store
.offset_mode
== 1)
537 uint32_t Rm
= sim
->get_reg_mode(sim
,
538 instruction
.info
.load_store
.offset
.reg
.Rm
);
539 uint8_t shift
= instruction
.info
.load_store
.offset
.reg
.shift
;
540 uint8_t shift_imm
= instruction
.info
.load_store
.offset
.reg
.shift_imm
;
541 uint8_t carry
= sim
->get_cpsr(sim
, 29, 1);
543 offset
= arm_shift(shift
, Rm
, shift_imm
, &carry
);
545 if (instruction
.info
.load_store
.U
)
546 modified_address
= Rn
+ offset
;
548 modified_address
= Rn
- offset
;
552 LOG_ERROR("BUG: offset_mode neither 0 (offset) nor 1 (scaled register)");
555 if (instruction
.info
.load_store
.index_mode
== 0)
558 * we load from the modified address, but don't change
559 * the base address register
561 load_address
= modified_address
;
562 modified_address
= Rn
;
564 else if (instruction
.info
.load_store
.index_mode
== 1)
567 * we load from the modified address, and write it
568 * back to the base address register
570 load_address
= modified_address
;
572 else if (instruction
.info
.load_store
.index_mode
== 2)
575 * we load from the unmodified address, and write the
576 * modified address back
581 if ((!dry_run_pc
) || (instruction
.info
.load_store
.Rd
== 15))
583 retval
= target_read_u32(target
, load_address
, &load_value
);
584 if (retval
!= ERROR_OK
)
590 if (instruction
.info
.load_store
.Rd
== 15)
591 *dry_run_pc
= load_value
& ~1;
593 *dry_run_pc
= current_pc
+ instruction_size
;
598 if ((instruction
.info
.load_store
.index_mode
== 1) ||
599 (instruction
.info
.load_store
.index_mode
== 2))
601 sim
->set_reg_mode(sim
, instruction
.info
.load_store
.Rn
, modified_address
);
604 if (instruction
.info
.load_store
.Rd
== 15) {
605 sim
->set_reg_mode(sim
, 15, load_value
& ~1);
607 sim
->set_state(sim
, ARMV4_5_STATE_THUMB
);
609 sim
->set_state(sim
, ARMV4_5_STATE_ARM
);
612 sim
->set_reg_mode(sim
, instruction
.info
.load_store
.Rd
, load_value
);
615 /* load multiple instruction */
616 else if (instruction
.type
== ARM_LDM
)
619 uint32_t Rn
= sim
->get_reg_mode(sim
, instruction
.info
.load_store_multiple
.Rn
);
620 uint32_t load_values
[16];
623 for (i
= 0; i
< 16; i
++)
625 if (instruction
.info
.load_store_multiple
.register_list
& (1 << i
))
629 switch (instruction
.info
.load_store_multiple
.addressing_mode
)
631 case 0: /* Increment after */
634 case 1: /* Increment before */
637 case 2: /* Decrement after */
638 Rn
= Rn
- (bits_set
* 4) + 4;
640 case 3: /* Decrement before */
641 Rn
= Rn
- (bits_set
* 4);
645 for (i
= 0; i
< 16; i
++)
647 if (instruction
.info
.load_store_multiple
.register_list
& (1 << i
))
649 if ((!dry_run_pc
) || (i
== 15))
651 target_read_u32(target
, Rn
, &load_values
[i
]);
659 if (instruction
.info
.load_store_multiple
.register_list
& 0x8000)
661 *dry_run_pc
= load_values
[15] & ~1;
667 enum armv4_5_mode mode
= sim
->get_mode(sim
);
670 if (instruction
.info
.load_store_multiple
.S
)
672 if (instruction
.info
.load_store_multiple
.register_list
& 0x8000)
675 mode
= ARMV4_5_MODE_USR
;
678 for (i
= 0; i
< 16; i
++)
680 if (instruction
.info
.load_store_multiple
.register_list
& (1 << i
))
683 uint32_t val
= load_values
[i
];
684 sim
->set_reg_mode(sim
, i
, val
& ~1);
686 sim
->set_state(sim
, ARMV4_5_STATE_THUMB
);
688 sim
->set_state(sim
, ARMV4_5_STATE_ARM
);
690 sim
->set_reg_mode(sim
, i
, load_values
[i
]);
697 uint32_t spsr
= sim
->get_reg_mode(sim
, 16);
698 sim
->set_reg(sim
, ARMV4_5_CPSR
, spsr
);
701 /* base register writeback */
702 if (instruction
.info
.load_store_multiple
.W
)
703 sim
->set_reg_mode(sim
, instruction
.info
.load_store_multiple
.Rn
, Rn
);
705 if (instruction
.info
.load_store_multiple
.register_list
& 0x8000)
709 /* store multiple instruction */
710 else if (instruction
.type
== ARM_STM
)
716 /* STM wont affect PC (advance by instruction size */
720 uint32_t Rn
= sim
->get_reg_mode(sim
,
721 instruction
.info
.load_store_multiple
.Rn
);
723 enum armv4_5_mode mode
= sim
->get_mode(sim
);
725 for (i
= 0; i
< 16; i
++)
727 if (instruction
.info
.load_store_multiple
.register_list
& (1 << i
))
731 if (instruction
.info
.load_store_multiple
.S
)
733 mode
= ARMV4_5_MODE_USR
;
736 switch (instruction
.info
.load_store_multiple
.addressing_mode
)
738 case 0: /* Increment after */
741 case 1: /* Increment before */
744 case 2: /* Decrement after */
745 Rn
= Rn
- (bits_set
* 4) + 4;
747 case 3: /* Decrement before */
748 Rn
= Rn
- (bits_set
* 4);
752 for (i
= 0; i
< 16; i
++)
754 if (instruction
.info
.load_store_multiple
.register_list
& (1 << i
))
756 target_write_u32(target
, Rn
, sim
->get_reg_mode(sim
, i
));
761 /* base register writeback */
762 if (instruction
.info
.load_store_multiple
.W
)
763 sim
->set_reg_mode(sim
,
764 instruction
.info
.load_store_multiple
.Rn
, Rn
);
768 else if (!dry_run_pc
)
770 /* the instruction wasn't handled, but we're supposed to simulate it
772 LOG_ERROR("Unimplemented instruction, could not simulate it.");
778 *dry_run_pc
= current_pc
+ instruction_size
;
783 sim
->set_reg(sim
, 15, current_pc
+ instruction_size
);
789 static uint32_t armv4_5_get_reg(struct arm_sim_interface
*sim
, int reg
)
791 armv4_5_common_t
*armv4_5
= (armv4_5_common_t
*)sim
->user_data
;
793 return buf_get_u32(armv4_5
->core_cache
->reg_list
[reg
].value
, 0, 32);
796 static void armv4_5_set_reg(struct arm_sim_interface
*sim
, int reg
, uint32_t value
)
798 armv4_5_common_t
*armv4_5
= (armv4_5_common_t
*)sim
->user_data
;
800 buf_set_u32(armv4_5
->core_cache
->reg_list
[reg
].value
, 0, 32, value
);
803 static uint32_t armv4_5_get_reg_mode(struct arm_sim_interface
*sim
, int reg
)
805 armv4_5_common_t
*armv4_5
= (armv4_5_common_t
*)sim
->user_data
;
807 return buf_get_u32(ARMV4_5_CORE_REG_MODE(armv4_5
->core_cache
,
808 armv4_5
->core_mode
, reg
).value
, 0, 32);
811 static void armv4_5_set_reg_mode(struct arm_sim_interface
*sim
, int reg
, uint32_t value
)
813 armv4_5_common_t
*armv4_5
= (armv4_5_common_t
*)sim
->user_data
;
815 buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5
->core_cache
,
816 armv4_5
->core_mode
, reg
).value
, 0, 32, value
);
819 static uint32_t armv4_5_get_cpsr(struct arm_sim_interface
*sim
, int pos
, int bits
)
821 armv4_5_common_t
*armv4_5
= (armv4_5_common_t
*)sim
->user_data
;
823 return buf_get_u32(armv4_5
->core_cache
->reg_list
[ARMV4_5_CPSR
].value
, pos
, bits
);
826 static enum armv4_5_state
armv4_5_get_state(struct arm_sim_interface
*sim
)
828 armv4_5_common_t
*armv4_5
= (armv4_5_common_t
*)sim
->user_data
;
830 return armv4_5
->core_state
;
833 static void armv4_5_set_state(struct arm_sim_interface
*sim
, enum armv4_5_state mode
)
835 armv4_5_common_t
*armv4_5
= (armv4_5_common_t
*)sim
->user_data
;
837 armv4_5
->core_state
= mode
;
841 static enum armv4_5_mode
armv4_5_get_mode(struct arm_sim_interface
*sim
)
843 armv4_5_common_t
*armv4_5
= (armv4_5_common_t
*)sim
->user_data
;
845 return armv4_5
->core_mode
;
850 int arm_simulate_step(target_t
*target
, uint32_t *dry_run_pc
)
852 struct armv4_5_common_s
*armv4_5
= target_to_armv4_5(target
);
853 struct arm_sim_interface sim
;
855 sim
.user_data
= armv4_5
;
856 sim
.get_reg
= &armv4_5_get_reg
;
857 sim
.set_reg
= &armv4_5_set_reg
;
858 sim
.get_reg_mode
= &armv4_5_get_reg_mode
;
859 sim
.set_reg_mode
= &armv4_5_set_reg_mode
;
860 sim
.get_cpsr
= &armv4_5_get_cpsr
;
861 sim
.get_mode
= &armv4_5_get_mode
;
862 sim
.get_state
= &armv4_5_get_state
;
863 sim
.set_state
= &armv4_5_set_state
;
865 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)