arm_dpm: flush both scratch registers (R0 and R1)
[openocd.git] / src / target / arm_dpm.c
index 55f253e464ff95e730541939b8d44de1d03d2021..f9b30c18722c8732d7d6db5934ac59ccec0f8041 100644 (file)
@@ -21,6 +21,7 @@
 
 #include "arm.h"
 #include "arm_dpm.h"
+#include "armv8_dpm.h"
 #include <jtag/jtag.h>
 #include "register.h"
 #include "breakpoints.h"
@@ -130,11 +131,47 @@ int dpm_modeswitch(struct arm_dpm *dpm, enum arm_mode mode)
        return retval;
 }
 
+/* Read 64bit VFP registers */
+static int dpm_read_reg_u64(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
+{
+       int retval = ERROR_FAIL;
+       uint32_t value_r0, value_r1;
+
+       switch (regnum) {
+               case ARM_VFP_V3_D0 ... ARM_VFP_V3_D31:
+                       /* move from double word register to r0:r1: "vmov r0, r1, vm"
+                        * then read r0 via dcc
+                        */
+                       retval = dpm->instr_read_data_r0(dpm,
+                               ARMV4_5_VMOV(1, 1, 0, ((regnum - ARM_VFP_V3_D0) >> 4),
+                               ((regnum - ARM_VFP_V3_D0) & 0xf)), &value_r0);
+                       /* read r1 via dcc */
+                       retval = dpm->instr_read_data_dcc(dpm,
+                               ARMV4_5_MCR(14, 0, 1, 0, 5, 0),
+                               &value_r1);
+                       break;
+               default:
+
+                       break;
+       }
+
+       if (retval == ERROR_OK) {
+               buf_set_u32(r->value, 0, 32, value_r0);
+               buf_set_u32(r->value + 4, 0, 32, value_r1);
+               r->valid = true;
+               r->dirty = false;
+               LOG_DEBUG("READ: %s, %8.8x, %8.8x", r->name,
+                               (unsigned) value_r0, (unsigned) value_r1);
+       }
+
+       return retval;
+}
 
-static int dpm_read_reg32(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
+/* just read the register -- rely on the core mode being right */
+static int dpm_read_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
 {
        uint32_t value;
-       int retval = ERROR_FAIL;
+       int retval;
 
        switch (regnum) {
                case 0 ... 14:
@@ -165,11 +202,19 @@ static int dpm_read_reg32(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
                                        /* core-specific ... ? */
                                        LOG_WARNING("Jazelle PC adjustment unknown");
                                        break;
-                               case ARM_STATE_AARCH64:
-                                       LOG_ERROR("AARCH64: 32bit read requested");
+                               default:
+                                       LOG_WARNING("unknow core state");
                                        break;
                        }
                        break;
+               case ARM_VFP_V3_D0 ... ARM_VFP_V3_D31:
+                       return dpm_read_reg_u64(dpm, r, regnum);
+                       break;
+               case ARM_VFP_V3_FPSCR:
+                       /* "VMRS r0, FPSCR"; then return via DCC */
+                       retval = dpm->instr_read_data_r0(dpm,
+                               ARMV4_5_VMRS(0), &value);
+                       break;
                default:
                        /* 16: "MRS r0, CPSR"; then return via DCC
                         * 17: "MRS r0, SPSR"; then return via DCC
@@ -190,57 +235,44 @@ static int dpm_read_reg32(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
        return retval;
 }
 
-static int dpm_read_reg64(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
+/* Write 64bit VFP registers */
+static int dpm_write_reg_u64(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
 {
-       uint64_t value;
-       uint32_t i;
        int retval = ERROR_FAIL;
+       uint32_t value_r0 = buf_get_u32(r->value, 0, 32);
+       uint32_t value_r1 = buf_get_u32(r->value + 4, 0, 32);
 
        switch (regnum) {
-               case 0 ... 30:
-                       i = 0xd5130400 + regnum; /* msr dbgdtr_el0,reg */
-                       retval = dpm->instr_read_data_dcc_64(dpm, i, &value);
-                       break;
-               case 31: /* SP */
-                       i = 0x910003e0;
-                       retval = dpm->instr_read_data_r0_64(dpm, i, &value);
-                       break;
-               case 32: /* PC */
-                       i = 0xd53b4520;
-                       retval = dpm->instr_read_data_r0_64(dpm, i, &value);
-                       break;
-               case 33: /* CPSR */
-                       i = 0xd53b4500;
-                       retval = dpm->instr_read_data_r0_64(dpm, i, &value);
+               case ARM_VFP_V3_D0 ... ARM_VFP_V3_D31:
+                       /* write value_r1 to r1 via dcc */
+                       retval = dpm->instr_write_data_dcc(dpm,
+                               ARMV4_5_MRC(14, 0, 1, 0, 5, 0),
+                               value_r1);
+                       /* write value_r0 to r0 via dcc then,
+                        * move to double word register from r0:r1: "vmov vm, r0, r1"
+                        */
+                       retval = dpm->instr_write_data_r0(dpm,
+                               ARMV4_5_VMOV(0, 1, 0, ((regnum - ARM_VFP_V3_D0) >> 4),
+                               ((regnum - ARM_VFP_V3_D0) & 0xf)), value_r0);
                        break;
-
                default:
+
                        break;
        }
 
        if (retval == ERROR_OK) {
-               buf_set_u64(r->value, 0, 64, value);
-               r->valid = true;
                r->dirty = false;
-               LOG_DEBUG("READ: %s, %16.16llx", r->name, (long long)value);
+               LOG_DEBUG("WRITE: %s, %8.8x, %8.8x", r->name,
+                               (unsigned) value_r0, (unsigned) value_r1);
        }
 
        return retval;
 }
 
-
-/* just read the register -- rely on the core mode being right */
-static int dpm_read_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
-{
-       if (r->size == 64)
-               return dpm_read_reg64(dpm, r, regnum);
-       else
-               return dpm_read_reg32(dpm, r, regnum);
-}
-
-static int dpm_write_reg32(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
+/* just write the register -- rely on the core mode being right */
+static int dpm_write_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
 {
-       int retval = ERROR_FAIL;
+       int retval;
        uint32_t value = buf_get_u32(r->value, 0, 32);
 
        switch (regnum) {
@@ -254,6 +286,14 @@ static int dpm_write_reg32(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
                         * read r0 from DCC; then "MOV pc, r0" */
                        retval = dpm->instr_write_data_r0(dpm, 0xe1a0f000, value);
                        break;
+               case ARM_VFP_V3_D0 ... ARM_VFP_V3_D31:
+                       return dpm_write_reg_u64(dpm, r, regnum);
+                       break;
+               case ARM_VFP_V3_FPSCR:
+                       /* move to r0 from DCC, then "VMSR FPSCR, r0" */
+                       retval = dpm->instr_write_data_r0(dpm,
+                               ARMV4_5_VMSR(0), value);
+                       break;
                default:
                        /* 16: read r0 from DCC, then "MSR r0, CPSR_cxsf"
                         * 17: read r0 from DCC, then "MSR r0, SPSR_cxsf"
@@ -290,84 +330,45 @@ static int dpm_write_pc_core_state(struct arm_dpm *dpm, struct reg *r)
        return dpm->instr_write_data_r0(dpm, ARMV4_5_BX(0), value);
 }
 
-static int dpm_write_reg64(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
-{
-       int retval = ERROR_FAIL;
-       uint32_t i;
-       uint64_t value = buf_get_u64(r->value, 0, 64);
-
-       switch (regnum) {
-               case 0 ... 30:
-                       i = 0xd5330400 + regnum;
-                       retval = dpm->instr_write_data_dcc_64(dpm, i, value);
-                       break;
-               case 32: /* PC */
-                       i = 0xd51b4520;
-                       retval = dpm->instr_write_data_r0_64(dpm, i, value);
-                       break;
-               default:
-                       LOG_DEBUG("register %s (%16.16llx) not defined", r->name,
-                                 (unsigned long long)value);
-                       break;
-       }
-
-       if (retval == ERROR_OK) {
-               r->dirty = false;
-               LOG_DEBUG("WRITE: %s, %16.16llx", r->name, (unsigned long long)value);
-       }
-
-       return retval;
-}
-
-/* just write the register -- rely on the core mode being right */
-static int dpm_write_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
-{
-       if (r->size == 64)
-               return dpm_write_reg64(dpm, r, regnum);
-       else
-               return dpm_write_reg32(dpm, r, regnum);
-}
-
-static int arm_dpm_read_current_registers_i(struct arm_dpm *dpm)
+/**
+ * Read basic registers of the the current context:  R0 to R15, and CPSR;
+ * sets the core mode (such as USR or IRQ) and state (such as ARM or Thumb).
+ * In normal operation this is called on entry to halting debug state,
+ * possibly after some other operations supporting restore of debug state
+ * or making sure the CPU is fully idle (drain write buffer, etc).
+ */
+int arm_dpm_read_current_registers(struct arm_dpm *dpm)
 {
        struct arm *arm = dpm->arm;
-       uint32_t cpsr, instr, core_regs;
+       uint32_t cpsr;
        int retval;
        struct reg *r;
-       enum arm_state core_state = arm->core_state;
 
        retval = dpm->prepare(dpm);
        if (retval != ERROR_OK)
                return retval;
 
-       /* read R0 first (it's used for scratch), then CPSR */
-       r = arm->core_cache->reg_list + 0;
-       if (!r->valid) {
-               retval = dpm_read_reg(dpm, r, 0);
-               if (retval != ERROR_OK)
-                       goto fail;
+       /* read R0 and R1 first (it's used for scratch), then CPSR */
+       for (unsigned i = 0; i < 2; i++) {
+               r = arm->core_cache->reg_list + i;
+               if (!r->valid) {
+                       retval = dpm_read_reg(dpm, r, i);
+                       if (retval != ERROR_OK)
+                               goto fail;
+               }
+               r->dirty = true;
        }
-       r->dirty = true;
 
-       if (core_state == ARM_STATE_AARCH64)
-               instr = 0xd53b4500;  /* mrs x0, dspsr_el0 */
-       else
-               instr = ARMV4_5_MRS(0, 0);
-       retval = dpm->instr_read_data_r0(dpm, instr, &cpsr);
+       retval = dpm->instr_read_data_r0(dpm, ARMV4_5_MRS(0, 0), &cpsr);
        if (retval != ERROR_OK)
                goto fail;
 
        /* update core mode and state, plus shadow mapping for R8..R14 */
        arm_set_cpsr(arm, cpsr);
-       if (core_state == ARM_STATE_AARCH64)
-               /* arm_set_cpsr changes core_state, restore it for now */
-               arm->core_state = ARM_STATE_AARCH64;
-
-       core_regs = arm->core_cache->num_regs;
 
        /* REVISIT we can probably avoid reading R1..R14, saving time... */
-       for (unsigned i = 1; i < core_regs; i++) {
-               r = dpm->arm_reg_current(arm, i);
+       for (unsigned i = 2; i < 16; i++) {
+               r = arm_reg_current(arm, i);
                if (r->valid)
                        continue;
 
@@ -388,23 +389,6 @@ fail:
        return retval;
 }
 
-/**
- * Read basic registers of the the current context:  R0 to R15, and CPSR;
- * sets the core mode (such as USR or IRQ) and state (such as ARM or Thumb).
- * In normal operation this is called on entry to halting debug state,
- * possibly after some other operations supporting restore of debug state
- * or making sure the CPU is fully idle (drain write buffer, etc).
- */
-int arm_dpm_read_current_registers(struct arm_dpm *dpm)
-{
-       return arm_dpm_read_current_registers_i(dpm);
-}
-
-int arm_dpm_read_current_registers_64(struct arm_dpm *dpm)
-{
-       return arm_dpm_read_current_registers_i(dpm);
-}
-
 /* Avoid needless I/O ... leave breakpoints and watchpoints alone
  * unless they're removed, or need updating because of single-stepping
  * or running debugger code.
@@ -453,14 +437,59 @@ done:
 
 static int dpm_add_breakpoint(struct target *target, struct breakpoint *bp);
 
-
-static int arm_dpm_write_dirty_registers_32(struct arm_dpm *dpm)
+/**
+ * Writes all modified core registers for all processor modes.  In normal
+ * operation this is called on exit from halting debug state.
+ *
+ * @param dpm: represents the processor
+ * @param bpwp: true ensures breakpoints and watchpoints are set,
+ *     false ensures they are cleared
+ */
+int arm_dpm_write_dirty_registers(struct arm_dpm *dpm, bool bpwp)
 {
        struct arm *arm = dpm->arm;
        struct reg_cache *cache = arm->core_cache;
        int retval;
        bool did_write;
 
+       retval = dpm->prepare(dpm);
+       if (retval != ERROR_OK)
+               goto done;
+
+       /* If we're managing hardware breakpoints for this core, enable
+        * or disable them as requested.
+        *
+        * REVISIT We don't yet manage them for ANY cores.  Eventually
+        * we should be able to assume we handle them; but until then,
+        * cope with the hand-crafted breakpoint code.
+        */
+       if (arm->target->type->add_breakpoint == dpm_add_breakpoint) {
+               for (unsigned i = 0; i < dpm->nbp; i++) {
+                       struct dpm_bp *dbp = dpm->dbp + i;
+                       struct breakpoint *bp = dbp->bp;
+
+                       retval = dpm_maybe_update_bpwp(dpm, bpwp, &dbp->bpwp,
+                                       bp ? &bp->set : NULL);
+                       if (retval != ERROR_OK)
+                               goto done;
+               }
+       }
+
+       /* enable/disable watchpoints */
+       for (unsigned i = 0; i < dpm->nwp; i++) {
+               struct dpm_wp *dwp = dpm->dwp + i;
+               struct watchpoint *wp = dwp->wp;
+
+               retval = dpm_maybe_update_bpwp(dpm, bpwp, &dwp->bpwp,
+                               wp ? &wp->set : NULL);
+               if (retval != ERROR_OK)
+                       goto done;
+       }
+
+       /* NOTE:  writes to breakpoint and watchpoint registers might
+        * be queued, and need (efficient/batched) flushing later.
+        */
+
        /* Scan the registers until we find one that's both dirty and
         * eligible for flushing.  Flush that and everything else that
         * shares the same core mode setting.  Typically this won't
@@ -471,8 +500,8 @@ static int arm_dpm_write_dirty_registers_32(struct arm_dpm *dpm)
 
                did_write = false;
 
-               /* check everything except our scratch register R0 */
-               for (unsigned i = 1; i < cache->num_regs; i++) {
+               /* check everything except our scratch registers R0 and R1 */
+               for (unsigned i = 2; i < cache->num_regs; i++) {
                        struct arm_reg *r;
                        unsigned regnum;
 
@@ -558,112 +587,14 @@ static int arm_dpm_write_dirty_registers_32(struct arm_dpm *dpm)
                goto done;
        arm->pc->dirty = false;
 
-       /* flush R0 -- it's *very* dirty by now */
-       retval = dpm_write_reg(dpm, &cache->reg_list[0], 0);
-       if (retval != ERROR_OK)
-               goto done;
-       cache->reg_list[0].dirty = false;
-
-done:
-       return retval;
-}
-
-static int arm_dpm_write_dirty_registers_64(struct arm_dpm *dpm)
-{
-       struct arm *arm = dpm->arm;
-       struct reg_cache *cache = arm->core_cache;
-       int retval;
-
-       /* Scan the registers until we find one that's both dirty and
-        * eligible for flushing.  Flush that and everything else that
-        * shares the same core mode setting.  Typically this won't
-        * actually find anything to do...
-        */
-
-       /* check everything except our scratch register R0 */
-       for (unsigned i = 1; i <= 32; i++) {
-               struct arm_reg *r;
-               unsigned regnum;
-
-               if (!cache->reg_list[i].dirty)
-                       continue;
-
-               r = cache->reg_list[i].arch_info;
-               regnum = r->num;
-               retval = dpm_write_reg(dpm,
-                                      &cache->reg_list[i],
-                                      regnum);
+       /* flush R0 and R1 (our scratch registers) */
+       for (unsigned i = 0; i < 2; i++) {
+               retval = dpm_write_reg(dpm, &cache->reg_list[i], i);
                if (retval != ERROR_OK)
                        goto done;
+               cache->reg_list[i].dirty = false;
        }
 
-       /* flush R0 -- it's *very* dirty by now */
-       retval = dpm_write_reg(dpm, &cache->reg_list[0], 0);
-       if (retval != ERROR_OK)
-               goto done;
-       cache->reg_list[0].dirty = false;
-
-done:
-       return retval;
-}
-
-/**
- * Writes all modified core registers for all processor modes.  In normal
- * operation this is called on exit from halting debug state.
- *
- * @param dpm: represents the processor
- * @param bpwp: true ensures breakpoints and watchpoints are set,
- *     false ensures they are cleared
- */
-int arm_dpm_write_dirty_registers(struct arm_dpm *dpm, bool bpwp)
-{
-       struct arm *arm = dpm->arm;
-       struct reg_cache *cache = arm->core_cache;
-       int retval;
-
-       retval = dpm->prepare(dpm);
-       if (retval != ERROR_OK)
-               goto done;
-
-       /* If we're managing hardware breakpoints for this core, enable
-        * or disable them as requested.
-        *
-        * REVISIT We don't yet manage them for ANY cores.  Eventually
-        * we should be able to assume we handle them; but until then,
-        * cope with the hand-crafted breakpoint code.
-        */
-       if (arm->target->type->add_breakpoint == dpm_add_breakpoint) {
-               for (unsigned i = 0; i < dpm->nbp; i++) {
-                       struct dpm_bp *dbp = dpm->dbp + i;
-                       struct breakpoint *bp = dbp->bp;
-
-                       retval = dpm_maybe_update_bpwp(dpm, bpwp, &dbp->bpwp,
-                                       bp ? &bp->set : NULL);
-                       if (retval != ERROR_OK)
-                               goto done;
-               }
-       }
-
-       /* enable/disable watchpoints */
-       for (unsigned i = 0; i < dpm->nwp; i++) {
-               struct dpm_wp *dwp = dpm->dwp + i;
-               struct watchpoint *wp = dwp->wp;
-
-               retval = dpm_maybe_update_bpwp(dpm, bpwp, &dwp->bpwp,
-                               wp ? &wp->set : NULL);
-               if (retval != ERROR_OK)
-                       goto done;
-       }
-
-       /* NOTE:  writes to breakpoint and watchpoint registers might
-        * be queued, and need (efficient/batched) flushing later.
-        */
-
-       if (cache->reg_list[0].size == 64)
-               retval = arm_dpm_write_dirty_registers_64(dpm);
-       else
-               retval = arm_dpm_write_dirty_registers_32(dpm);
-
        /* (void) */ dpm->finish(dpm);
 done:
        return retval;
@@ -699,6 +630,7 @@ static enum arm_mode dpm_mapmode(struct arm *arm,
                /* r13/sp, and r14/lr are always shadowed */
                case 13:
                case 14:
+               case ARM_VFP_V3_D0 ... ARM_VFP_V3_FPSCR:
                        return mode;
                default:
                        LOG_WARNING("invalid register #%u", num);
@@ -720,7 +652,8 @@ static int arm_dpm_read_core_reg(struct target *target, struct reg *r,
        struct arm_dpm *dpm = target_to_arm(target)->dpm;
        int retval;
 
-       if (regnum < 0 || regnum > 16)
+       if (regnum < 0 || (regnum > 16 && regnum < ARM_VFP_V3_D0) ||
+               (regnum > ARM_VFP_V3_FPSCR))
                return ERROR_COMMAND_SYNTAX_ERROR;
 
        if (regnum == 16) {
@@ -763,7 +696,8 @@ static int arm_dpm_write_core_reg(struct target *target, struct reg *r,
        int retval;
 
 
-       if (regnum < 0 || regnum > 16)
+       if (regnum < 0 || (regnum > 16 && regnum < ARM_VFP_V3_D0) ||
+                       (regnum > ARM_VFP_V3_FPSCR))
                return ERROR_COMMAND_SYNTAX_ERROR;
 
        if (regnum == 16) {
@@ -1089,20 +1023,16 @@ void arm_dpm_report_dscr(struct arm_dpm *dpm, uint32_t dscr)
 
        /* Examine debug reason */
        switch (DSCR_ENTRY(dscr)) {
-               case 6: /* Data abort (v6 only) */
-               case 7: /* Prefetch abort (v6 only) */
-               /* FALL THROUGH -- assume a v6 core in abort mode */
-               case 0: /* HALT request from debugger */
-               case 4: /* EDBGRQ */
+               case DSCR_ENTRY_HALT_REQ:       /* HALT request from debugger */
+               case DSCR_ENTRY_EXT_DBG_REQ:    /* EDBGRQ */
                        target->debug_reason = DBG_REASON_DBGRQ;
                        break;
-               case 1: /* HW breakpoint */
-               case 3: /* SW BKPT */
-               case 5: /* vector catch */
+               case DSCR_ENTRY_BREAKPOINT:     /* HW breakpoint */
+               case DSCR_ENTRY_BKPT_INSTR:     /* vector catch */
                        target->debug_reason = DBG_REASON_BREAKPOINT;
                        break;
-               case 2: /* asynch watchpoint */
-               case 10:/* precise watchpoint */
+               case DSCR_ENTRY_IMPRECISE_WATCHPT:      /* asynch watchpoint */
+               case DSCR_ENTRY_PRECISE_WATCHPT:/* precise watchpoint */
                        target->debug_reason = DBG_REASON_WATCHPOINT;
                        break;
                default:
@@ -1133,20 +1063,15 @@ int arm_dpm_setup(struct arm_dpm *dpm)
 
        /* register access setup */
        arm->full_context = arm_dpm_full_context;
-       arm->read_core_reg = arm->read_core_reg ? : arm_dpm_read_core_reg;
-       arm->write_core_reg = arm->write_core_reg ? : arm_dpm_write_core_reg;
-
-       if (arm->core_cache != NULL) {
-               if (arm->core_state == ARM_STATE_AARCH64) {
-                       cache = armv8_build_reg_cache(target);
-                       target->reg_cache = cache;
-               } else {
-                       cache = arm_build_reg_cache(target, arm);
-                       *register_get_last_cache_p(&target->reg_cache) = cache;
-               }
+       arm->read_core_reg = arm_dpm_read_core_reg;
+       arm->write_core_reg = arm_dpm_write_core_reg;
 
+       if (arm->core_cache == NULL) {
+               cache = arm_build_reg_cache(target, arm);
                if (!cache)
                        return ERROR_FAIL;
+
+               *register_get_last_cache_p(&target->reg_cache) = cache;
        }
 
        /* coprocessor access setup */
@@ -1163,20 +1088,10 @@ int arm_dpm_setup(struct arm_dpm *dpm)
        target->type->add_watchpoint = dpm_add_watchpoint;
        target->type->remove_watchpoint = dpm_remove_watchpoint;
 
-
-       if (dpm->arm_reg_current == 0)
-               dpm->arm_reg_current = arm_reg_current;
-
        /* FIXME add vector catch support */
 
-       if (arm->core_state == ARM_STATE_AARCH64) {
-               dpm->nbp = 1 + ((dpm->didr >> 24) & 0xf);
-               dpm->nwp = 1 + ((dpm->didr >> 28) & 0xf);
-       } else {
-               dpm->nbp = 1 + ((dpm->didr >> 12) & 0xf);
-               dpm->nwp = 1 + ((dpm->didr >> 20) & 0xf);
-       }
-
+       dpm->nbp = 1 + ((dpm->didr >> 24) & 0xf);
+       dpm->nwp = 1 + ((dpm->didr >> 28) & 0xf);
        dpm->dbp = calloc(dpm->nbp, sizeof *dpm->dbp);
        dpm->dwp = calloc(dpm->nwp, sizeof *dpm->dwp);
 

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)