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"
35 static uint32_t arm_shift(uint8_t shift
, uint32_t Rm
,
36 uint32_t shift_amount
, uint8_t *carry
)
38 uint32_t return_value
= 0;
41 if (shift
== 0x0) /* LSL */
43 if ((shift_amount
> 0) && (shift_amount
<= 32))
45 return_value
= Rm
<< shift_amount
;
46 *carry
= Rm
>> (32 - shift_amount
);
48 else if (shift_amount
> 32)
53 else /* (shift_amount == 0) */
58 else if (shift
== 0x1) /* LSR */
60 if ((shift_amount
> 0) && (shift_amount
<= 32))
62 return_value
= Rm
>> shift_amount
;
63 *carry
= (Rm
>> (shift_amount
- 1)) & 1;
65 else if (shift_amount
> 32)
70 else /* (shift_amount == 0) */
75 else if (shift
== 0x2) /* ASR */
77 if ((shift_amount
> 0) && (shift_amount
<= 32))
79 /* C right shifts of unsigned values are guaranteed to
80 * be logical (shift in zeroes); simulate an arithmetic
81 * shift (shift in signed-bit) by adding the sign bit
84 return_value
= Rm
>> shift_amount
;
86 return_value
|= 0xffffffff << (32 - shift_amount
);
88 else if (shift_amount
> 32)
92 return_value
= 0xffffffff;
101 else /* (shift_amount == 0) */
106 else if (shift
== 0x3) /* ROR */
108 if (shift_amount
== 0)
114 shift_amount
= shift_amount
% 32;
115 return_value
= (Rm
>> shift_amount
) | (Rm
<< (32 - shift_amount
));
116 *carry
= (return_value
>> 31) & 0x1;
119 else if (shift
== 0x4) /* RRX */
121 return_value
= Rm
>> 1;
131 static uint32_t arm_shifter_operand(struct arm_sim_interface
*sim
,
132 int variant
, union arm_shifter_operand shifter_operand
,
133 uint8_t *shifter_carry_out
)
135 uint32_t return_value
;
136 int instruction_size
;
138 if (sim
->get_state(sim
) == ARMV4_5_STATE_ARM
)
139 instruction_size
= 4;
141 instruction_size
= 2;
143 *shifter_carry_out
= sim
->get_cpsr(sim
, 29, 1);
145 if (variant
== 0) /* 32-bit immediate */
147 return_value
= shifter_operand
.immediate
.immediate
;
149 else if (variant
== 1) /* immediate shift */
151 uint32_t Rm
= sim
->get_reg_mode(sim
, shifter_operand
.immediate_shift
.Rm
);
153 /* adjust RM in case the PC is being read */
154 if (shifter_operand
.immediate_shift
.Rm
== 15)
155 Rm
+= 2 * instruction_size
;
157 return_value
= arm_shift(shifter_operand
.immediate_shift
.shift
,
158 Rm
, shifter_operand
.immediate_shift
.shift_imm
,
161 else if (variant
== 2) /* register shift */
163 uint32_t Rm
= sim
->get_reg_mode(sim
, shifter_operand
.register_shift
.Rm
);
164 uint32_t Rs
= sim
->get_reg_mode(sim
, shifter_operand
.register_shift
.Rs
);
166 /* adjust RM in case the PC is being read */
167 if (shifter_operand
.register_shift
.Rm
== 15)
168 Rm
+= 2 * instruction_size
;
170 return_value
= arm_shift(shifter_operand
.immediate_shift
.shift
,
171 Rm
, Rs
, shifter_carry_out
);
175 LOG_ERROR("BUG: shifter_operand.variant not 0, 1 or 2");
176 return_value
= 0xffffffff;
182 static int pass_condition(uint32_t cpsr
, uint32_t opcode
)
184 switch ((opcode
& 0xf0000000) >> 28)
187 if (cpsr
& 0x40000000)
192 if (!(cpsr
& 0x40000000))
197 if (cpsr
& 0x20000000)
202 if (!(cpsr
& 0x20000000))
207 if (cpsr
& 0x80000000)
212 if (!(cpsr
& 0x80000000))
217 if (cpsr
& 0x10000000)
222 if (!(cpsr
& 0x10000000))
227 if ((cpsr
& 0x20000000) && !(cpsr
& 0x40000000))
232 if (!(cpsr
& 0x20000000) || (cpsr
& 0x40000000))
237 if (((cpsr
& 0x80000000) && (cpsr
& 0x10000000))
238 || (!(cpsr
& 0x80000000) && !(cpsr
& 0x10000000)))
243 if (((cpsr
& 0x80000000) && !(cpsr
& 0x10000000))
244 || (!(cpsr
& 0x80000000) && (cpsr
& 0x10000000)))
249 if (!(cpsr
& 0x40000000) &&
250 (((cpsr
& 0x80000000) && (cpsr
& 0x10000000))
251 || (!(cpsr
& 0x80000000) && !(cpsr
& 0x10000000))))
256 if ((cpsr
& 0x40000000) ||
257 ((cpsr
& 0x80000000) && !(cpsr
& 0x10000000))
258 || (!(cpsr
& 0x80000000) && (cpsr
& 0x10000000)))
268 LOG_ERROR("BUG: should never get here");
272 static int thumb_pass_branch_condition(uint32_t cpsr
, uint16_t opcode
)
274 return pass_condition(cpsr
, (opcode
& 0x0f00) << 20);
277 /* simulate a single step (if possible)
278 * if the dry_run_pc argument is provided, no state is changed,
279 * but the new pc is stored in the variable pointed at by the argument
281 int arm_simulate_step_core(struct target
*target
,
282 uint32_t *dry_run_pc
, struct arm_sim_interface
*sim
)
284 uint32_t current_pc
= sim
->get_reg(sim
, 15);
285 struct arm_instruction instruction
;
286 int instruction_size
;
287 int retval
= ERROR_OK
;
289 if (sim
->get_state(sim
) == ARMV4_5_STATE_ARM
)
293 /* get current instruction, and identify it */
294 if ((retval
= target_read_u32(target
, current_pc
, &opcode
)) != ERROR_OK
)
298 if ((retval
= arm_evaluate_opcode(opcode
, current_pc
, &instruction
)) != ERROR_OK
)
302 instruction_size
= 4;
304 /* check condition code (for all instructions) */
305 if (!pass_condition(sim
->get_cpsr(sim
, 0, 32), opcode
))
309 *dry_run_pc
= current_pc
+ instruction_size
;
313 sim
->set_reg(sim
, 15, current_pc
+ instruction_size
);
323 retval
= target_read_u16(target
, current_pc
, &opcode
);
324 if (retval
!= ERROR_OK
)
326 retval
= thumb_evaluate_opcode(opcode
, current_pc
, &instruction
);
327 if (retval
!= ERROR_OK
)
329 instruction_size
= 2;
331 /* check condition code (only for branch (1) instructions) */
332 if ((opcode
& 0xf000) == 0xd000
333 && !thumb_pass_branch_condition(
334 sim
->get_cpsr(sim
, 0, 32), opcode
))
338 *dry_run_pc
= current_pc
+ instruction_size
;
342 sim
->set_reg(sim
, 15, current_pc
+ instruction_size
);
348 /* Deal with 32-bit BL/BLX */
349 if ((opcode
& 0xf800) == 0xf000) {
350 uint32_t high
= instruction
.info
.b_bl_bx_blx
.target_address
;
351 retval
= target_read_u16(target
, current_pc
+2, &opcode
);
352 if (retval
!= ERROR_OK
)
354 retval
= thumb_evaluate_opcode(opcode
, current_pc
, &instruction
);
355 if (retval
!= ERROR_OK
)
357 instruction
.info
.b_bl_bx_blx
.target_address
+= high
;
361 /* examine instruction type */
363 /* branch instructions */
364 if ((instruction
.type
>= ARM_B
) && (instruction
.type
<= ARM_BLX
))
368 if (instruction
.info
.b_bl_bx_blx
.reg_operand
== -1)
370 target
= instruction
.info
.b_bl_bx_blx
.target_address
;
374 target
= sim
->get_reg_mode(sim
, instruction
.info
.b_bl_bx_blx
.reg_operand
);
375 if (instruction
.info
.b_bl_bx_blx
.reg_operand
== 15)
377 target
+= 2 * instruction_size
;
383 *dry_run_pc
= target
& ~1;
388 if (instruction
.type
== ARM_B
)
390 sim
->set_reg(sim
, 15, target
);
392 else if (instruction
.type
== ARM_BL
)
394 uint32_t old_pc
= sim
->get_reg(sim
, 15);
395 int T
= (sim
->get_state(sim
) == ARMV4_5_STATE_THUMB
);
396 sim
->set_reg_mode(sim
, 14, old_pc
+ 4 + T
);
397 sim
->set_reg(sim
, 15, target
);
399 else if (instruction
.type
== ARM_BX
)
403 sim
->set_state(sim
, ARMV4_5_STATE_THUMB
);
407 sim
->set_state(sim
, ARMV4_5_STATE_ARM
);
409 sim
->set_reg(sim
, 15, target
& 0xfffffffe);
411 else if (instruction
.type
== ARM_BLX
)
413 uint32_t old_pc
= sim
->get_reg(sim
, 15);
414 int T
= (sim
->get_state(sim
) == ARMV4_5_STATE_THUMB
);
415 sim
->set_reg_mode(sim
, 14, old_pc
+ 4 + T
);
419 sim
->set_state(sim
, ARMV4_5_STATE_THUMB
);
423 sim
->set_state(sim
, ARMV4_5_STATE_ARM
);
425 sim
->set_reg(sim
, 15, target
& 0xfffffffe);
431 /* data processing instructions, except compare instructions (CMP, CMN, TST, TEQ) */
432 else if (((instruction
.type
>= ARM_AND
) && (instruction
.type
<= ARM_RSC
))
433 || ((instruction
.type
>= ARM_ORR
) && (instruction
.type
<= ARM_MVN
)))
435 uint32_t Rd
, Rn
, shifter_operand
;
436 uint8_t C
= sim
->get_cpsr(sim
, 29, 1);
440 /* ARM_MOV and ARM_MVN does not use Rn */
441 if ((instruction
.type
!= ARM_MOV
) && (instruction
.type
!= ARM_MVN
))
442 Rn
= sim
->get_reg_mode(sim
, instruction
.info
.data_proc
.Rn
);
446 shifter_operand
= arm_shifter_operand(sim
,
447 instruction
.info
.data_proc
.variant
,
448 instruction
.info
.data_proc
.shifter_operand
,
451 /* adjust Rn in case the PC is being read */
452 if (instruction
.info
.data_proc
.Rn
== 15)
453 Rn
+= 2 * instruction_size
;
455 if (instruction
.type
== ARM_AND
)
456 Rd
= Rn
& shifter_operand
;
457 else if (instruction
.type
== ARM_EOR
)
458 Rd
= Rn
^ shifter_operand
;
459 else if (instruction
.type
== ARM_SUB
)
460 Rd
= Rn
- shifter_operand
;
461 else if (instruction
.type
== ARM_RSB
)
462 Rd
= shifter_operand
- Rn
;
463 else if (instruction
.type
== ARM_ADD
)
464 Rd
= Rn
+ shifter_operand
;
465 else if (instruction
.type
== ARM_ADC
)
466 Rd
= Rn
+ shifter_operand
+ (C
& 1);
467 else if (instruction
.type
== ARM_SBC
)
468 Rd
= Rn
- shifter_operand
- (C
& 1) ? 0 : 1;
469 else if (instruction
.type
== ARM_RSC
)
470 Rd
= shifter_operand
- Rn
- (C
& 1) ? 0 : 1;
471 else if (instruction
.type
== ARM_ORR
)
472 Rd
= Rn
| shifter_operand
;
473 else if (instruction
.type
== ARM_BIC
)
474 Rd
= Rn
& ~(shifter_operand
);
475 else if (instruction
.type
== ARM_MOV
)
476 Rd
= shifter_operand
;
477 else if (instruction
.type
== ARM_MVN
)
478 Rd
= ~shifter_operand
;
480 LOG_WARNING("unhandled instruction type");
484 if (instruction
.info
.data_proc
.Rd
== 15)
485 *dry_run_pc
= Rd
& ~1;
487 *dry_run_pc
= current_pc
+ instruction_size
;
493 if (instruction
.info
.data_proc
.Rd
== 15) {
494 sim
->set_reg_mode(sim
, 15, Rd
& ~1);
496 sim
->set_state(sim
, ARMV4_5_STATE_THUMB
);
498 sim
->set_state(sim
, ARMV4_5_STATE_ARM
);
501 sim
->set_reg_mode(sim
, instruction
.info
.data_proc
.Rd
, Rd
);
502 LOG_WARNING("no updating of flags yet");
505 /* compare instructions (CMP, CMN, TST, TEQ) */
506 else if ((instruction
.type
>= ARM_TST
) && (instruction
.type
<= ARM_CMN
))
510 *dry_run_pc
= current_pc
+ instruction_size
;
515 LOG_WARNING("no updating of flags yet");
518 /* load register instructions */
519 else if ((instruction
.type
>= ARM_LDR
) && (instruction
.type
<= ARM_LDRSH
))
521 uint32_t load_address
= 0, modified_address
= 0, load_value
;
522 uint32_t Rn
= sim
->get_reg_mode(sim
, instruction
.info
.load_store
.Rn
);
524 /* adjust Rn in case the PC is being read */
525 if (instruction
.info
.load_store
.Rn
== 15)
526 Rn
+= 2 * instruction_size
;
528 if (instruction
.info
.load_store
.offset_mode
== 0)
530 if (instruction
.info
.load_store
.U
)
531 modified_address
= Rn
+ instruction
.info
.load_store
.offset
.offset
;
533 modified_address
= Rn
- instruction
.info
.load_store
.offset
.offset
;
535 else if (instruction
.info
.load_store
.offset_mode
== 1)
538 uint32_t Rm
= sim
->get_reg_mode(sim
,
539 instruction
.info
.load_store
.offset
.reg
.Rm
);
540 uint8_t shift
= instruction
.info
.load_store
.offset
.reg
.shift
;
541 uint8_t shift_imm
= instruction
.info
.load_store
.offset
.reg
.shift_imm
;
542 uint8_t carry
= sim
->get_cpsr(sim
, 29, 1);
544 offset
= arm_shift(shift
, Rm
, shift_imm
, &carry
);
546 if (instruction
.info
.load_store
.U
)
547 modified_address
= Rn
+ offset
;
549 modified_address
= Rn
- offset
;
553 LOG_ERROR("BUG: offset_mode neither 0 (offset) nor 1 (scaled register)");
556 if (instruction
.info
.load_store
.index_mode
== 0)
559 * we load from the modified address, but don't change
560 * the base address register
562 load_address
= modified_address
;
563 modified_address
= Rn
;
565 else if (instruction
.info
.load_store
.index_mode
== 1)
568 * we load from the modified address, and write it
569 * back to the base address register
571 load_address
= modified_address
;
573 else if (instruction
.info
.load_store
.index_mode
== 2)
576 * we load from the unmodified address, and write the
577 * modified address back
582 if ((!dry_run_pc
) || (instruction
.info
.load_store
.Rd
== 15))
584 retval
= target_read_u32(target
, load_address
, &load_value
);
585 if (retval
!= ERROR_OK
)
591 if (instruction
.info
.load_store
.Rd
== 15)
592 *dry_run_pc
= load_value
& ~1;
594 *dry_run_pc
= current_pc
+ instruction_size
;
599 if ((instruction
.info
.load_store
.index_mode
== 1) ||
600 (instruction
.info
.load_store
.index_mode
== 2))
602 sim
->set_reg_mode(sim
, instruction
.info
.load_store
.Rn
, modified_address
);
605 if (instruction
.info
.load_store
.Rd
== 15) {
606 sim
->set_reg_mode(sim
, 15, load_value
& ~1);
608 sim
->set_state(sim
, ARMV4_5_STATE_THUMB
);
610 sim
->set_state(sim
, ARMV4_5_STATE_ARM
);
613 sim
->set_reg_mode(sim
, instruction
.info
.load_store
.Rd
, load_value
);
616 /* load multiple instruction */
617 else if (instruction
.type
== ARM_LDM
)
620 uint32_t Rn
= sim
->get_reg_mode(sim
, instruction
.info
.load_store_multiple
.Rn
);
621 uint32_t load_values
[16];
624 for (i
= 0; i
< 16; i
++)
626 if (instruction
.info
.load_store_multiple
.register_list
& (1 << i
))
630 switch (instruction
.info
.load_store_multiple
.addressing_mode
)
632 case 0: /* Increment after */
635 case 1: /* Increment before */
638 case 2: /* Decrement after */
639 Rn
= Rn
- (bits_set
* 4) + 4;
641 case 3: /* Decrement before */
642 Rn
= Rn
- (bits_set
* 4);
646 for (i
= 0; i
< 16; i
++)
648 if (instruction
.info
.load_store_multiple
.register_list
& (1 << i
))
650 if ((!dry_run_pc
) || (i
== 15))
652 target_read_u32(target
, Rn
, &load_values
[i
]);
660 if (instruction
.info
.load_store_multiple
.register_list
& 0x8000)
662 *dry_run_pc
= load_values
[15] & ~1;
668 enum armv4_5_mode mode
= sim
->get_mode(sim
);
671 if (instruction
.info
.load_store_multiple
.S
)
673 if (instruction
.info
.load_store_multiple
.register_list
& 0x8000)
676 mode
= ARMV4_5_MODE_USR
;
679 for (i
= 0; i
< 16; i
++)
681 if (instruction
.info
.load_store_multiple
.register_list
& (1 << i
))
684 uint32_t val
= load_values
[i
];
685 sim
->set_reg_mode(sim
, i
, val
& ~1);
687 sim
->set_state(sim
, ARMV4_5_STATE_THUMB
);
689 sim
->set_state(sim
, ARMV4_5_STATE_ARM
);
691 sim
->set_reg_mode(sim
, i
, load_values
[i
]);
698 uint32_t spsr
= sim
->get_reg_mode(sim
, 16);
699 sim
->set_reg(sim
, ARMV4_5_CPSR
, spsr
);
702 /* base register writeback */
703 if (instruction
.info
.load_store_multiple
.W
)
704 sim
->set_reg_mode(sim
, instruction
.info
.load_store_multiple
.Rn
, Rn
);
706 if (instruction
.info
.load_store_multiple
.register_list
& 0x8000)
710 /* store multiple instruction */
711 else if (instruction
.type
== ARM_STM
)
717 /* STM wont affect PC (advance by instruction size */
721 uint32_t Rn
= sim
->get_reg_mode(sim
,
722 instruction
.info
.load_store_multiple
.Rn
);
724 enum armv4_5_mode mode
= sim
->get_mode(sim
);
726 for (i
= 0; i
< 16; i
++)
728 if (instruction
.info
.load_store_multiple
.register_list
& (1 << i
))
732 if (instruction
.info
.load_store_multiple
.S
)
734 mode
= ARMV4_5_MODE_USR
;
737 switch (instruction
.info
.load_store_multiple
.addressing_mode
)
739 case 0: /* Increment after */
742 case 1: /* Increment before */
745 case 2: /* Decrement after */
746 Rn
= Rn
- (bits_set
* 4) + 4;
748 case 3: /* Decrement before */
749 Rn
= Rn
- (bits_set
* 4);
753 for (i
= 0; i
< 16; i
++)
755 if (instruction
.info
.load_store_multiple
.register_list
& (1 << i
))
757 target_write_u32(target
, Rn
, sim
->get_reg_mode(sim
, i
));
762 /* base register writeback */
763 if (instruction
.info
.load_store_multiple
.W
)
764 sim
->set_reg_mode(sim
,
765 instruction
.info
.load_store_multiple
.Rn
, Rn
);
769 else if (!dry_run_pc
)
771 /* the instruction wasn't handled, but we're supposed to simulate it
773 LOG_ERROR("Unimplemented instruction, could not simulate it.");
779 *dry_run_pc
= current_pc
+ instruction_size
;
784 sim
->set_reg(sim
, 15, current_pc
+ instruction_size
);
790 static uint32_t armv4_5_get_reg(struct arm_sim_interface
*sim
, int reg
)
792 struct arm
*armv4_5
= (struct arm
*)sim
->user_data
;
794 return buf_get_u32(armv4_5
->core_cache
->reg_list
[reg
].value
, 0, 32);
797 static void armv4_5_set_reg(struct arm_sim_interface
*sim
, int reg
, uint32_t value
)
799 struct arm
*armv4_5
= (struct arm
*)sim
->user_data
;
801 buf_set_u32(armv4_5
->core_cache
->reg_list
[reg
].value
, 0, 32, value
);
804 static uint32_t armv4_5_get_reg_mode(struct arm_sim_interface
*sim
, int reg
)
806 struct arm
*armv4_5
= (struct arm
*)sim
->user_data
;
808 return buf_get_u32(ARMV4_5_CORE_REG_MODE(armv4_5
->core_cache
,
809 armv4_5
->core_mode
, reg
).value
, 0, 32);
812 static void armv4_5_set_reg_mode(struct arm_sim_interface
*sim
, int reg
, uint32_t value
)
814 struct arm
*armv4_5
= (struct arm
*)sim
->user_data
;
816 buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5
->core_cache
,
817 armv4_5
->core_mode
, reg
).value
, 0, 32, value
);
820 static uint32_t armv4_5_get_cpsr(struct arm_sim_interface
*sim
, int pos
, int bits
)
822 struct arm
*armv4_5
= (struct arm
*)sim
->user_data
;
824 return buf_get_u32(armv4_5
->cpsr
->value
, pos
, bits
);
827 static enum armv4_5_state
armv4_5_get_state(struct arm_sim_interface
*sim
)
829 struct arm
*armv4_5
= (struct arm
*)sim
->user_data
;
831 return armv4_5
->core_state
;
834 static void armv4_5_set_state(struct arm_sim_interface
*sim
, enum armv4_5_state mode
)
836 struct arm
*armv4_5
= (struct arm
*)sim
->user_data
;
838 armv4_5
->core_state
= mode
;
842 static enum armv4_5_mode
armv4_5_get_mode(struct arm_sim_interface
*sim
)
844 struct arm
*armv4_5
= (struct arm
*)sim
->user_data
;
846 return armv4_5
->core_mode
;
851 int arm_simulate_step(struct target
*target
, uint32_t *dry_run_pc
)
853 struct arm
*armv4_5
= target_to_armv4_5(target
);
854 struct arm_sim_interface sim
;
856 sim
.user_data
= armv4_5
;
857 sim
.get_reg
= &armv4_5_get_reg
;
858 sim
.set_reg
= &armv4_5_set_reg
;
859 sim
.get_reg_mode
= &armv4_5_get_reg_mode
;
860 sim
.set_reg_mode
= &armv4_5_set_reg_mode
;
861 sim
.get_cpsr
= &armv4_5_get_cpsr
;
862 sim
.get_mode
= &armv4_5_get_mode
;
863 sim
.get_state
= &armv4_5_get_state
;
864 sim
.set_state
= &armv4_5_set_state
;
866 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)