openocd: fix SPDX tag format for files .c
[openocd.git] / src / target / riscv / riscv-011.c
index 3820d8fc0ff896479d243a77e987a711ddc0239f..be296cdd8c68cd244d551078c653316f36bc9c7c 100644 (file)
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
 /*
  * Support for RISC-V, debug version 0.11. This was never an officially adopted
  * spec, but SiFive made some silicon that uses it.
@@ -14,7 +16,7 @@
 #include "target/target.h"
 #include "target/algorithm.h"
 #include "target/target_type.h"
-#include "log.h"
+#include <helper/log.h>
 #include "jtag/jtag.h"
 #include "target/register.h"
 #include "target/breakpoints.h"
@@ -68,8 +70,6 @@
 #define get_field(reg, mask) (((reg) & (mask)) / ((mask) & ~((mask) << 1)))
 #define set_field(reg, mask, val) (((reg) & ~(mask)) | (((val) * ((mask) & ~((mask) << 1))) & (mask)))
 
-#define DIM(x)         (sizeof(x)/sizeof(*x))
-
 /* Constants for legacy SiFive hardware breakpoints. */
 #define CSR_BPCONTROL_X                        (1<<0)
 #define CSR_BPCONTROL_W                        (1<<1)
@@ -152,6 +152,9 @@ typedef enum slot {
 #define DMINFO_AUTHTYPE                        (3<<2)
 #define DMINFO_VERSION                 3
 
+#define DMAUTHDATA0                            0x12
+#define DMAUTHDATA1                            0x13
+
 /*** Info about the core being debugged. ***/
 
 #define DBUS_ADDRESS_UNKNOWN   0xffff
@@ -204,7 +207,6 @@ typedef struct {
         * before the interrupt is cleared. */
        unsigned int interrupt_high_delay;
 
-       bool need_strict_step;
        bool never_halted;
 } riscv011_info_t;
 
@@ -217,8 +219,7 @@ typedef struct {
 
 static int poll_target(struct target *target, bool announce);
 static int riscv011_poll(struct target *target);
-static int get_register(struct target *target, riscv_reg_t *value, int hartid,
-               int regid);
+static int get_register(struct target *target, riscv_reg_t *value, int regid);
 
 /*** Utility functions. ***/
 
@@ -226,8 +227,10 @@ static int get_register(struct target *target, riscv_reg_t *value, int hartid,
 
 static riscv011_info_t *get_info(const struct target *target)
 {
-       riscv_info_t *info = (riscv_info_t *) target->arch_info;
-       return (riscv011_info_t *) info->version_specific;
+       struct riscv_info *info = target->arch_info;
+       assert(info);
+       assert(info->version_specific);
+       return info->version_specific;
 }
 
 static unsigned int slot_offset(const struct target *target, slot_t slot)
@@ -280,7 +283,7 @@ static uint32_t dtmcontrol_scan(struct target *target, uint32_t out)
 {
        struct scan_field field;
        uint8_t in_value[4];
-       uint8_t out_value[4];
+       uint8_t out_value[4] = { 0 };
 
        buf_set_u32(out_value, 0, 32, out);
 
@@ -358,6 +361,15 @@ static void add_dbus_scan(const struct target *target, struct scan_field *field,
                uint16_t address, uint64_t data)
 {
        riscv011_info_t *info = get_info(target);
+       RISCV_INFO(r);
+
+       if (r->reset_delays_wait >= 0) {
+               r->reset_delays_wait--;
+               if (r->reset_delays_wait < 0) {
+                       info->dbus_busy_delay = 0;
+                       info->interrupt_high_delay = 0;
+               }
+       }
 
        field->num_bits = info->addrbits + DBUS_OP_SIZE + DBUS_DATA_SIZE;
        field->in_value = in_value;
@@ -413,7 +425,7 @@ static dbus_status_t dbus_scan(struct target *target, uint16_t *address_in,
 {
        riscv011_info_t *info = get_info(target);
        uint8_t in[8] = {0};
-       uint8_t out[8];
+       uint8_t out[8] = {0};
        struct scan_field field = {
                .num_bits = info->addrbits + DBUS_OP_SIZE + DBUS_DATA_SIZE,
                .out_value = out,
@@ -510,6 +522,8 @@ typedef struct {
 static scans_t *scans_new(struct target *target, unsigned int scan_count)
 {
        scans_t *scans = malloc(sizeof(scans_t));
+       if (!scans)
+               goto error0;
        scans->scan_count = scan_count;
        /* This code also gets called before xlen is detected. */
        if (riscv_xlen(target))
@@ -518,10 +532,25 @@ static scans_t *scans_new(struct target *target, unsigned int scan_count)
                scans->scan_size = 2 + 128 / 8;
        scans->next_scan = 0;
        scans->in = calloc(scans->scan_size, scans->scan_count);
+       if (!scans->in)
+               goto error1;
        scans->out = calloc(scans->scan_size, scans->scan_count);
+       if (!scans->out)
+               goto error2;
        scans->field = calloc(scans->scan_count, sizeof(struct scan_field));
+       if (!scans->field)
+               goto error3;
        scans->target = target;
        return scans;
+
+error3:
+       free(scans->out);
+error2:
+       free(scans->in);
+error1:
+       free(scans);
+error0:
+       return NULL;
 }
 
 static scans_t *scans_delete(scans_t *scans)
@@ -835,6 +864,8 @@ static int cache_write(struct target *target, unsigned int address, bool run)
        LOG_DEBUG("enter");
        riscv011_info_t *info = get_info(target);
        scans_t *scans = scans_new(target, info->dramsize + 2);
+       if (!scans)
+               return ERROR_FAIL;
 
        unsigned int last = info->dramsize;
        for (unsigned int i = 0; i < info->dramsize; i++) {
@@ -1003,7 +1034,7 @@ static int wait_for_state(struct target *target, enum target_state state)
        }
 }
 
-static int read_csr(struct target *target, uint64_t *value, uint32_t csr)
+static int read_remote_csr(struct target *target, uint64_t *value, uint32_t csr)
 {
        riscv011_info_t *info = get_info(target);
        cache_set32(target, 0, csrr(S0, csr));
@@ -1025,7 +1056,7 @@ static int read_csr(struct target *target, uint64_t *value, uint32_t csr)
        return ERROR_OK;
 }
 
-static int write_csr(struct target *target, uint32_t csr, uint64_t value)
+static int write_remote_csr(struct target *target, uint32_t csr, uint64_t value)
 {
        LOG_DEBUG("csr 0x%x <- 0x%" PRIx64, csr, value);
        cache_set_load(target, 0, S0, SLOT0);
@@ -1053,7 +1084,7 @@ static int maybe_read_tselect(struct target *target)
        riscv011_info_t *info = get_info(target);
 
        if (info->tselect_dirty) {
-               int result = read_csr(target, &info->tselect, CSR_TSELECT);
+               int result = read_remote_csr(target, &info->tselect, CSR_TSELECT);
                if (result != ERROR_OK)
                        return result;
                info->tselect_dirty = false;
@@ -1067,7 +1098,7 @@ static int maybe_write_tselect(struct target *target)
        riscv011_info_t *info = get_info(target);
 
        if (!info->tselect_dirty) {
-               int result = write_csr(target, CSR_TSELECT, info->tselect);
+               int result = write_remote_csr(target, CSR_TSELECT, info->tselect);
                if (result != ERROR_OK)
                        return result;
                info->tselect_dirty = true;
@@ -1106,7 +1137,10 @@ static int execute_resume(struct target *target, bool step)
                }
        }
 
-       info->dcsr |= DCSR_EBREAKM | DCSR_EBREAKH | DCSR_EBREAKS | DCSR_EBREAKU;
+       info->dcsr = set_field(info->dcsr, DCSR_EBREAKM, riscv_ebreakm);
+       info->dcsr = set_field(info->dcsr, DCSR_EBREAKS, riscv_ebreaks);
+       info->dcsr = set_field(info->dcsr, DCSR_EBREAKU, riscv_ebreaku);
+       info->dcsr = set_field(info->dcsr, DCSR_EBREAKH, 1);
        info->dcsr &= ~DCSR_HALT;
 
        if (step)
@@ -1200,7 +1234,7 @@ static int update_mstatus_actual(struct target *target)
        /* Force reading the register. In that process mstatus_actual will be
         * updated. */
        riscv_reg_t mstatus;
-       return get_register(target, &mstatus, 0, GDB_REGNO_MSTATUS);
+       return get_register(target, &mstatus, GDB_REGNO_MSTATUS);
 }
 
 /*** OpenOCD target functions. ***/
@@ -1246,7 +1280,7 @@ static int register_write(struct target *target, unsigned int number,
 
        if (number == S0) {
                cache_set_load(target, 0, S0, SLOT0);
-               cache_set32(target, 1, csrw(S0, CSR_DSCRATCH));
+               cache_set32(target, 1, csrw(S0, CSR_DSCRATCH0));
                cache_set_jump(target, 2);
        } else if (number == S1) {
                cache_set_load(target, 0, S0, SLOT0);
@@ -1304,10 +1338,8 @@ static int register_write(struct target *target, unsigned int number,
        return ERROR_OK;
 }
 
-static int get_register(struct target *target, riscv_reg_t *value, int hartid,
-               int regid)
+static int get_register(struct target *target, riscv_reg_t *value, int regid)
 {
-       assert(hartid == 0);
        riscv011_info_t *info = get_info(target);
 
        maybe_write_tselect(target);
@@ -1350,10 +1382,8 @@ static int get_register(struct target *target, riscv_reg_t *value, int hartid,
        return ERROR_OK;
 }
 
-static int set_register(struct target *target, int hartid, int regid,
-               uint64_t value)
+static int set_register(struct target *target, int regid, uint64_t value)
 {
-       assert(hartid == 0);
        return register_write(target, regid, value);
 }
 
@@ -1375,45 +1405,21 @@ static int halt(struct target *target)
        return ERROR_OK;
 }
 
-static int init_target(struct command_context *cmd_ctx,
-               struct target *target)
-{
-       LOG_DEBUG("init");
-       riscv_info_t *generic_info = (riscv_info_t *) target->arch_info;
-       generic_info->get_register = get_register;
-       generic_info->set_register = set_register;
-
-       generic_info->version_specific = calloc(1, sizeof(riscv011_info_t));
-       if (!generic_info->version_specific)
-               return ERROR_FAIL;
-
-       /* Assume 32-bit until we discover the real value in examine(). */
-       generic_info->xlen[0] = 32;
-       riscv_init_registers(target);
-
-       return ERROR_OK;
-}
-
 static void deinit_target(struct target *target)
 {
        LOG_DEBUG("riscv_deinit_target()");
-       riscv_info_t *info = (riscv_info_t *) target->arch_info;
+       struct riscv_info *info = target->arch_info;
+       if (!info)
+               return;
+
        free(info->version_specific);
        info->version_specific = NULL;
 }
 
 static int strict_step(struct target *target, bool announce)
 {
-       riscv011_info_t *info = get_info(target);
-
        LOG_DEBUG("enter");
 
-       struct breakpoint *breakpoint = target->breakpoints;
-       while (breakpoint) {
-               riscv_remove_breakpoint(target, breakpoint);
-               breakpoint = breakpoint->next;
-       }
-
        struct watchpoint *watchpoint = target->watchpoints;
        while (watchpoint) {
                riscv_remove_watchpoint(target, watchpoint);
@@ -1424,28 +1430,18 @@ static int strict_step(struct target *target, bool announce)
        if (result != ERROR_OK)
                return result;
 
-       breakpoint = target->breakpoints;
-       while (breakpoint) {
-               riscv_add_breakpoint(target, breakpoint);
-               breakpoint = breakpoint->next;
-       }
-
        watchpoint = target->watchpoints;
        while (watchpoint) {
                riscv_add_watchpoint(target, watchpoint);
                watchpoint = watchpoint->next;
        }
 
-       info->need_strict_step = false;
-
        return ERROR_OK;
 }
 
 static int step(struct target *target, int current, target_addr_t address,
                int handle_breakpoints)
 {
-       riscv011_info_t *info = get_info(target);
-
        jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE);
 
        if (!current) {
@@ -1458,12 +1454,12 @@ static int step(struct target *target, int current, target_addr_t address,
                        return result;
        }
 
-       if (info->need_strict_step || handle_breakpoints) {
+       if (handle_breakpoints) {
                int result = strict_step(target, true);
                if (result != ERROR_OK)
                        return result;
        } else {
-               return resume(target, 0, true);
+               return full_step(target, false);
        }
 
        return ERROR_OK;
@@ -1489,7 +1485,6 @@ static int examine(struct target *target)
        }
 
        RISCV_INFO(r);
-       r->hart_count = 1;
 
        riscv011_info_t *info = get_info(target);
        info->addrbits = get_field(dtmcontrol, DTMCONTROL_ADDRBITS);
@@ -1531,7 +1526,7 @@ static int examine(struct target *target)
        }
 
        /* Pretend this is a 32-bit system until we have found out the true value. */
-       r->xlen[0] = 32;
+       r->xlen = 32;
 
        /* Figure out XLEN, and test writing all of Debug RAM while we're at it. */
        cache_set32(target, 0, xori(S1, ZERO, -1));
@@ -1557,13 +1552,13 @@ static int examine(struct target *target)
 
        uint32_t word0 = cache_get32(target, 0);
        uint32_t word1 = cache_get32(target, 1);
-       riscv_info_t *generic_info = (riscv_info_t *) target->arch_info;
+       struct riscv_info *generic_info = riscv_info(target);
        if (word0 == 1 && word1 == 0) {
-               generic_info->xlen[0] = 32;
+               generic_info->xlen = 32;
        } else if (word0 == 0xffffffff && word1 == 3) {
-               generic_info->xlen[0] = 64;
+               generic_info->xlen = 64;
        } else if (word0 == 0xffffffff && word1 == 0xffffffff) {
-               generic_info->xlen[0] = 128;
+               generic_info->xlen = 128;
        } else {
                uint32_t exception = cache_get32(target, info->dramsize-1);
                LOG_ERROR("Failed to discover xlen; word0=0x%x, word1=0x%x, exception=0x%x",
@@ -1573,11 +1568,11 @@ static int examine(struct target *target)
        }
        LOG_DEBUG("Discovered XLEN is %d", riscv_xlen(target));
 
-       if (read_csr(target, &r->misa[0], CSR_MISA) != ERROR_OK) {
+       if (read_remote_csr(target, &r->misa, CSR_MISA) != ERROR_OK) {
                const unsigned old_csr_misa = 0xf10;
                LOG_WARNING("Failed to read misa at 0x%x; trying 0x%x.", CSR_MISA,
                                old_csr_misa);
-               if (read_csr(target, &r->misa[0], old_csr_misa) != ERROR_OK) {
+               if (read_remote_csr(target, &r->misa, old_csr_misa) != ERROR_OK) {
                        /* Maybe this is an old core that still has $misa at the old
                         * address. */
                        LOG_ERROR("Failed to read misa at 0x%x.", old_csr_misa);
@@ -1599,7 +1594,7 @@ static int examine(struct target *target)
        for (size_t i = 0; i < 32; ++i)
                reg_cache_set(target, i, -1);
        LOG_INFO("Examined RISCV core; XLEN=%d, misa=0x%" PRIx64,
-                       riscv_xlen(target), r->misa[0]);
+                       riscv_xlen(target), r->misa);
 
        return ERROR_OK;
 }
@@ -1609,6 +1604,8 @@ static riscv_error_t handle_halt_routine(struct target *target)
        riscv011_info_t *info = get_info(target);
 
        scans_t *scans = scans_new(target, 256);
+       if (!scans)
+               return RE_FAIL;
 
        /* Read all GPRs as fast as we can, because gdb is going to ask for them
         * anyway. Reading them one at a time is much slower. */
@@ -1637,8 +1634,8 @@ static riscv_error_t handle_halt_routine(struct target *target)
        scans_add_read(scans, SLOT0, false);
 
        /* Read S0 from dscratch */
-       unsigned int csr[] = {CSR_DSCRATCH, CSR_DPC, CSR_DCSR};
-       for (unsigned int i = 0; i < DIM(csr); i++) {
+       unsigned int csr[] = {CSR_DSCRATCH0, CSR_DPC, CSR_DCSR};
+       for (unsigned int i = 0; i < ARRAY_SIZE(csr); i++) {
                scans_add_write32(scans, 0, csrr(S0, csr[i]), true);
                scans_add_read(scans, SLOT0, false);
        }
@@ -1676,7 +1673,7 @@ static riscv_error_t handle_halt_routine(struct target *target)
                                break;
                        default:
                                LOG_ERROR("Got invalid bus access status: %d", status);
-                               return ERROR_FAIL;
+                               goto error;
                }
                if (data & DMCONTROL_INTERRUPT) {
                        interrupt_set++;
@@ -1806,6 +1803,8 @@ static riscv_error_t handle_halt_routine(struct target *target)
                }
        }
 
+       scans_delete(scans);
+
        if (dbus_busy) {
                increase_dbus_busy_delay(target);
                return RE_AGAIN;
@@ -1819,8 +1818,6 @@ static riscv_error_t handle_halt_routine(struct target *target)
        info->dpc = reg_cache_get(target, CSR_DPC);
        info->dcsr = reg_cache_get(target, CSR_DCSR);
 
-       scans_delete(scans);
-
        cache_invalidate(target);
 
        return RE_OK;
@@ -1850,10 +1847,7 @@ static int handle_halt(struct target *target, bool announce)
                        target->debug_reason = DBG_REASON_BREAKPOINT;
                        break;
                case DCSR_CAUSE_HWBP:
-                       target->debug_reason = DBG_REASON_WPTANDBKPT;
-                       /* If we halted because of a data trigger, gdb doesn't know to do
-                        * the disable-breakpoints-step-enable-breakpoints dance. */
-                       info->need_strict_step = true;
+                       target->debug_reason = DBG_REASON_WATCHPOINT;
                        break;
                case DCSR_CAUSE_DEBUGINT:
                        target->debug_reason = DBG_REASON_DBGRQ;
@@ -1938,26 +1932,10 @@ static int riscv011_poll(struct target *target)
 static int riscv011_resume(struct target *target, int current,
                target_addr_t address, int handle_breakpoints, int debug_execution)
 {
-       riscv011_info_t *info = get_info(target);
-
+       RISCV_INFO(r);
        jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE);
 
-       if (!current) {
-               if (riscv_xlen(target) > 32) {
-                       LOG_WARNING("Asked to resume at 32-bit PC on %d-bit target.",
-                                       riscv_xlen(target));
-               }
-               int result = register_write(target, GDB_REGNO_PC, address);
-               if (result != ERROR_OK)
-                       return result;
-       }
-
-       if (info->need_strict_step || handle_breakpoints) {
-               int result = strict_step(target, false);
-               if (result != ERROR_OK)
-                       return result;
-       }
-
+       r->prepped = false;
        return resume(target, debug_execution, false);
 }
 
@@ -1976,8 +1954,11 @@ static int assert_reset(struct target *target)
 
        /* Not sure what we should do when there are multiple cores.
         * Here just reset the single hart we're talking to. */
-       info->dcsr |= DCSR_EBREAKM | DCSR_EBREAKH | DCSR_EBREAKS |
-               DCSR_EBREAKU | DCSR_HALT;
+       info->dcsr = set_field(info->dcsr, DCSR_EBREAKM, riscv_ebreakm);
+       info->dcsr = set_field(info->dcsr, DCSR_EBREAKS, riscv_ebreaks);
+       info->dcsr = set_field(info->dcsr, DCSR_EBREAKU, riscv_ebreaku);
+       info->dcsr = set_field(info->dcsr, DCSR_EBREAKH, 1);
+       info->dcsr |= DCSR_HALT;
        if (target->reset_halt)
                info->dcsr |= DCSR_NDRESET;
        else
@@ -2004,8 +1985,13 @@ static int deassert_reset(struct target *target)
 }
 
 static int read_memory(struct target *target, target_addr_t address,
-               uint32_t size, uint32_t count, uint8_t *buffer)
+               uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment)
 {
+       if (increment != size) {
+               LOG_ERROR("read_memory with custom increment not implemented");
+               return ERROR_NOT_IMPLEMENTED;
+       }
+
        jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE);
 
        cache_set32(target, 0, lw(S0, ZERO, DEBUG_RAM_START + 16));
@@ -2032,6 +2018,8 @@ static int read_memory(struct target *target, target_addr_t address,
        riscv011_info_t *info = get_info(target);
        const unsigned max_batch_size = 256;
        scans_t *scans = scans_new(target, max_batch_size);
+       if (!scans)
+               return ERROR_FAIL;
 
        uint32_t result_value = 0x777;
        uint32_t i = 0;
@@ -2188,6 +2176,8 @@ static int write_memory(struct target *target, target_addr_t address,
 
        const unsigned max_batch_size = 256;
        scans_t *scans = scans_new(target, max_batch_size);
+       if (!scans)
+               return ERROR_FAIL;
 
        uint32_t result_value = 0x777;
        uint32_t i = 0;
@@ -2307,6 +2297,100 @@ static int arch_state(struct target *target)
        return ERROR_OK;
 }
 
+static COMMAND_HELPER(riscv011_print_info, struct target *target)
+{
+       /* Abstract description. */
+       riscv_print_info_line(CMD, "target", "memory.read_while_running8", 0);
+       riscv_print_info_line(CMD, "target", "memory.write_while_running8", 0);
+       riscv_print_info_line(CMD, "target", "memory.read_while_running16", 0);
+       riscv_print_info_line(CMD, "target", "memory.write_while_running16", 0);
+       riscv_print_info_line(CMD, "target", "memory.read_while_running32", 0);
+       riscv_print_info_line(CMD, "target", "memory.write_while_running32", 0);
+       riscv_print_info_line(CMD, "target", "memory.read_while_running64", 0);
+       riscv_print_info_line(CMD, "target", "memory.write_while_running64", 0);
+       riscv_print_info_line(CMD, "target", "memory.read_while_running128", 0);
+       riscv_print_info_line(CMD, "target", "memory.write_while_running128", 0);
+
+       uint32_t dminfo = dbus_read(target, DMINFO);
+       riscv_print_info_line(CMD, "dm", "authenticated", get_field(dminfo, DMINFO_AUTHENTICATED));
+
+       return 0;
+}
+
+static int wait_for_authbusy(struct target *target)
+{
+       time_t start = time(NULL);
+       while (1) {
+               uint32_t dminfo = dbus_read(target, DMINFO);
+               if (!get_field(dminfo, DMINFO_AUTHBUSY))
+                       break;
+               if (time(NULL) - start > riscv_command_timeout_sec) {
+                       LOG_ERROR("Timed out after %ds waiting for authbusy to go low (dminfo=0x%x). "
+                                       "Increase the timeout with riscv set_command_timeout_sec.",
+                                       riscv_command_timeout_sec,
+                                       dminfo);
+                       return ERROR_FAIL;
+               }
+       }
+
+       return ERROR_OK;
+}
+
+static int riscv011_authdata_read(struct target *target, uint32_t *value, unsigned int index)
+{
+       if (index > 1) {
+               LOG_ERROR("Spec 0.11 only has a two authdata registers.");
+               return ERROR_FAIL;
+       }
+
+       if (wait_for_authbusy(target) != ERROR_OK)
+               return ERROR_FAIL;
+
+       uint16_t authdata_address = index ? DMAUTHDATA1 : DMAUTHDATA0;
+       *value = dbus_read(target, authdata_address);
+
+       return ERROR_OK;
+}
+
+static int riscv011_authdata_write(struct target *target, uint32_t value, unsigned int index)
+{
+       if (index > 1) {
+               LOG_ERROR("Spec 0.11 only has a two authdata registers.");
+               return ERROR_FAIL;
+       }
+
+       if (wait_for_authbusy(target) != ERROR_OK)
+               return ERROR_FAIL;
+
+       uint16_t authdata_address = index ? DMAUTHDATA1 : DMAUTHDATA0;
+       dbus_write(target, authdata_address, value);
+
+       return ERROR_OK;
+}
+
+static int init_target(struct command_context *cmd_ctx,
+               struct target *target)
+{
+       LOG_DEBUG("init");
+       RISCV_INFO(generic_info);
+       generic_info->get_register = get_register;
+       generic_info->set_register = set_register;
+       generic_info->read_memory = read_memory;
+       generic_info->authdata_read = &riscv011_authdata_read;
+       generic_info->authdata_write = &riscv011_authdata_write;
+       generic_info->print_info = &riscv011_print_info;
+
+       generic_info->version_specific = calloc(1, sizeof(riscv011_info_t));
+       if (!generic_info->version_specific)
+               return ERROR_FAIL;
+
+       /* Assume 32-bit until we discover the real value in examine(). */
+       generic_info->xlen = 32;
+       riscv_init_registers(target);
+
+       return ERROR_OK;
+}
+
 struct target_type riscv011_target = {
        .name = "riscv",
 
@@ -2324,7 +2408,6 @@ struct target_type riscv011_target = {
        .assert_reset = assert_reset,
        .deassert_reset = deassert_reset,
 
-       .read_memory = read_memory,
        .write_memory = write_memory,
 
        .arch_state = arch_state,

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)