jtag: linuxgpiod: drop extra parenthesis
[openocd.git] / src / target / mips32.c
index af5f2c50d80701d3a22c6b4dd1333e1c797ff280..81faab72da7cb82e6082108c1cab70368ef5f6a1 100644 (file)
@@ -161,6 +161,67 @@ static const struct {
 #define MIPS32_NUM_REGS ARRAY_SIZE(mips32_regs)
 
 
+
+#define zero   0
+
+#define AT     1
+
+#define v0     2
+#define v1     3
+
+#define a0     4
+#define a1     5
+#define a2     6
+#define        a3      7
+#define t0     8
+#define t1     9
+#define t2     10
+#define t3     11
+#define t4     12
+#define t5     13
+#define t6     14
+#define t7     15
+#define ta0    12      /* alias for $t4 */
+#define ta1    13      /* alias for $t5 */
+#define ta2    14      /* alias for $t6 */
+#define ta3    15      /* alias for $t7 */
+
+#define s0     16
+#define s1     17
+#define s2     18
+#define s3     19
+#define s4     20
+#define s5     21
+#define s6     22
+#define s7     23
+#define s8     30              /* == fp */
+
+#define t8     24
+#define t9     25
+#define k0     26
+#define k1     27
+
+#define gp     28
+
+#define sp     29
+#define fp     30
+#define ra     31
+
+
+static const struct {
+       const char *name;
+} mips32_dsp_regs[MIPS32NUMDSPREGS] = {
+       { "hi0"},
+       { "hi1"},
+       { "hi2"},
+       { "hi3"},
+       { "lo0"},
+       { "lo1"},
+       { "lo2"},
+       { "lo3"},
+       { "control"},
+};
+
 static int mips32_get_core_reg(struct reg *reg)
 {
        int retval;
@@ -201,6 +262,61 @@ static int mips32_set_core_reg(struct reg *reg, uint8_t *buf)
        return ERROR_OK;
 }
 
+/**
+ * mips32_set_all_fpr_width - Set the width of all floating-point registers
+ * @param[in] mips32: MIPS32 common structure
+ * @param[in] fp64: Flag indicating whether to set the width to 64 bits (double precision)
+ *
+ * @brief Sets the width of all floating-point registers based on the specified flag.
+ */
+static void mips32_set_all_fpr_width(struct mips32_common *mips32, bool fp64)
+{
+       struct reg_cache *cache = mips32->core_cache;
+       struct reg *reg_list = cache->reg_list;
+       int i;
+
+       for (i = MIPS32_REGLIST_FP_INDEX; i < (MIPS32_REGLIST_FP_INDEX + MIPS32_REG_FP_COUNT); i++) {
+               reg_list[i].size = fp64 ? 64 : 32;
+               reg_list[i].reg_data_type->type = fp64 ? REG_TYPE_IEEE_DOUBLE : REG_TYPE_IEEE_SINGLE;
+       }
+}
+
+/**
+ * mips32_detect_fpr_mode_change - Detect changes in floating-point register mode
+ * @param[in] mips32: MIPS32 common structure
+ * @param[in] cp0_status: Value of the CP0 status register
+ *
+ * @brief Detects changes in the floating-point register mode based on the CP0 status register.
+ * If changes are detected, it updates the internal state
+ * and logs a warning message indicating the mode change.
+ */
+static void mips32_detect_fpr_mode_change(struct mips32_common *mips32, uint32_t cp0_status)
+{
+       if (!mips32->fp_imp)
+               return;
+
+       /* CP0.Status.FR indicates the working mode of floating-point register.
+        * When FP = 0, fpr can contain any 32bit data type,
+        * 64bit data types are stored in even-odd register pairs.
+        * When FP = 1, fpr can contain any data types.*/
+       bool fpu_in_64bit = ((cp0_status & BIT(MIPS32_CP0_STATUS_FR_SHIFT)) != 0);
+
+       /* CP0.Status.CU1 indicated whether CoProcessor1(which is FPU) is present. */
+       bool fp_enabled = ((cp0_status & BIT(MIPS32_CP0_STATUS_CU1_SHIFT)) != 0);
+
+       if (mips32->fpu_in_64bit != fpu_in_64bit) {
+               mips32->fpu_in_64bit = fpu_in_64bit;
+               mips32_set_all_fpr_width(mips32, fpu_in_64bit);
+               LOG_WARNING("** FP mode changed to %sbit, you must reconnect GDB **", fpu_in_64bit ? "64" : "32");
+       }
+
+       if (mips32->fpu_enabled != fp_enabled) {
+               mips32->fpu_enabled = fp_enabled;
+               const char *s = fp_enabled ? "enabled" : "disabled";
+               LOG_WARNING("** FP is %s, register update %s **", s, s);
+       }
+}
+
 static int mips32_read_core_reg(struct target *target, unsigned int num)
 {
        unsigned int cnum;
@@ -217,6 +333,8 @@ static int mips32_read_core_reg(struct target *target, unsigned int num)
                cnum = num - MIPS32_REGLIST_C0_INDEX;
                reg_value = mips32->core_regs.cp0[cnum];
                buf_set_u32(mips32->core_cache->reg_list[num].value, 0, 32, reg_value);
+               if (cnum == MIPS32_REG_C0_STATUS_INDEX)
+                       mips32_detect_fpr_mode_change(mips32, reg_value);
        } else if (num >= MIPS32_REGLIST_FPC_INDEX) {
                /* FPCR */
                cnum = num - MIPS32_REGLIST_FPC_INDEX;
@@ -258,6 +376,8 @@ static int mips32_write_core_reg(struct target *target, unsigned int num)
                cnum = num - MIPS32_REGLIST_C0_INDEX;
                reg_value = buf_get_u32(mips32->core_cache->reg_list[num].value, 0, 32);
                mips32->core_regs.cp0[cnum] = (uint32_t)reg_value;
+               if (cnum == MIPS32_REG_C0_STATUS_INDEX)
+                       mips32_detect_fpr_mode_change(mips32, reg_value);
        } else if (num >= MIPS32_REGLIST_FPC_INDEX) {
                /* FPCR */
                cnum = num - MIPS32_REGLIST_FPC_INDEX;
@@ -796,6 +916,44 @@ static const struct cpu_entry *mips32_find_cpu_by_prid(uint32_t prid)
        return &mips32_cpu_entry[MIPS32_NUM_CPU_ENTRIES - 1];
 }
 
+static bool mips32_cpu_is_lexra(struct mips_ejtag *ejtag_info)
+{
+       return (ejtag_info->prid & PRID_COMP_MASK) == PRID_COMP_LEXRA;
+}
+
+static int mips32_cpu_get_release(struct mips_ejtag *ejtag_info)
+{
+       return (ejtag_info->config[0] & MIPS32_CONFIG0_AR_MASK) >> MIPS32_CONFIG0_AR_SHIFT;
+}
+
+/**
+ * mips32_cpu_support_sync - Checks CPU supports ordering
+ * @param[in] ejtag_info: MIPS EJTAG information structure.
+ *
+ * @brief MIPS ISA implemented on Lexra CPUs is MIPS-I, similar to R3000,
+ * which does not have the SYNC instruction alone with unaligned
+ * load/store instructions.
+ *
+ * @returns true if current CPU supports sync instruction(CPU is not Lexra)
+*/
+bool mips32_cpu_support_sync(struct mips_ejtag *ejtag_info)
+{
+       return !mips32_cpu_is_lexra(ejtag_info);
+}
+
+/**
+ * mips32_cpu_support_hazard_barrier - Checks CPU supports hazard barrier
+ * @param[in] ejtag_info: MIPS EJTAG information structure.
+ *
+ * @brief hazard barrier instructions EHB and *.HB was introduced to MIPS from release 2.
+ *
+ * @returns true if current CPU supports hazard barrier(release > 1)
+*/
+bool mips32_cpu_support_hazard_barrier(struct mips_ejtag *ejtag_info)
+{
+       return mips32_cpu_get_release(ejtag_info) > MIPS32_RELEASE_1;
+}
+
 /**
  * mips32_cpu_probe - Detects processor type and applies necessary quirks.
  * @param[in] target: The target CPU to probe.
@@ -834,6 +992,27 @@ int mips32_cpu_probe(struct target *target)
                        break;
                }
                break;
+
+       /* Determine which CP0 registers are available in the current processor core */
+       case PRID_COMP_MTI:
+               switch (entry->prid & PRID_IMP_MASK) {
+               case PRID_IMP_MAPTIV_UC:
+                       mips32->cp0_mask = MIPS_CP0_MAPTIV_UC;
+                       break;
+               case PRID_IMP_MAPTIV_UP:
+               case PRID_IMP_M5150:
+                       mips32->cp0_mask = MIPS_CP0_MAPTIV_UP;
+                       break;
+               case PRID_IMP_IAPTIV:
+               case PRID_IMP_IAPTIV_CM:
+                       mips32->cp0_mask = MIPS_CP0_IAPTIV;
+                       break;
+               default:
+                       /* CP0 mask should be the same as MK4 by default */
+                       mips32->cp0_mask = MIPS_CP0_MK4;
+                       break;
+               }
+
        default:
                break;
        }
@@ -867,8 +1046,8 @@ static int mips32_read_config_fpu(struct mips32_common *mips32, struct mips_ejta
                mips32->fp_imp = MIPS32_FP_IMP_NONE;
                return ERROR_OK;
        }
-       uint32_t status_value;
-       bool status_fr, status_cu1;
+       uint32_t fir_value, status_value;
+       bool fpu_in_64bit, fp_enabled;
 
        retval = mips32_cp0_read(ejtag_info, &status_value, MIPS32_C0_STATUS, 0);
        if (retval != ERROR_OK) {
@@ -876,20 +1055,34 @@ static int mips32_read_config_fpu(struct mips32_common *mips32, struct mips_ejta
                return retval;
        }
 
-       status_fr = (status_value >> MIPS32_CP0_STATUS_FR_SHIFT) & 0x1;
-       status_cu1 = (status_value >> MIPS32_CP0_STATUS_CU1_SHIFT) & 0x1;
-       if (status_cu1) {
-               /* TODO: read fpu(cp1) config register for current operating mode.
-                * Now its set to 32 bits by default. */
-               snprintf(buf, sizeof(buf), "yes");
-               fp_imp = MIPS32_FP_IMP_32;
+       fpu_in_64bit = (status_value & BIT(MIPS32_CP0_STATUS_FR_SHIFT)) != 0;
+       fp_enabled = (status_value & BIT(MIPS32_CP0_STATUS_CU1_SHIFT)) != 0;
+       if (fp_enabled) {
+               retval = mips32_cp1_control_read(ejtag_info, &fir_value, 0);
+               if (retval != ERROR_OK) {
+                       LOG_ERROR("Failed to read cp1 FIR register");
+                       return retval;
+               }
+
+               if ((fir_value >> MIPS32_CP1_FIR_F64_SHIFT) & 0x1)
+                       fp_imp++;
        } else {
+               /* This is the only condition that writes to buf */
                snprintf(buf, sizeof(buf), "yes, disabled");
                fp_imp = MIPS32_FP_IMP_UNKNOWN;
        }
 
-       mips32->fpu_in_64bit = status_fr;
-       mips32->fpu_enabled = status_cu1;
+       mips32->fpu_in_64bit = fpu_in_64bit;
+       mips32->fpu_enabled = fp_enabled;
+
+       mips32_set_all_fpr_width(mips32, fpu_in_64bit);
+
+       /* If fpu is not disabled, print out more information */
+       if (!buf[0])
+               snprintf(buf, sizeof(buf), "yes, %sbit (%s, working in %sbit)",
+                       fp_imp == MIPS32_FP_IMP_64 ? "64" : "32",
+                       fp_enabled ? "enabled" : "disabled",
+                       fpu_in_64bit ? "64" : "32");
 
        LOG_USER("FPU implemented: %s", buf);
        mips32->fp_imp = fp_imp;
@@ -1212,12 +1405,239 @@ static int mips32_read_config_mmu(struct mips_ejtag *ejtag_info)
 }
 
 /**
- * MIPS32 targets expose command interface
- * to manipulate CP0 registers
+ * mips32_cp0_find_register_by_name - Find CP0 register by its name.
+ * @param[in] cp0_mask: Mask to filter out irrelevant registers.
+ * @param[in] reg_name: Name of the register to find.
+ *
+ * @brief This function iterates through mips32_cp0_regs to find a register
+ * matching reg_name, considering cp0_mask to filter out registers
+ * not relevant for the current core.
+ *
+ * @return Pointer to the found register, or NULL if not found.
+ */
+static const struct mips32_cp0 *mips32_cp0_find_register_by_name(uint32_t cp0_mask, const char *reg_name)
+{
+       if (reg_name)
+               for (unsigned int i = 0; i < MIPS32NUMCP0REGS; i++) {
+                       if ((mips32_cp0_regs[i].core & cp0_mask) == 0)
+                               continue;
+
+                       if (strcmp(mips32_cp0_regs[i].name, reg_name) == 0)
+                               return &mips32_cp0_regs[i];
+               }
+       return NULL;
+}
+
+/**
+ * mips32_cp0_get_all_regs - Print all CP0 registers and their values.
+ * @param[in] cmd: Command invocation context.
+ * @param[in] ejtag_info: EJTAG interface information.
+ * @param[in] cp0_mask: Mask to identify relevant registers.
+ *
+ * @brief Iterates over all CP0 registers, reads their values, and prints them.
+ * Only considers registers relevant to the current core, as defined by cp0_mask.
+ *
+ * @return ERROR_OK on success; error code on failure.
+ */
+static int mips32_cp0_get_all_regs(struct command_invocation *cmd, struct mips_ejtag *ejtag_info, uint32_t cp0_mask)
+{
+       uint32_t value;
+
+       for (unsigned int i = 0; i < MIPS32NUMCP0REGS; i++) {
+               /* Register name not valid for this core */
+               if ((mips32_cp0_regs[i].core & cp0_mask) == 0)
+                       continue;
+
+               int retval = mips32_cp0_read(ejtag_info, &value, mips32_cp0_regs[i].reg, mips32_cp0_regs[i].sel);
+               if (retval != ERROR_OK) {
+                       command_print(CMD, "Error: couldn't access reg %s", mips32_cp0_regs[i].name);
+                       return retval;
+               }
+
+               command_print(CMD, "%*s: 0x%8.8" PRIx32, 14, mips32_cp0_regs[i].name, value);
+       }
+       return ERROR_OK;
+}
+
+/**
+ * mips32_cp0_get_reg_by_name - Read and print a CP0 register's value by name.
+ * @param[in] cmd: Command invocation context.
+ * @param[in] ejtag_info: EJTAG interface information.
+ * @param[in] cp0_mask: Mask to identify relevant registers.
+ *
+ * @brief Finds a CP0 register by name, reads its value, and prints it.
+ * Handles error scenarios like register not found or read failure.
+ *
+ * @return ERROR_OK on success; error code on failure.
+ */
+static int mips32_cp0_get_reg_by_name(struct command_invocation *cmd, struct mips_ejtag *ejtag_info, uint32_t cp0_mask)
+{
+       const struct mips32_cp0 *cp0_regs = mips32_cp0_find_register_by_name(cp0_mask, CMD_ARGV[0]);
+       if (!cp0_regs) {
+               command_print(CMD, "Error: Register '%s' not found", CMD_ARGV[0]);
+               return ERROR_COMMAND_ARGUMENT_INVALID;
+       }
+
+       uint32_t value;
+       int retval = mips32_cp0_read(ejtag_info, &value, cp0_regs->reg, cp0_regs->sel);
+       if (retval != ERROR_OK) {
+               command_print(CMD, "Error: Encounter an Error while reading cp0 reg %d sel %d",
+                                       cp0_regs->reg, cp0_regs->sel);
+               return retval;
+       }
+
+       command_print(CMD, "0x%8.8" PRIx32, value);
+       return ERROR_OK;
+}
+
+/**
+ * mips32_cp0_get_reg_by_number - Read and print a CP0 register's value by number.
+ * @param[in] cmd: Command invocation context.
+ * @param[in] ejtag_info: EJTAG interface information.
+ *
+ * @brief Reads a specific CP0 register (identified by number and selection) and prints its value.
+ * The register number and selection are parsed from the command arguments.
+ *
+ * @return ERROR_OK on success; error code on failure.
+ */
+static int mips32_cp0_get_reg_by_number(struct command_invocation *cmd, struct mips_ejtag *ejtag_info)
+{
+       uint32_t cp0_reg, cp0_sel, value;
+       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], cp0_reg);
+       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], cp0_sel);
+
+       int retval = mips32_cp0_read(ejtag_info, &value, cp0_reg, cp0_sel);
+       if (retval != ERROR_OK) {
+               command_print(CMD,
+                               "Error: couldn't access reg %" PRIu32,
+                               cp0_reg);
+               return retval;
+       }
+
+       command_print(CMD, "cp0 reg %" PRIu32 ", select %" PRIu32 ": %8.8" PRIx32,
+                       cp0_reg, cp0_sel, value);
+       return ERROR_OK;
+}
+
+/**
+ * mips32_cp0_set_reg_by_name - Write to a CP0 register identified by name.
+ * @param[in] cmd: Command invocation context.
+ * @param[in] mips32: Common MIPS32 data structure.
+ * @param[in] ejtag_info: EJTAG interface information.
+ *
+ * @brief Writes a value to a CP0 register specified by name. Updates internal
+ * cache if specific registers (STATUS, CAUSE, DEPC, GUESTCTL1) are modified.
+ *
+ * @return ERROR_OK on success; error code on failure.
+ */
+static int mips32_cp0_set_reg_by_name(struct command_invocation *cmd,
+               struct mips32_common *mips32, struct mips_ejtag *ejtag_info)
+{
+       const struct mips32_cp0 *cp0_regs = mips32_cp0_find_register_by_name(mips32->cp0_mask, CMD_ARGV[0]);
+       if (!cp0_regs) {
+               command_print(CMD, "Error: Register '%s' not found", CMD_ARGV[0]);
+               return ERROR_COMMAND_ARGUMENT_INVALID;
+       }
+
+
+       uint32_t value;
+       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value);
+
+       if (cp0_regs->reg == MIPS32_C0_STATUS && cp0_regs->sel == 0) {
+               /* Update cached Status register if user is writing to Status */
+               mips32->core_regs.cp0[MIPS32_REG_C0_STATUS_INDEX] = value;
+               mips32->core_cache->reg_list[MIPS32_REGLIST_C0_STATUS_INDEX].dirty = 1;
+       } else if (cp0_regs->reg == MIPS32_C0_CAUSE && cp0_regs->sel == 0) {
+               /* Update register cache with new value if its Cause */
+               mips32->core_regs.cp0[MIPS32_REG_C0_CAUSE_INDEX] = value;
+               mips32->core_cache->reg_list[MIPS32_REGLIST_C0_CAUSE_INDEX].dirty = 1;
+       } else if (cp0_regs->reg == MIPS32_C0_DEPC && cp0_regs->sel == 0) {
+               /* Update cached PC if its DEPC */
+               mips32->core_regs.cp0[MIPS32_REG_C0_PC_INDEX] = value;
+               mips32->core_cache->reg_list[MIPS32_REGLIST_C0_PC_INDEX].dirty = 1;
+       } else if (cp0_regs->reg == MIPS32_C0_GUESTCTL1 && cp0_regs->sel == 4) {
+               /* Update cached guestCtl1 */
+               mips32->core_regs.cp0[MIPS32_REG_C0_GUESTCTL1_INDEX] = value;
+               mips32->core_cache->reg_list[MIPS32_REGLIST_C0_GUESTCTL1_INDEX].dirty = 1;
+       }
+
+       int retval = mips32_cp0_write(ejtag_info, value,
+                                                               cp0_regs->reg,
+                                                               cp0_regs->sel);
+       if (retval != ERROR_OK) {
+               command_print(CMD, "Error: Encounter an Error while writing to cp0 reg %d, sel %d",
+                                       cp0_regs->reg, cp0_regs->sel);
+               return retval;
+       }
+
+       command_print(CMD, "cp0 reg %s (%u, select %u: %8.8" PRIx32 ")",
+                       CMD_ARGV[0], cp0_regs->reg, cp0_regs->sel, value);
+       return ERROR_OK;
+}
+
+/**
+ * mips32_cp0_set_reg_by_number - Write to a CP0 register identified by number.
+ * @param[in] cmd: Command invocation context.
+ * @param[in] mips32: Common MIPS32 data structure.
+ * @param[in] ejtag_info: EJTAG interface information.
+ *
+ * @brief Writes a value to a CP0 register specified by number and selection.
+ * Handles special cases like updating the internal cache for certain registers.
+ *
+ * @return ERROR_OK on success; error code on failure.
+ */
+static int mips32_cp0_set_reg_by_number(struct command_invocation *cmd,
+               struct mips32_common *mips32, struct mips_ejtag *ejtag_info)
+{
+       uint32_t cp0_reg, cp0_sel, value;
+       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], cp0_reg);
+       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], cp0_sel);
+       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], value);
+
+       if (cp0_reg == MIPS32_C0_STATUS && cp0_sel == 0) {
+               /* Update cached status register if user is writing to Status register */
+               mips32->core_regs.cp0[MIPS32_REG_C0_STATUS_INDEX] = value;
+               mips32->core_cache->reg_list[MIPS32_REGLIST_C0_STATUS_INDEX].dirty = 1;
+       } else if (cp0_reg == MIPS32_C0_CAUSE && cp0_sel == 0) {
+               /* Update register cache with new value if its Cause register */
+               mips32->core_regs.cp0[MIPS32_REG_C0_CAUSE_INDEX] = value;
+               mips32->core_cache->reg_list[MIPS32_REGLIST_C0_CAUSE_INDEX].dirty = 1;
+       } else if (cp0_reg == MIPS32_C0_DEPC && cp0_sel == 0) {
+               /* Update cached PC if its DEPC */
+               mips32->core_regs.cp0[MIPS32_REG_C0_PC_INDEX] = value;
+               mips32->core_cache->reg_list[MIPS32_REGLIST_C0_PC_INDEX].dirty = 1;
+       } else if (cp0_reg == MIPS32_C0_GUESTCTL1 && cp0_sel == 4) {
+               /* Update cached guestCtl1, too */
+               mips32->core_regs.cp0[MIPS32_REG_C0_GUESTCTL1_INDEX] = value;
+               mips32->core_cache->reg_list[MIPS32_REGLIST_C0_GUESTCTL1_INDEX].dirty = 1;
+       }
+
+       int retval = mips32_cp0_write(ejtag_info, value, cp0_reg, cp0_sel);
+       if (retval != ERROR_OK) {
+               command_print(CMD,
+                               "Error: couldn't access cp0 reg %" PRIu32 ", select %" PRIu32,
+                               cp0_reg,  cp0_sel);
+               return retval;
+       }
+
+       command_print(CMD, "cp0 reg %" PRIu32 ", select %" PRIu32 ": %8.8" PRIx32,
+                       cp0_reg, cp0_sel, value);
+       return ERROR_OK;
+}
+
+/**
+ * mips32_handle_cp0_command - Handle commands related to CP0 registers.
+ * @cmd: Command invocation context.
+ *
+ * Orchestrates different operations on CP0 registers based on the command arguments.
+ * Supports operations like reading all registers, reading/writing a specific register
+ * by name or number.
+ *
+ * Return: ERROR_OK on success; error code on failure.
  */
 COMMAND_HANDLER(mips32_handle_cp0_command)
 {
-       int retval;
+       int retval, tmp;
        struct target *target = get_current_target(CMD_CTX);
        struct mips32_common *mips32 = target_to_mips32(target);
        struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
@@ -1232,43 +1652,228 @@ COMMAND_HANDLER(mips32_handle_cp0_command)
                return ERROR_TARGET_NOT_HALTED;
        }
 
-       /* two or more argument, access a single register/select (write if third argument is given) */
-       if (CMD_ARGC < 2)
-               return ERROR_COMMAND_SYNTAX_ERROR;
-       else {
-               uint32_t cp0_reg, cp0_sel;
-               COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], cp0_reg);
-               COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], cp0_sel);
+       switch (CMD_ARGC) {
+               case 0: /* No arg => print out all cp0 regs */
+                       retval = mips32_cp0_get_all_regs(CMD, ejtag_info, mips32->cp0_mask);
+                       break;
+               case 1: /* 1 arg => get cp0 #reg/#sel value by name */
+                       retval = mips32_cp0_get_reg_by_name(CMD, ejtag_info, mips32->cp0_mask);
+                       break;
+               case 2: /* 2 args => get cp0 reg/sel value or set value by name */
+                       tmp = *CMD_ARGV[0];
+                       if (isdigit(tmp)) /* starts from number then args are #reg and #sel */
+                               retval = mips32_cp0_get_reg_by_number(CMD, ejtag_info);
+                       else /* or set value by register name */
+                               retval = mips32_cp0_set_reg_by_name(CMD, mips32, ejtag_info);
 
-               if (CMD_ARGC == 2) {
-                       uint32_t value;
+                       break;
+               case 3: /* 3 args => set cp0 reg/sel value*/
+                       retval = mips32_cp0_set_reg_by_number(CMD, mips32, ejtag_info);
+                       break;
+               default: /* Other argc => err */
+                       retval = ERROR_COMMAND_SYNTAX_ERROR;
+                       break;
+       }
 
-                       retval = mips32_cp0_read(ejtag_info, &value, cp0_reg, cp0_sel);
-                       if (retval != ERROR_OK) {
-                               command_print(CMD,
-                                               "couldn't access reg %" PRIu32,
-                                               cp0_reg);
-                               return ERROR_OK;
-                       }
-                       command_print(CMD, "cp0 reg %" PRIu32 ", select %" PRIu32 ": %8.8" PRIx32,
-                                       cp0_reg, cp0_sel, value);
+       return retval;
+}
 
-               } else if (CMD_ARGC == 3) {
-                       uint32_t value;
-                       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], value);
-                       retval = mips32_cp0_write(ejtag_info, value, cp0_reg, cp0_sel);
-                       if (retval != ERROR_OK) {
-                               command_print(CMD,
-                                               "couldn't access cp0 reg %" PRIu32 ", select %" PRIu32,
-                                               cp0_reg,  cp0_sel);
-                               return ERROR_OK;
-                       }
-                       command_print(CMD, "cp0 reg %" PRIu32 ", select %" PRIu32 ": %8.8" PRIx32,
-                                       cp0_reg, cp0_sel, value);
-               }
-       }
+/**
+ * mips32_dsp_enable - Enable access to DSP registers
+ * @param[in] ctx: Context information for the pracc queue
+ * @param[in] isa: Instruction Set Architecture identifier
+ *
+ * @brief Enables access to DSP registers by modifying the status register.
+ *
+ * This function adds instructions to the context queue for enabling
+ * access to DSP registers by modifying the status register.
+ */
+static void mips32_dsp_enable(struct pracc_queue_info *ctx, int isa)
+{
+       /* Save Status Register */
+       /* move status to $9 (t1) 2*/
+       pracc_add(ctx, 0, MIPS32_MFC0(isa, 9, 12, 0));
+
+       /* Read it again in order to modify it */
+       /* move status to $0 (t0) 3*/
+       pracc_add(ctx, 0, MIPS32_MFC0(isa, 8, 12, 0));
+
+       /* Enable access to DSP registers by setting MX bit in status register */
+       /* $15 = MIPS32_PRACC_STACK 4/5/6*/
+       pracc_add(ctx, 0, MIPS32_LUI(isa, 15, UPPER16(MIPS32_DSP_ENABLE)));
+       pracc_add(ctx, 0, MIPS32_ORI(isa, 15, 15, LOWER16(MIPS32_DSP_ENABLE)));
+       pracc_add(ctx, 0, MIPS32_ISA_OR(8, 8, 15));
+       /* Enable DSP - update status registers 7*/
+       pracc_add(ctx, 0, MIPS32_MTC0(isa, 8, 12, 0));
+}
 
-       return ERROR_OK;
+/**
+ * mips32_dsp_restore - Restore DSP status registers to the previous setting
+ * @param[in] ctx: Context information pracc queue
+ * @param[in] isa: isa identifier
+ *
+ * @brief Restores the DSP status registers to their previous setting.
+ *
+ * This function adds instructions to the context queue for restoring the DSP
+ * status registers to their values before the operation.
+ */
+static void mips32_dsp_restore(struct pracc_queue_info *ctx, int isa)
+{
+       pracc_add(ctx, 0, MIPS32_MTC0(isa, 9, 12, 0)); /* Restore status registers to previous setting */
+       pracc_add(ctx, 0, MIPS32_NOP); /* nop */
+}
+
+/**
+ * mips32_pracc_read_dsp_reg - Read a value from a MIPS32 DSP register
+ * @param[in] ejtag_info: EJTAG information structure
+ * @param[out] val: Pointer to store the read value
+ * @param[in] reg: Index of the DSP register to read
+ *
+ * @brief Reads the value from the specified MIPS32 DSP register using EJTAG access.
+ *
+ * This function initiates a sequence of instructions to read the value from the
+ * specified DSP register. It will enable dsp module if its not enabled
+ * and restoring the status registers after the read operation.
+ *
+ * @return ERROR_OK on success; error code on failure.
+ */
+static int mips32_pracc_read_dsp_reg(struct mips_ejtag *ejtag_info, uint32_t *val, uint32_t reg)
+{
+       int isa = 0;
+
+       struct pracc_queue_info ctx = {
+               .max_code = 48,
+               .ejtag_info = ejtag_info
+       };
+
+       uint32_t dsp_read_code[] = {
+               MIPS32_MFHI(isa, t0),           /* mfhi t0 ($ac0) - OPCODE - 0x00004010 */
+               MIPS32_DSP_MFHI(t0, 1),         /* mfhi t0,$ac1 - OPCODE - 0x00204010 */
+               MIPS32_DSP_MFHI(t0, 2),         /* mfhi t0,$ac2 - OPCODE - 0x00404010 */
+               MIPS32_DSP_MFHI(t0, 3),         /* mfhi t0,$ac3 - OPCODE - 0x00604010*/
+               MIPS32_MFLO(isa, t0),           /* mflo t0 ($ac0) - OPCODE - 0x00004012 */
+               MIPS32_DSP_MFLO(t0, 1),         /* mflo t0,$ac1 - OPCODE - 0x00204012 */
+               MIPS32_DSP_MFLO(t0, 2),         /* mflo t0,$ac2 - OPCODE - 0x00404012 */
+               MIPS32_DSP_MFLO(t0, 3),         /* mflo t0,$ac3 - OPCODE - 0x00604012 */
+               MIPS32_DSP_RDDSP(t0, 0x3F),     /* rddsp t0, 0x3f (DSPCtl) - OPCODE - 0x7c3f44b8 */
+       };
+
+       /* Check status register to determine if dsp register access is enabled */
+       /* Get status register so it can be restored later */
+
+       ctx.pracc_list = NULL;
+
+       /* Init context queue */
+       pracc_queue_init(&ctx);
+
+       if (ctx.retval != ERROR_OK)
+               goto exit;
+
+       /* Enables DSP whether its already enabled or not */
+       mips32_dsp_enable(&ctx, isa);
+
+       /* move AC or Control to $8 (t0) 8*/
+       pracc_add(&ctx, 0, dsp_read_code[reg]);
+       /* Restore status registers to previous setting */
+       mips32_dsp_restore(&ctx, isa);
+
+       /* $15 = MIPS32_PRACC_BASE_ADDR 1*/
+       pracc_add(&ctx, 0, MIPS32_LUI(isa, 15, PRACC_UPPER_BASE_ADDR));
+       /* store $8 to pracc_out 10*/
+       pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT, MIPS32_SW(isa, 8, PRACC_OUT_OFFSET, 15));
+       /* move COP0 DeSave to $15 11*/
+       pracc_add(&ctx, 0, MIPS32_MFC0(isa, 15, 31, 0));
+       /* restore upper 16 of $8 12*/
+       pracc_add(&ctx, 0, MIPS32_LUI(isa, 8, UPPER16(ejtag_info->reg8)));
+       /* restore lower 16 of $8 13*/
+       pracc_add(&ctx, 0, MIPS32_ORI(isa, 8, 8, LOWER16(ejtag_info->reg8)));
+       /* restore upper 16 of $9 14*/
+       pracc_add(&ctx, 0, MIPS32_LUI(isa, 9, UPPER16(ejtag_info->reg9)));
+       pracc_add(&ctx, 0, MIPS32_SYNC(isa));
+       /* jump to start 18*/
+       pracc_add(&ctx, 0, MIPS32_B(isa, NEG16(ctx.code_count + 1)));
+       /* restore lower 16 of $9 15*/
+       pracc_add(&ctx, 0, MIPS32_ORI(isa, 9, 9, LOWER16(ejtag_info->reg9)));
+
+       ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, val, 1);
+exit:
+       pracc_queue_free(&ctx);
+       return ctx.retval;
+}
+
+/**
+ * mips32_pracc_write_dsp_reg - Write a value to a MIPS32 DSP register
+ * @param[in] ejtag_info: EJTAG information structure
+ * @param[in] val: Value to be written to the register
+ * @param[in] reg: Index of the DSP register to write
+ *
+ * @brief Writes the specified value to the specified MIPS32 DSP register.
+ *
+ * This function initiates a sequence of instructions to write the given value to the
+ * specified DSP register.
+ *
+ * @return ERROR_OK on success; error code on failure.
+ */
+static int mips32_pracc_write_dsp_reg(struct mips_ejtag *ejtag_info, uint32_t val, uint32_t reg)
+{
+       int isa = 0;
+
+       struct pracc_queue_info ctx = {
+               .max_code = 48,
+               .ejtag_info = ejtag_info
+       };
+
+       uint32_t dsp_write_code[] = {
+               MIPS32_MTHI(isa, t0),           /* mthi t0 ($ac0) - OPCODE - 0x01000011 */
+               MIPS32_DSP_MTHI(t0, 1),         /* mthi t0, $ac1 - OPCODE - 0x01000811 */
+               MIPS32_DSP_MTHI(t0, 2),         /* mthi t0, $ac2 - OPCODE - 0x01001011 */
+               MIPS32_DSP_MTHI(t0, 3),         /* mthi t0, $ac3 - OPCODE - 0x01001811 */
+               MIPS32_MTLO(isa, t0),           /* mtlo t0 ($ac0) - OPCODE - 0x01000013 */
+               MIPS32_DSP_MTLO(t0, 1),         /* mtlo t0, $ac1 - OPCODE - 0x01000813 */
+               MIPS32_DSP_MTLO(t0, 2),         /* mtlo t0, $ac2 - OPCODE - 0x01001013 */
+               MIPS32_DSP_MTLO(t0, 3),         /* mtlo t0, $ac3 - OPCODE - 0x01001813 */
+               MIPS32_DSP_WRDSP(t0, 0x1F), /* wrdsp t0, 0x1f (DSPCtl) - OPCODE - 0x7d00fcf8*/
+       };
+
+       /* Init context queue */
+       pracc_queue_init(&ctx);
+       if (ctx.retval != ERROR_OK)
+               goto exit;
+
+       /* Enables DSP whether its already enabled or not */
+       mips32_dsp_enable(&ctx, isa);
+
+       /* Load val to $8 (t0) */
+       pracc_add(&ctx, 0, MIPS32_LUI(isa, 8, UPPER16(val)));
+       pracc_add(&ctx, 0, MIPS32_ORI(isa, 8, 8, LOWER16(val)));
+
+       /* move AC or Control to $8 (t0) */
+       pracc_add(&ctx, 0, dsp_write_code[reg]);
+
+       /* nop, delay in order to ensure write */
+       pracc_add(&ctx, 0, MIPS32_NOP);
+       /* Restore status registers to previous setting */
+       mips32_dsp_restore(&ctx, isa);
+
+       /* move COP0 DeSave to $15 */
+       pracc_add(&ctx, 0, MIPS32_MFC0(isa, 15, 31, 0));
+
+       /* restore $8 */
+       pracc_add(&ctx, 0, MIPS32_LUI(isa, 8, UPPER16(ejtag_info->reg8)));
+       pracc_add(&ctx, 0, MIPS32_ORI(isa, 8, 8, LOWER16(ejtag_info->reg8)));
+
+       /* restore upper 16 of $9 */
+       pracc_add(&ctx, 0, MIPS32_LUI(isa, 9, UPPER16(ejtag_info->reg9)));
+
+       /* jump to start */
+       pracc_add(&ctx, 0, MIPS32_B(isa, NEG16(ctx.code_count + 1)));
+       /* restore lower 16 of $9  */
+       pracc_add(&ctx, 0, MIPS32_ORI(isa, 9, 9, LOWER16(ejtag_info->reg9)));
+
+       ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, NULL, 1);
+exit:
+       pracc_queue_free(&ctx);
+       return ctx.retval;
 }
 
 /**
@@ -1334,17 +1939,18 @@ COMMAND_HANDLER(mips32_handle_cpuinfo_command)
 
        char *instr;
        switch ((config3 & MIPS32_CONFIG3_ISA_MASK) >> MIPS32_CONFIG3_ISA_SHIFT) {
-               case 0:
-                       instr = "MIPS32";
+       case 0:
+               instr = "MIPS32";
                break;
-               case 1:
-                       instr = "microMIPS";
+       case 1:
+               instr = "microMIPS";
                break;
-               case 2:
-                       instr = "MIPS32 (at reset) and microMIPS";
+       case 2:
+               instr = "MIPS32 (at reset) and microMIPS";
                break;
-               case 3:
-                       instr = "microMIPS (at reset) and MIPS32";
+       case 3:
+       default:
+               instr = "microMIPS (at reset) and MIPS32";
                break;
        }
 
@@ -1472,6 +2078,230 @@ COMMAND_HANDLER(mips32_handle_cpuinfo_command)
        return ERROR_OK;
 }
 
+/**
+ * mips32_dsp_find_register_by_name - Find DSP register index by name
+ * @param[in] reg_name: Name of the DSP register to find
+ *
+ * @brief Searches for a DSP register by name and returns its index.
+ * If no match is found, it returns MIPS32NUMDSPREGS.
+ *
+ * @return Index of the found register or MIPS32NUMDSPREGS if not found.
+ */
+static int mips32_dsp_find_register_by_name(const char *reg_name)
+{
+       if (reg_name)
+               for (int i = 0; i < MIPS32NUMDSPREGS; i++) {
+                       if (strcmp(mips32_dsp_regs[i].name, reg_name) == 0)
+                               return i;
+               }
+       return MIPS32NUMDSPREGS;
+}
+
+/**
+ * mips32_dsp_get_all_regs - Get values of all MIPS32 DSP registers
+ * @param[in] cmd: Command invocation context
+ * @param[in] ejtag_info: EJTAG information structure
+ *
+ * @brief This function iterates through all DSP registers, reads their values,
+ * and prints each register name along with its corresponding value.
+ *
+ * @return ERROR_OK on success; error code on failure.
+ */
+static int mips32_dsp_get_all_regs(struct command_invocation *cmd, struct mips_ejtag *ejtag_info)
+{
+       uint32_t value = 0;
+       for (int i = 0; i < MIPS32NUMDSPREGS; i++) {
+               int retval = mips32_pracc_read_dsp_reg(ejtag_info, &value, i);
+               if (retval != ERROR_OK) {
+                       command_print(CMD, "couldn't access reg %s", mips32_dsp_regs[i].name);
+                       return retval;
+               }
+               command_print(CMD, "%*s: 0x%8.8x", 7, mips32_dsp_regs[i].name, value);
+       }
+       return ERROR_OK;
+}
+
+/**
+ * mips32_dsp_get_register - Get the value of a MIPS32 DSP register
+ * @param[in] cmd: Command invocation context
+ * @param[in] ejtag_info: EJTAG information structure
+ *
+ * @brief Retrieves the value of a specified MIPS32 DSP register.
+ * If the register is found, it reads the register value and prints the result.
+ * If the register is not found, it prints an error message.
+ *
+ * @return ERROR_OK on success; error code on failure.
+ */
+static int mips32_dsp_get_register(struct command_invocation *cmd, struct mips_ejtag *ejtag_info)
+{
+       uint32_t value = 0;
+       int index = mips32_dsp_find_register_by_name(CMD_ARGV[0]);
+       if (index == MIPS32NUMDSPREGS) {
+               command_print(CMD, "ERROR: register '%s' not found", CMD_ARGV[0]);
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+
+       int retval = mips32_pracc_read_dsp_reg(ejtag_info, &value, index);
+       if (retval != ERROR_OK)
+               command_print(CMD, "ERROR: Could not access dsp register %s", CMD_ARGV[0]);
+       else
+               command_print(CMD, "0x%8.8x", value);
+
+       return retval;
+}
+
+/**
+ * mips32_dsp_set_register - Set the value of a MIPS32 DSP register
+ * @param[in] cmd: Command invocation context
+ * @param[in] ejtag_info: EJTAG information structure
+ *
+ * @brief Sets the value of a specified MIPS32 DSP register.
+ * If the register is found, it writes provided value to the register.
+ * If the register is not found or there is an error in writing the value,
+ * it prints an error message.
+ *
+ * @return ERROR_OK on success; error code on failure.
+ */
+static int mips32_dsp_set_register(struct command_invocation *cmd, struct mips_ejtag *ejtag_info)
+{
+       uint32_t value;
+       int index = mips32_dsp_find_register_by_name(CMD_ARGV[0]);
+       if (index == MIPS32NUMDSPREGS) {
+               command_print(CMD, "ERROR: register '%s' not found", CMD_ARGV[0]);
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+
+       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value);
+
+       int retval = mips32_pracc_write_dsp_reg(ejtag_info, value, index);
+       if (retval != ERROR_OK)
+               command_print(CMD, "Error: could not write to dsp register %s", CMD_ARGV[0]);
+
+       return retval;
+}
+
+/**
+ * mips32_handle_dsp_command - Handles mips dsp related command
+ * @param[in] cmd: Command invocation context
+ *
+ * @brief Reads or sets the content of each dsp register.
+ *
+ * @return ERROR_OK on success; error code on failure.
+*/
+COMMAND_HANDLER(mips32_handle_dsp_command)
+{
+       int retval, tmp;
+       struct target *target = get_current_target(CMD_CTX);
+       struct mips32_common *mips32 = target_to_mips32(target);
+       struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
+
+       retval = mips32_verify_pointer(CMD, mips32);
+       if (retval != ERROR_OK)
+               return retval;
+
+       if (target->state != TARGET_HALTED) {
+               command_print(CMD, "target must be stopped for \"%s\" command", CMD_NAME);
+               return ERROR_OK;
+       }
+
+       /* Check for too many command args */
+       if (CMD_ARGC >= 3)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       /* Check if DSP access supported or not */
+       if (!mips32->dsp_imp) {
+               /* Issue Error Message */
+               command_print(CMD, "DSP not implemented by this processor");
+               return ERROR_OK;
+       }
+
+       switch (CMD_ARGC) {
+               case 0:
+                       retval = mips32_dsp_get_all_regs(CMD, ejtag_info);
+                       break;
+               case 1:
+                       retval = mips32_dsp_get_register(CMD, ejtag_info);
+                       break;
+               case 2:
+                       tmp = *CMD_ARGV[0];
+                       if (isdigit(tmp)) {
+                               command_print(CMD, "Error: invalid dsp command format");
+                               retval = ERROR_COMMAND_ARGUMENT_INVALID;
+                       } else {
+                               retval = mips32_dsp_set_register(CMD, ejtag_info);
+                       }
+                       break;
+               default:
+                       command_print(CMD, "Error: invalid argument format, required 0-2, given %d", CMD_ARGC);
+                       retval = ERROR_COMMAND_ARGUMENT_INVALID;
+                       break;
+       }
+       return retval;
+}
+
+/**
+ * mips32_handle_ejtag_reg_command - Handler commands related to EJTAG
+ * @param[in] cmd: Command invocation context
+ *
+ * @brief Prints all EJTAG Registers including DCR features.
+ *
+ * @return ERROR_OK on success; error code on failure.
+ */
+COMMAND_HANDLER(mips32_handle_ejtag_reg_command)
+{
+       struct target *target = get_current_target(CMD_CTX);
+       struct mips32_common *mips32 = target_to_mips32(target);
+       struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
+
+       uint32_t ejtag_ctrl;
+       uint32_t dcr;
+       int retval;
+
+       retval = mips_ejtag_get_idcode(ejtag_info);
+       if (retval != ERROR_OK)
+               command_print(CMD, "Error: Encounter an Error while getting idcode");
+       else
+               command_print(CMD, "       idcode: 0x%8.8" PRIx32, ejtag_info->idcode);
+
+       retval = mips_ejtag_get_impcode(ejtag_info);
+       if (retval != ERROR_OK)
+               command_print(CMD, "Error: Encounter an Error while getting impcode");
+       else
+               command_print(CMD, "      impcode: 0x%8.8" PRIx32, ejtag_info->impcode);
+
+       mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL);
+       ejtag_ctrl = ejtag_info->ejtag_ctrl;
+       retval = mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl);
+       if (retval != ERROR_OK)
+               command_print(CMD, "Error: Encounter an Error while executing drscan reading EJTAG Control register");
+       else
+               command_print(CMD, "ejtag control: 0x%8.8" PRIx32, ejtag_ctrl);
+
+       ejtag_main_print_imp(ejtag_info);
+
+       /* Display current DCR */
+       retval = target_read_u32(target, EJTAG_DCR, &dcr);
+       if (retval != ERROR_OK)
+               command_print(CMD, "Error: Encounter an Error while reading Debug Control Register");
+       else
+               command_print(CMD, "          DCR: 0x%8.8" PRIx32, dcr);
+
+       for (unsigned int i = 0; i < EJTAG_DCR_ENTRIES; i++) {
+               if (dcr & BIT(dcr_features[i].bit))
+                       command_print(CMD, "%s supported", dcr_features[i].name);
+       }
+
+       return ERROR_OK;
+}
+
+/**
+ * mips32_handle_scan_delay_command - Handler command for changing scan delay
+ * @param[in] cmd: Command invocation context
+ *
+ * @brief Changes current scan mode between legacy and fast queued mode.
+ *
+ * @return ERROR_OK on success; error code on failure.
+ */
 COMMAND_HANDLER(mips32_handle_scan_delay_command)
 {
        struct target *target = get_current_target(CMD_CTX);
@@ -1500,7 +2330,7 @@ static const struct command_registration mips32_exec_command_handlers[] = {
                .name = "cp0",
                .handler = mips32_handle_cp0_command,
                .mode = COMMAND_EXEC,
-               .usage = "regnum select [value]",
+               .usage = "[[reg_name|regnum select] [value]]",
                .help = "display/modify cp0 register",
        },
        {
@@ -1510,6 +2340,14 @@ static const struct command_registration mips32_exec_command_handlers[] = {
                .help = "display CPU information",
                .usage = "",
        },
+       {
+               .name = "dsp",
+               .handler = mips32_handle_dsp_command,
+               .mode = COMMAND_EXEC,
+               .help = "display or set DSP register; "
+                       "with no arguments, displays all registers and their values",
+               .usage = "[[register_name] [value]]",
+       },
        {
                .name = "scan_delay",
                .handler = mips32_handle_scan_delay_command,
@@ -1517,6 +2355,13 @@ static const struct command_registration mips32_exec_command_handlers[] = {
                .help = "display/set scan delay in nano seconds",
                .usage = "[value]",
        },
+       {
+               .name = "ejtag_reg",
+               .handler = mips32_handle_ejtag_reg_command,
+               .mode = COMMAND_ANY,
+               .help = "read ejtag registers",
+               .usage = "",
+       },
        COMMAND_REGISTRATION_DONE
 };
 

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)