helper: Remove src/helper from include dirs
[openocd.git] / src / target / riscv / riscv.c
index b5fd22b481e690258a2d7c480cd7370f3baec9d6..07fb95550c99cf379753e4b3c37be67f34755425 100644 (file)
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
 #include <assert.h>
 #include <stdlib.h>
 #include <time.h>
@@ -6,65 +8,21 @@
 #include "config.h"
 #endif
 
+#include <helper/log.h>
+#include <helper/time_support.h>
 #include "target/target.h"
 #include "target/algorithm.h"
 #include "target/target_type.h"
-#include "log.h"
 #include "jtag/jtag.h"
 #include "target/register.h"
 #include "target/breakpoints.h"
-#include "helper/time_support.h"
 #include "riscv.h"
 #include "gdb_regs.h"
 #include "rtos/rtos.h"
 
-/**
- * Since almost everything can be accomplish by scanning the dbus register, all
- * functions here assume dbus is already selected. The exception are functions
- * called directly by OpenOCD, which can't assume anything about what's
- * currently in IR. They should set IR to dbus explicitly.
- */
-
-/**
- * Code structure
- *
- * At the bottom of the stack are the OpenOCD JTAG functions:
- *             jtag_add_[id]r_scan
- *             jtag_execute_query
- *             jtag_add_runtest
- *
- * There are a few functions to just instantly shift a register and get its
- * value:
- *             dtmcontrol_scan
- *             idcode_scan
- *             dbus_scan
- *
- * Because doing one scan and waiting for the result is slow, most functions
- * batch up a bunch of dbus writes and then execute them all at once. They use
- * the scans "class" for this:
- *             scans_new
- *             scans_delete
- *             scans_execute
- *             scans_add_...
- * Usually you new(), call a bunch of add functions, then execute() and look
- * at the results by calling scans_get...()
- *
- * Optimized functions will directly use the scans class above, but slightly
- * lazier code will use the cache functions that in turn use the scans
- * functions:
- *             cache_get...
- *             cache_set...
- *             cache_write
- * cache_set... update a local structure, which is then synced to the target
- * with cache_write(). Only Debug RAM words that are actually changed are sent
- * to the target. Afterwards use cache_get... to read results.
- */
-
 #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)
@@ -108,12 +66,6 @@ typedef enum {
 #define DBUS_DATA_SIZE                         34
 #define DBUS_ADDRESS_START                     36
 
-typedef enum {
-       RE_OK,
-       RE_FAIL,
-       RE_AGAIN
-} riscv_error_t;
-
 typedef enum slot {
        SLOT0,
        SLOT1,
@@ -170,6 +122,71 @@ struct scan_field select_idcode = {
        .out_value = ir_idcode
 };
 
+bscan_tunnel_type_t bscan_tunnel_type;
+int bscan_tunnel_ir_width; /* if zero, then tunneling is not present/active */
+
+static uint8_t bscan_zero[4] = {0};
+static uint8_t bscan_one[4] = {1};
+
+uint8_t ir_user4[4] = {0x23};
+struct scan_field select_user4 = {
+       .in_value = NULL,
+       .out_value = ir_user4
+};
+
+
+uint8_t bscan_tunneled_ir_width[4] = {5};  /* overridden by assignment in riscv_init_target */
+struct scan_field _bscan_tunnel_data_register_select_dmi[] = {
+               {
+                       .num_bits = 3,
+                       .out_value = bscan_zero,
+                       .in_value = NULL,
+               },
+               {
+                       .num_bits = 5, /* initialized in riscv_init_target to ir width of DM */
+                       .out_value = ir_dbus,
+                       .in_value = NULL,
+               },
+               {
+                       .num_bits = 7,
+                       .out_value = bscan_tunneled_ir_width,
+                       .in_value = NULL,
+               },
+               {
+                       .num_bits = 1,
+                       .out_value = bscan_zero,
+                       .in_value = NULL,
+               }
+};
+
+struct scan_field _bscan_tunnel_nested_tap_select_dmi[] = {
+               {
+                       .num_bits = 1,
+                       .out_value = bscan_zero,
+                       .in_value = NULL,
+               },
+               {
+                       .num_bits = 7,
+                       .out_value = bscan_tunneled_ir_width,
+                       .in_value = NULL,
+               },
+               {
+                       .num_bits = 0, /* initialized in riscv_init_target to ir width of DM */
+                       .out_value = ir_dbus,
+                       .in_value = NULL,
+               },
+               {
+                       .num_bits = 3,
+                       .out_value = bscan_zero,
+                       .in_value = NULL,
+               }
+};
+struct scan_field *bscan_tunnel_nested_tap_select_dmi = _bscan_tunnel_nested_tap_select_dmi;
+uint32_t bscan_tunnel_nested_tap_select_dmi_num_fields = ARRAY_SIZE(_bscan_tunnel_nested_tap_select_dmi);
+
+struct scan_field *bscan_tunnel_data_register_select_dmi = _bscan_tunnel_data_register_select_dmi;
+uint32_t bscan_tunnel_data_register_select_dmi_num_fields = ARRAY_SIZE(_bscan_tunnel_data_register_select_dmi);
+
 struct trigger {
        uint64_t address;
        uint32_t length;
@@ -186,6 +203,12 @@ int riscv_command_timeout_sec = DEFAULT_COMMAND_TIMEOUT_SEC;
 int riscv_reset_timeout_sec = DEFAULT_RESET_TIMEOUT_SEC;
 
 bool riscv_prefer_sba;
+bool riscv_enable_virt2phys = true;
+bool riscv_ebreakm = true;
+bool riscv_ebreaks = true;
+bool riscv_ebreaku = true;
+
+bool riscv_enable_virtual;
 
 typedef struct {
        uint16_t low, high;
@@ -199,12 +222,159 @@ range_t *expose_csr;
 /* Same, but for custom registers. */
 range_t *expose_custom;
 
+static enum {
+       RO_NORMAL,
+       RO_REVERSED
+} resume_order;
+
+virt2phys_info_t sv32 = {
+       .name = "Sv32",
+       .va_bits = 32,
+       .level = 2,
+       .pte_shift = 2,
+       .vpn_shift = {12, 22},
+       .vpn_mask = {0x3ff, 0x3ff},
+       .pte_ppn_shift = {10, 20},
+       .pte_ppn_mask = {0x3ff, 0xfff},
+       .pa_ppn_shift = {12, 22},
+       .pa_ppn_mask = {0x3ff, 0xfff},
+};
+
+virt2phys_info_t sv39 = {
+       .name = "Sv39",
+       .va_bits = 39,
+       .level = 3,
+       .pte_shift = 3,
+       .vpn_shift = {12, 21, 30},
+       .vpn_mask = {0x1ff, 0x1ff, 0x1ff},
+       .pte_ppn_shift = {10, 19, 28},
+       .pte_ppn_mask = {0x1ff, 0x1ff, 0x3ffffff},
+       .pa_ppn_shift = {12, 21, 30},
+       .pa_ppn_mask = {0x1ff, 0x1ff, 0x3ffffff},
+};
+
+virt2phys_info_t sv48 = {
+       .name = "Sv48",
+       .va_bits = 48,
+       .level = 4,
+       .pte_shift = 3,
+       .vpn_shift = {12, 21, 30, 39},
+       .vpn_mask = {0x1ff, 0x1ff, 0x1ff, 0x1ff},
+       .pte_ppn_shift = {10, 19, 28, 37},
+       .pte_ppn_mask = {0x1ff, 0x1ff, 0x1ff, 0x1ffff},
+       .pa_ppn_shift = {12, 21, 30, 39},
+       .pa_ppn_mask = {0x1ff, 0x1ff, 0x1ff, 0x1ffff},
+};
+
+static int riscv_resume_go_all_harts(struct target *target);
+
+void select_dmi_via_bscan(struct target *target)
+{
+       jtag_add_ir_scan(target->tap, &select_user4, TAP_IDLE);
+       if (bscan_tunnel_type == BSCAN_TUNNEL_DATA_REGISTER)
+               jtag_add_dr_scan(target->tap, bscan_tunnel_data_register_select_dmi_num_fields,
+                                                                               bscan_tunnel_data_register_select_dmi, TAP_IDLE);
+       else /* BSCAN_TUNNEL_NESTED_TAP */
+               jtag_add_dr_scan(target->tap, bscan_tunnel_nested_tap_select_dmi_num_fields,
+                                                                               bscan_tunnel_nested_tap_select_dmi, TAP_IDLE);
+}
+
+uint32_t dtmcontrol_scan_via_bscan(struct target *target, uint32_t out)
+{
+       /* On BSCAN TAP: Select IR=USER4, issue tunneled IR scan via BSCAN TAP's DR */
+       uint8_t tunneled_ir_width[4] = {bscan_tunnel_ir_width};
+       uint8_t tunneled_dr_width[4] = {32};
+       uint8_t out_value[5] = {0};
+       uint8_t in_value[5] = {0};
+
+       buf_set_u32(out_value, 0, 32, out);
+       struct scan_field tunneled_ir[4] = {};
+       struct scan_field tunneled_dr[4] = {};
+
+       if (bscan_tunnel_type == BSCAN_TUNNEL_DATA_REGISTER) {
+               tunneled_ir[0].num_bits = 3;
+               tunneled_ir[0].out_value = bscan_zero;
+               tunneled_ir[0].in_value = NULL;
+               tunneled_ir[1].num_bits = bscan_tunnel_ir_width;
+               tunneled_ir[1].out_value = ir_dtmcontrol;
+               tunneled_ir[1].in_value = NULL;
+               tunneled_ir[2].num_bits = 7;
+               tunneled_ir[2].out_value = tunneled_ir_width;
+               tunneled_ir[2].in_value = NULL;
+               tunneled_ir[3].num_bits = 1;
+               tunneled_ir[3].out_value = bscan_zero;
+               tunneled_ir[3].in_value = NULL;
+
+               tunneled_dr[0].num_bits = 3;
+               tunneled_dr[0].out_value = bscan_zero;
+               tunneled_dr[0].in_value = NULL;
+               tunneled_dr[1].num_bits = 32 + 1;
+               tunneled_dr[1].out_value = out_value;
+               tunneled_dr[1].in_value = in_value;
+               tunneled_dr[2].num_bits = 7;
+               tunneled_dr[2].out_value = tunneled_dr_width;
+               tunneled_dr[2].in_value = NULL;
+               tunneled_dr[3].num_bits = 1;
+               tunneled_dr[3].out_value = bscan_one;
+               tunneled_dr[3].in_value = NULL;
+       } else {
+               /* BSCAN_TUNNEL_NESTED_TAP */
+               tunneled_ir[3].num_bits = 3;
+               tunneled_ir[3].out_value = bscan_zero;
+               tunneled_ir[3].in_value = NULL;
+               tunneled_ir[2].num_bits = bscan_tunnel_ir_width;
+               tunneled_ir[2].out_value = ir_dtmcontrol;
+               tunneled_ir[1].in_value = NULL;
+               tunneled_ir[1].num_bits = 7;
+               tunneled_ir[1].out_value = tunneled_ir_width;
+               tunneled_ir[2].in_value = NULL;
+               tunneled_ir[0].num_bits = 1;
+               tunneled_ir[0].out_value = bscan_zero;
+               tunneled_ir[0].in_value = NULL;
+
+               tunneled_dr[3].num_bits = 3;
+               tunneled_dr[3].out_value = bscan_zero;
+               tunneled_dr[3].in_value = NULL;
+               tunneled_dr[2].num_bits = 32 + 1;
+               tunneled_dr[2].out_value = out_value;
+               tunneled_dr[2].in_value = in_value;
+               tunneled_dr[1].num_bits = 7;
+               tunneled_dr[1].out_value = tunneled_dr_width;
+               tunneled_dr[1].in_value = NULL;
+               tunneled_dr[0].num_bits = 1;
+               tunneled_dr[0].out_value = bscan_one;
+               tunneled_dr[0].in_value = NULL;
+       }
+       jtag_add_ir_scan(target->tap, &select_user4, TAP_IDLE);
+       jtag_add_dr_scan(target->tap, ARRAY_SIZE(tunneled_ir), tunneled_ir, TAP_IDLE);
+       jtag_add_dr_scan(target->tap, ARRAY_SIZE(tunneled_dr), tunneled_dr, TAP_IDLE);
+       select_dmi_via_bscan(target);
+
+       int retval = jtag_execute_queue();
+       if (retval != ERROR_OK) {
+               LOG_ERROR("failed jtag scan: %d", retval);
+               return retval;
+       }
+       /* Note the starting offset is bit 1, not bit 0.  In BSCAN tunnel, there is a one-bit TCK skew between
+          output and input */
+       uint32_t in = buf_get_u32(in_value, 1, 32);
+       LOG_DEBUG("DTMCS: 0x%x -> 0x%x", out, in);
+
+       return in;
+}
+
+
+
 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] = { 0 };
 
+       if (bscan_tunnel_ir_width != 0)
+               return dtmcontrol_scan_via_bscan(target, out);
+
+
        buf_set_u32(out_value, 0, 32, out);
 
        jtag_add_ir_scan(target->tap, &select_dtmcontrol, TAP_IDLE);
@@ -264,6 +434,15 @@ static int riscv_init_target(struct command_context *cmd_ctx,
        select_dbus.num_bits = target->tap->ir_length;
        select_idcode.num_bits = target->tap->ir_length;
 
+       if (bscan_tunnel_ir_width != 0) {
+               select_user4.num_bits = target->tap->ir_length;
+               bscan_tunneled_ir_width[0] = bscan_tunnel_ir_width;
+               if (bscan_tunnel_type == BSCAN_TUNNEL_DATA_REGISTER)
+                       bscan_tunnel_data_register_select_dmi[1].num_bits = bscan_tunnel_ir_width;
+               else /* BSCAN_TUNNEL_NESTED_TAP */
+                       bscan_tunnel_nested_tap_select_dmi[2].num_bits = bscan_tunnel_ir_width;
+       }
+
        riscv_semihosting_init(target);
 
        target->debug_reason = DBG_REASON_DBGRQ;
@@ -276,8 +455,7 @@ static void riscv_free_registers(struct target *target)
        /* Free the shared structure use for most registers. */
        if (target->reg_cache) {
                if (target->reg_cache->reg_list) {
-                       if (target->reg_cache->reg_list[0].arch_info)
-                               free(target->reg_cache->reg_list[0].arch_info);
+                       free(target->reg_cache->reg_list[0].arch_info);
                        /* Free the ones we allocated separately. */
                        for (unsigned i = GDB_REGNO_COUNT; i < target->reg_cache->num_regs; i++)
                                free(target->reg_cache->reg_list[i].arch_info);
@@ -303,12 +481,6 @@ static void riscv_deinit_target(struct target *target)
        target->arch_info = NULL;
 }
 
-static int oldriscv_halt(struct target *target)
-{
-       struct target_type *tt = get_target_type(target);
-       return tt->halt(target);
-}
-
 static void trigger_from_breakpoint(struct trigger *trigger,
                const struct breakpoint *breakpoint)
 {
@@ -692,6 +864,8 @@ int riscv_hit_watchpoint(struct target *target, struct watchpoint **hit_watchpoi
 {
        struct watchpoint *wp = target->watchpoints;
 
+       if (riscv_rtos_enabled(target))
+               riscv_set_current_hartid(target, target->rtos->current_thread - 1);
        LOG_DEBUG("Current hartid = %d", riscv_current_hartid(target));
 
        /*TODO instead of disassembling the instruction that we think caused the
@@ -772,15 +946,12 @@ static int oldriscv_step(struct target *target, int current, uint32_t address,
        return tt->step(target, current, address, handle_breakpoints);
 }
 
-static int old_or_new_riscv_step(
-               struct target *target,
-               int current,
-               target_addr_t address,
-               int handle_breakpoints
-){
+static int old_or_new_riscv_step(struct target *target, int current,
+               target_addr_t address, int handle_breakpoints)
+{
        RISCV_INFO(r);
        LOG_DEBUG("handle_breakpoints=%d", handle_breakpoints);
-       if (r->is_halted == NULL)
+       if (!r->is_halted)
                return oldriscv_step(target, current, address, handle_breakpoints);
        else
                return riscv_openocd_step(target, current, address, handle_breakpoints);
@@ -804,7 +975,7 @@ static int riscv_examine(struct target *target)
        LOG_DEBUG("  version=0x%x", info->dtm_version);
 
        struct target_type *tt = get_target_type(target);
-       if (tt == NULL)
+       if (!tt)
                return ERROR_FAIL;
 
        int result = tt->init_target(info->cmd_ctx, target);
@@ -823,185 +994,721 @@ static int oldriscv_poll(struct target *target)
 static int old_or_new_riscv_poll(struct target *target)
 {
        RISCV_INFO(r);
-       if (r->is_halted == NULL)
+       if (!r->is_halted)
                return oldriscv_poll(target);
        else
                return riscv_openocd_poll(target);
 }
 
-static int old_or_new_riscv_halt(struct target *target)
+int halt_prep(struct target *target)
 {
        RISCV_INFO(r);
-       if (r->is_halted == NULL)
-               return oldriscv_halt(target);
-       else
-               return riscv_openocd_halt(target);
+       for (int i = 0; i < riscv_count_harts(target); ++i) {
+               if (!riscv_hart_enabled(target, i))
+                       continue;
+
+               LOG_DEBUG("[%s] prep hart, debug_reason=%d", target_name(target),
+                                 target->debug_reason);
+               if (riscv_set_current_hartid(target, i) != ERROR_OK)
+                       return ERROR_FAIL;
+               if (riscv_is_halted(target)) {
+                       LOG_DEBUG("Hart %d is already halted (reason=%d).", i,
+                                         target->debug_reason);
+               } else {
+                       if (r->halt_prep(target) != ERROR_OK)
+                               return ERROR_FAIL;
+                       r->prepped = true;
+               }
+       }
+       return ERROR_OK;
 }
 
-static int riscv_assert_reset(struct target *target)
+int riscv_halt_go_all_harts(struct target *target)
 {
-       LOG_DEBUG("[%d]", target->coreid);
-       struct target_type *tt = get_target_type(target);
+       RISCV_INFO(r);
+       for (int i = 0; i < riscv_count_harts(target); ++i) {
+               if (!riscv_hart_enabled(target, i))
+                       continue;
+
+               if (riscv_set_current_hartid(target, i) != ERROR_OK)
+                       return ERROR_FAIL;
+               if (riscv_is_halted(target)) {
+                       LOG_DEBUG("Hart %d is already halted.", i);
+               } else {
+                       if (r->halt_go(target) != ERROR_OK)
+                               return ERROR_FAIL;
+               }
+       }
+
        riscv_invalidate_register_cache(target);
-       return tt->assert_reset(target);
+
+       return ERROR_OK;
 }
 
-static int riscv_deassert_reset(struct target *target)
+int halt_go(struct target *target)
 {
-       LOG_DEBUG("[%d]", target->coreid);
-       struct target_type *tt = get_target_type(target);
-       return tt->deassert_reset(target);
-}
+       riscv_info_t *r = riscv_info(target);
+       int result;
+       if (!r->is_halted) {
+               struct target_type *tt = get_target_type(target);
+               result = tt->halt(target);
+       } else {
+               result = riscv_halt_go_all_harts(target);
+       }
+       target->state = TARGET_HALTED;
+       if (target->debug_reason == DBG_REASON_NOTHALTED)
+               target->debug_reason = DBG_REASON_DBGRQ;
 
+       return result;
+}
 
-static int oldriscv_resume(struct target *target, int current, uint32_t address,
-               int handle_breakpoints, int debug_execution)
+static int halt_finish(struct target *target)
 {
-       struct target_type *tt = get_target_type(target);
-       return tt->resume(target, current, address, handle_breakpoints,
-                       debug_execution);
+       return target_call_event_callbacks(target, TARGET_EVENT_HALTED);
 }
 
-static int old_or_new_riscv_resume(
-               struct target *target,
-               int current,
-               target_addr_t address,
-               int handle_breakpoints,
-               int debug_execution
-){
-       LOG_DEBUG("handle_breakpoints=%d", handle_breakpoints);
+int riscv_halt(struct target *target)
+{
+       RISCV_INFO(r);
+
+       if (!r->is_halted) {
+               struct target_type *tt = get_target_type(target);
+               return tt->halt(target);
+       }
+
+       LOG_DEBUG("[%d] halting all harts", target->coreid);
+
+       int result = ERROR_OK;
        if (target->smp) {
-               struct target_list *targets = target->head;
-               int result = ERROR_OK;
-               while (targets) {
-                       struct target *t = targets->target;
-                       riscv_info_t *r = riscv_info(t);
-                       if (r->is_halted == NULL) {
-                               if (oldriscv_resume(t, current, address, handle_breakpoints,
-                                                       debug_execution) != ERROR_OK)
-                                       result = ERROR_FAIL;
-                       } else {
-                               if (riscv_openocd_resume(t, current, address,
-                                                       handle_breakpoints, debug_execution) != ERROR_OK)
+               for (struct target_list *tlist = target->head; tlist; tlist = tlist->next) {
+                       struct target *t = tlist->target;
+                       if (halt_prep(t) != ERROR_OK)
+                               result = ERROR_FAIL;
+               }
+
+               for (struct target_list *tlist = target->head; tlist; tlist = tlist->next) {
+                       struct target *t = tlist->target;
+                       riscv_info_t *i = riscv_info(t);
+                       if (i->prepped) {
+                               if (halt_go(t) != ERROR_OK)
                                        result = ERROR_FAIL;
                        }
-                       targets = targets->next;
                }
-               return result;
-       }
 
-       RISCV_INFO(r);
-       if (r->is_halted == NULL)
-               return oldriscv_resume(target, current, address, handle_breakpoints, debug_execution);
-       else
-               return riscv_openocd_resume(target, current, address, handle_breakpoints, debug_execution);
-}
+               for (struct target_list *tlist = target->head; tlist; tlist = tlist->next) {
+                       struct target *t = tlist->target;
+                       if (halt_finish(t) != ERROR_OK)
+                               return ERROR_FAIL;
+               }
+
+       } else {
+               if (halt_prep(target) != ERROR_OK)
+                       result = ERROR_FAIL;
+               if (halt_go(target) != ERROR_OK)
+                       result = ERROR_FAIL;
+               if (halt_finish(target) != ERROR_OK)
+                       return ERROR_FAIL;
+       }
 
-static int riscv_select_current_hart(struct target *target)
-{
-       RISCV_INFO(r);
        if (riscv_rtos_enabled(target)) {
-               if (r->rtos_hartid == -1)
-                       r->rtos_hartid = target->rtos->current_threadid - 1;
-               return riscv_set_current_hartid(target, r->rtos_hartid);
-       } else
-               return riscv_set_current_hartid(target, target->coreid);
+               if (r->rtos_hartid != -1) {
+                       LOG_DEBUG("halt requested on RTOS hartid %d", r->rtos_hartid);
+                       target->rtos->current_threadid = r->rtos_hartid + 1;
+                       target->rtos->current_thread = r->rtos_hartid + 1;
+               } else
+                       LOG_DEBUG("halt requested, but no known RTOS hartid");
+       }
+
+       return result;
 }
 
-static int riscv_read_memory(struct target *target, target_addr_t address,
-               uint32_t size, uint32_t count, uint8_t *buffer)
+static int riscv_assert_reset(struct target *target)
 {
-       if (riscv_select_current_hart(target) != ERROR_OK)
-               return ERROR_FAIL;
+       LOG_DEBUG("[%d]", target->coreid);
        struct target_type *tt = get_target_type(target);
-       return tt->read_memory(target, address, size, count, buffer);
+       riscv_invalidate_register_cache(target);
+       return tt->assert_reset(target);
 }
 
-static int riscv_write_memory(struct target *target, target_addr_t address,
-               uint32_t size, uint32_t count, const uint8_t *buffer)
+static int riscv_deassert_reset(struct target *target)
 {
-       if (riscv_select_current_hart(target) != ERROR_OK)
-               return ERROR_FAIL;
+       LOG_DEBUG("[%d]", target->coreid);
        struct target_type *tt = get_target_type(target);
-       return tt->write_memory(target, address, size, count, buffer);
+       return tt->deassert_reset(target);
 }
 
-static int riscv_get_gdb_reg_list_internal(struct target *target,
-               struct reg **reg_list[], int *reg_list_size,
-               enum target_register_class reg_class, bool read)
+int riscv_resume_prep_all_harts(struct target *target)
 {
        RISCV_INFO(r);
-       LOG_DEBUG("rtos_hartid=%d, current_hartid=%d, reg_class=%d, read=%d",
-                       r->rtos_hartid, r->current_hartid, reg_class, read);
+       for (int i = 0; i < riscv_count_harts(target); ++i) {
+               if (!riscv_hart_enabled(target, i))
+                       continue;
 
-       if (!target->reg_cache) {
-               LOG_ERROR("Target not initialized. Return ERROR_FAIL.");
-               return ERROR_FAIL;
+               LOG_DEBUG("prep hart %d", i);
+               if (riscv_set_current_hartid(target, i) != ERROR_OK)
+                       return ERROR_FAIL;
+               if (riscv_is_halted(target)) {
+                       if (r->resume_prep(target) != ERROR_OK)
+                               return ERROR_FAIL;
+               } else {
+                       LOG_DEBUG("  hart %d requested resume, but was already resumed", i);
+               }
        }
 
-       if (riscv_select_current_hart(target) != ERROR_OK)
-               return ERROR_FAIL;
+       LOG_DEBUG("[%d] mark as prepped", target->coreid);
+       r->prepped = true;
 
-       switch (reg_class) {
-               case REG_CLASS_GENERAL:
-                       *reg_list_size = 33;
-                       break;
-               case REG_CLASS_ALL:
-                       *reg_list_size = target->reg_cache->num_regs;
-                       break;
-               default:
-                       LOG_ERROR("Unsupported reg_class: %d", reg_class);
-                       return ERROR_FAIL;
-       }
+       return ERROR_OK;
+}
 
-       *reg_list = calloc(*reg_list_size, sizeof(struct reg *));
-       if (!*reg_list)
+/* state must be riscv_reg_t state[RISCV_MAX_HWBPS] = {0}; */
+static int disable_triggers(struct target *target, riscv_reg_t *state)
+{
+       RISCV_INFO(r);
+
+       LOG_DEBUG("deal with triggers");
+
+       if (riscv_enumerate_triggers(target) != ERROR_OK)
                return ERROR_FAIL;
 
-       for (int i = 0; i < *reg_list_size; i++) {
-               assert(!target->reg_cache->reg_list[i].valid ||
-                               target->reg_cache->reg_list[i].size > 0);
-               (*reg_list)[i] = &target->reg_cache->reg_list[i];
-               if (read && !target->reg_cache->reg_list[i].valid) {
-                       if (target->reg_cache->reg_list[i].type->get(
-                                               &target->reg_cache->reg_list[i]) != ERROR_OK)
-                               /* This function is called when first connecting to gdb,
-                                * resulting in an attempt to read all kinds of registers which
-                                * probably will fail. Ignore these failures, and when
-                                * encountered stop reading to save time. */
-                               read = false;
+       int hartid = riscv_current_hartid(target);
+       if (r->manual_hwbp_set) {
+               /* Look at every trigger that may have been set. */
+               riscv_reg_t tselect;
+               if (riscv_get_register(target, &tselect, GDB_REGNO_TSELECT) != ERROR_OK)
+                       return ERROR_FAIL;
+               for (unsigned t = 0; t < r->trigger_count[hartid]; t++) {
+                       if (riscv_set_register(target, GDB_REGNO_TSELECT, t) != ERROR_OK)
+                               return ERROR_FAIL;
+                       riscv_reg_t tdata1;
+                       if (riscv_get_register(target, &tdata1, GDB_REGNO_TDATA1) != ERROR_OK)
+                               return ERROR_FAIL;
+                       if (tdata1 & MCONTROL_DMODE(riscv_xlen(target))) {
+                               state[t] = tdata1;
+                               if (riscv_set_register(target, GDB_REGNO_TDATA1, 0) != ERROR_OK)
+                                       return ERROR_FAIL;
+                       }
+               }
+               if (riscv_set_register(target, GDB_REGNO_TSELECT, tselect) != ERROR_OK)
+                       return ERROR_FAIL;
+
+       } else {
+               /* Just go through the triggers we manage. */
+               struct watchpoint *watchpoint = target->watchpoints;
+               int i = 0;
+               while (watchpoint) {
+                       LOG_DEBUG("watchpoint %d: set=%d", i, watchpoint->set);
+                       state[i] = watchpoint->set;
+                       if (watchpoint->set) {
+                               if (riscv_remove_watchpoint(target, watchpoint) != ERROR_OK)
+                                       return ERROR_FAIL;
+                       }
+                       watchpoint = watchpoint->next;
+                       i++;
                }
        }
 
        return ERROR_OK;
 }
 
-static int riscv_get_gdb_reg_list(struct target *target,
-               struct reg **reg_list[], int *reg_list_size,
-               enum target_register_class reg_class)
-{
-       return riscv_get_gdb_reg_list_internal(target, reg_list, reg_list_size,
-                       reg_class, true);
-}
-
-static int riscv_arch_state(struct target *target)
+static int enable_triggers(struct target *target, riscv_reg_t *state)
 {
-       struct target_type *tt = get_target_type(target);
-       return tt->arch_state(target);
-}
+       RISCV_INFO(r);
 
-/* Algorithm must end with a software breakpoint instruction. */
-static int riscv_run_algorithm(struct target *target, int num_mem_params,
-               struct mem_param *mem_params, int num_reg_params,
-               struct reg_param *reg_params, target_addr_t entry_point,
-               target_addr_t exit_point, int timeout_ms, void *arch_info)
-{
-       riscv_info_t *info = (riscv_info_t *) target->arch_info;
+       int hartid = riscv_current_hartid(target);
 
-       if (num_mem_params > 0) {
-               LOG_ERROR("Memory parameters are not supported for RISC-V algorithms.");
-               return ERROR_FAIL;
-       }
+       if (r->manual_hwbp_set) {
+               /* Look at every trigger that may have been set. */
+               riscv_reg_t tselect;
+               if (riscv_get_register(target, &tselect, GDB_REGNO_TSELECT) != ERROR_OK)
+                       return ERROR_FAIL;
+               for (unsigned t = 0; t < r->trigger_count[hartid]; t++) {
+                       if (state[t] != 0) {
+                               if (riscv_set_register(target, GDB_REGNO_TSELECT, t) != ERROR_OK)
+                                       return ERROR_FAIL;
+                               if (riscv_set_register(target, GDB_REGNO_TDATA1, state[t]) != ERROR_OK)
+                                       return ERROR_FAIL;
+                       }
+               }
+               if (riscv_set_register(target, GDB_REGNO_TSELECT, tselect) != ERROR_OK)
+                       return ERROR_FAIL;
+
+       } else {
+               struct watchpoint *watchpoint = target->watchpoints;
+               int i = 0;
+               while (watchpoint) {
+                       LOG_DEBUG("watchpoint %d: cleared=%" PRId64, i, state[i]);
+                       if (state[i]) {
+                               if (riscv_add_watchpoint(target, watchpoint) != ERROR_OK)
+                                       return ERROR_FAIL;
+                       }
+                       watchpoint = watchpoint->next;
+                       i++;
+               }
+       }
+
+       return ERROR_OK;
+}
+
+/**
+ * Get everything ready to resume.
+ */
+static int resume_prep(struct target *target, int current,
+               target_addr_t address, int handle_breakpoints, int debug_execution)
+{
+       RISCV_INFO(r);
+       LOG_DEBUG("[%d]", target->coreid);
+
+       if (!current)
+               riscv_set_register(target, GDB_REGNO_PC, address);
+
+       if (target->debug_reason == DBG_REASON_WATCHPOINT) {
+               /* To be able to run off a trigger, disable all the triggers, step, and
+                * then resume as usual. */
+               riscv_reg_t trigger_state[RISCV_MAX_HWBPS] = {0};
+
+               if (disable_triggers(target, trigger_state) != ERROR_OK)
+                       return ERROR_FAIL;
+
+               if (old_or_new_riscv_step(target, true, 0, false) != ERROR_OK)
+                       return ERROR_FAIL;
+
+               if (enable_triggers(target, trigger_state) != ERROR_OK)
+                       return ERROR_FAIL;
+       }
+
+       if (r->is_halted) {
+               if (riscv_resume_prep_all_harts(target) != ERROR_OK)
+                       return ERROR_FAIL;
+       }
+
+       LOG_DEBUG("[%d] mark as prepped", target->coreid);
+       r->prepped = true;
+
+       return ERROR_OK;
+}
+
+/**
+ * Resume all the harts that have been prepped, as close to instantaneous as
+ * possible.
+ */
+static int resume_go(struct target *target, int current,
+               target_addr_t address, int handle_breakpoints, int debug_execution)
+{
+       riscv_info_t *r = riscv_info(target);
+       int result;
+       if (!r->is_halted) {
+               struct target_type *tt = get_target_type(target);
+               result = tt->resume(target, current, address, handle_breakpoints,
+                               debug_execution);
+       } else {
+               result = riscv_resume_go_all_harts(target);
+       }
+
+       return result;
+}
+
+static int resume_finish(struct target *target)
+{
+       register_cache_invalidate(target->reg_cache);
+
+       target->state = TARGET_RUNNING;
+       target->debug_reason = DBG_REASON_NOTHALTED;
+       return target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
+}
+
+/**
+ * @par single_hart When true, only resume a single hart even if SMP is
+ * configured.  This is used to run algorithms on just one hart.
+ */
+int riscv_resume(
+               struct target *target,
+               int current,
+               target_addr_t address,
+               int handle_breakpoints,
+               int debug_execution,
+               bool single_hart)
+{
+       LOG_DEBUG("handle_breakpoints=%d", handle_breakpoints);
+       int result = ERROR_OK;
+       if (target->smp && !single_hart) {
+               for (struct target_list *tlist = target->head; tlist; tlist = tlist->next) {
+                       struct target *t = tlist->target;
+                       if (resume_prep(t, current, address, handle_breakpoints,
+                                               debug_execution) != ERROR_OK)
+                               result = ERROR_FAIL;
+               }
+
+               for (struct target_list *tlist = target->head; tlist; tlist = tlist->next) {
+                       struct target *t = tlist->target;
+                       riscv_info_t *i = riscv_info(t);
+                       if (i->prepped) {
+                               if (resume_go(t, current, address, handle_breakpoints,
+                                                       debug_execution) != ERROR_OK)
+                                       result = ERROR_FAIL;
+                       }
+               }
+
+               for (struct target_list *tlist = target->head; tlist; tlist = tlist->next) {
+                       struct target *t = tlist->target;
+                       if (resume_finish(t) != ERROR_OK)
+                               return ERROR_FAIL;
+               }
+
+       } else {
+               if (resume_prep(target, current, address, handle_breakpoints,
+                                       debug_execution) != ERROR_OK)
+                       result = ERROR_FAIL;
+               if (resume_go(target, current, address, handle_breakpoints,
+                                       debug_execution) != ERROR_OK)
+                       result = ERROR_FAIL;
+               if (resume_finish(target) != ERROR_OK)
+                       return ERROR_FAIL;
+       }
+
+       return result;
+}
+
+static int riscv_target_resume(struct target *target, int current, target_addr_t address,
+               int handle_breakpoints, int debug_execution)
+{
+       return riscv_resume(target, current, address, handle_breakpoints,
+                       debug_execution, false);
+}
+
+static int riscv_select_current_hart(struct target *target)
+{
+       RISCV_INFO(r);
+       if (riscv_rtos_enabled(target)) {
+               if (r->rtos_hartid == -1)
+                       r->rtos_hartid = target->rtos->current_threadid - 1;
+               return riscv_set_current_hartid(target, r->rtos_hartid);
+       } else
+               return riscv_set_current_hartid(target, target->coreid);
+}
+
+static int riscv_mmu(struct target *target, int *enabled)
+{
+       if (!riscv_enable_virt2phys) {
+               *enabled = 0;
+               return ERROR_OK;
+       }
+
+       if (riscv_rtos_enabled(target))
+               riscv_set_current_hartid(target, target->rtos->current_thread - 1);
+
+       /* Don't use MMU in explicit or effective M (machine) mode */
+       riscv_reg_t priv;
+       if (riscv_get_register(target, &priv, GDB_REGNO_PRIV) != ERROR_OK) {
+               LOG_ERROR("Failed to read priv register.");
+               return ERROR_FAIL;
+       }
+
+       riscv_reg_t mstatus;
+       if (riscv_get_register(target, &mstatus, GDB_REGNO_MSTATUS) != ERROR_OK) {
+               LOG_ERROR("Failed to read mstatus register.");
+               return ERROR_FAIL;
+       }
+
+       if ((get_field(mstatus, MSTATUS_MPRV) ? get_field(mstatus, MSTATUS_MPP) : priv) == PRV_M) {
+               LOG_DEBUG("SATP/MMU ignored in Machine mode (mstatus=0x%" PRIx64 ").", mstatus);
+               *enabled = 0;
+               return ERROR_OK;
+       }
+
+       riscv_reg_t satp;
+       if (riscv_get_register(target, &satp, GDB_REGNO_SATP) != ERROR_OK) {
+               LOG_DEBUG("Couldn't read SATP.");
+               /* If we can't read SATP, then there must not be an MMU. */
+               *enabled = 0;
+               return ERROR_OK;
+       }
+
+       if (get_field(satp, RISCV_SATP_MODE(riscv_xlen(target))) == SATP_MODE_OFF) {
+               LOG_DEBUG("MMU is disabled.");
+               *enabled = 0;
+       } else {
+               LOG_DEBUG("MMU is enabled.");
+               *enabled = 1;
+       }
+
+       return ERROR_OK;
+}
+
+static int riscv_address_translate(struct target *target,
+               target_addr_t virtual, target_addr_t *physical)
+{
+       RISCV_INFO(r);
+       riscv_reg_t satp_value;
+       int mode;
+       uint64_t ppn_value;
+       target_addr_t table_address;
+       virt2phys_info_t *info;
+       uint64_t pte = 0;
+       int i;
+
+       if (riscv_rtos_enabled(target))
+               riscv_set_current_hartid(target, target->rtos->current_thread - 1);
+
+       int result = riscv_get_register(target, &satp_value, GDB_REGNO_SATP);
+       if (result != ERROR_OK)
+               return result;
+
+       unsigned xlen = riscv_xlen(target);
+       mode = get_field(satp_value, RISCV_SATP_MODE(xlen));
+       switch (mode) {
+               case SATP_MODE_SV32:
+                       info = &sv32;
+                       break;
+               case SATP_MODE_SV39:
+                       info = &sv39;
+                       break;
+               case SATP_MODE_SV48:
+                       info = &sv48;
+                       break;
+               case SATP_MODE_OFF:
+                       LOG_ERROR("No translation or protection." \
+                                     " (satp: 0x%" PRIx64 ")", satp_value);
+                       return ERROR_FAIL;
+               default:
+                       LOG_ERROR("The translation mode is not supported." \
+                                     " (satp: 0x%" PRIx64 ")", satp_value);
+                       return ERROR_FAIL;
+       }
+       LOG_DEBUG("virtual=0x%" TARGET_PRIxADDR "; mode=%s", virtual, info->name);
+
+       /* verify bits xlen-1:va_bits-1 are all equal */
+       target_addr_t mask = ((target_addr_t)1 << (xlen - (info->va_bits - 1))) - 1;
+       target_addr_t masked_msbs = (virtual >> (info->va_bits - 1)) & mask;
+       if (masked_msbs != 0 && masked_msbs != mask) {
+               LOG_ERROR("Virtual address 0x%" TARGET_PRIxADDR " is not sign-extended "
+                               "for %s mode.", virtual, info->name);
+               return ERROR_FAIL;
+       }
+
+       ppn_value = get_field(satp_value, RISCV_SATP_PPN(xlen));
+       table_address = ppn_value << RISCV_PGSHIFT;
+       i = info->level - 1;
+       while (i >= 0) {
+               uint64_t vpn = virtual >> info->vpn_shift[i];
+               vpn &= info->vpn_mask[i];
+               target_addr_t pte_address = table_address +
+                                                                       (vpn << info->pte_shift);
+               uint8_t buffer[8];
+               assert(info->pte_shift <= 3);
+               int retval = r->read_memory(target, pte_address,
+                               4, (1 << info->pte_shift) / 4, buffer, 4);
+               if (retval != ERROR_OK)
+                       return ERROR_FAIL;
+
+               if (info->pte_shift == 2)
+                       pte = buf_get_u32(buffer, 0, 32);
+               else
+                       pte = buf_get_u64(buffer, 0, 64);
+
+               LOG_DEBUG("i=%d; PTE @0x%" TARGET_PRIxADDR " = 0x%" PRIx64, i,
+                               pte_address, pte);
+
+               if (!(pte & PTE_V) || (!(pte & PTE_R) && (pte & PTE_W)))
+                       return ERROR_FAIL;
+
+               if ((pte & PTE_R) || (pte & PTE_X)) /* Found leaf PTE. */
+                       break;
+
+               i--;
+               if (i < 0)
+                       break;
+               ppn_value = pte >> PTE_PPN_SHIFT;
+               table_address = ppn_value << RISCV_PGSHIFT;
+       }
+
+       if (i < 0) {
+               LOG_ERROR("Couldn't find the PTE.");
+               return ERROR_FAIL;
+       }
+
+       /* Make sure to clear out the high bits that may be set. */
+       *physical = virtual & (((target_addr_t)1 << info->va_bits) - 1);
+
+       while (i < info->level) {
+               ppn_value = pte >> info->pte_ppn_shift[i];
+               ppn_value &= info->pte_ppn_mask[i];
+               *physical &= ~(((target_addr_t)info->pa_ppn_mask[i]) <<
+                               info->pa_ppn_shift[i]);
+               *physical |= (ppn_value << info->pa_ppn_shift[i]);
+               i++;
+       }
+       LOG_DEBUG("0x%" TARGET_PRIxADDR " -> 0x%" TARGET_PRIxADDR, virtual,
+                       *physical);
+
+       return ERROR_OK;
+}
+
+static int riscv_virt2phys(struct target *target, target_addr_t virtual, target_addr_t *physical)
+{
+       int enabled;
+       if (riscv_mmu(target, &enabled) == ERROR_OK) {
+               if (!enabled)
+                       return ERROR_FAIL;
+
+               if (riscv_address_translate(target, virtual, physical) == ERROR_OK)
+                       return ERROR_OK;
+       }
+
+       return ERROR_FAIL;
+}
+
+static int riscv_read_phys_memory(struct target *target, target_addr_t phys_address,
+                       uint32_t size, uint32_t count, uint8_t *buffer)
+{
+       RISCV_INFO(r);
+       if (riscv_select_current_hart(target) != ERROR_OK)
+               return ERROR_FAIL;
+       return r->read_memory(target, phys_address, size, count, buffer, size);
+}
+
+static int riscv_read_memory(struct target *target, target_addr_t address,
+               uint32_t size, uint32_t count, uint8_t *buffer)
+{
+       if (count == 0) {
+               LOG_WARNING("0-length read from 0x%" TARGET_PRIxADDR, address);
+               return ERROR_OK;
+       }
+
+       if (riscv_select_current_hart(target) != ERROR_OK)
+               return ERROR_FAIL;
+
+       target_addr_t physical_addr;
+       if (target->type->virt2phys(target, address, &physical_addr) == ERROR_OK)
+               address = physical_addr;
+
+       RISCV_INFO(r);
+       return r->read_memory(target, address, size, count, buffer, size);
+}
+
+static int riscv_write_phys_memory(struct target *target, target_addr_t phys_address,
+                       uint32_t size, uint32_t count, const uint8_t *buffer)
+{
+       if (riscv_select_current_hart(target) != ERROR_OK)
+               return ERROR_FAIL;
+       struct target_type *tt = get_target_type(target);
+       return tt->write_memory(target, phys_address, size, count, buffer);
+}
+
+static int riscv_write_memory(struct target *target, target_addr_t address,
+               uint32_t size, uint32_t count, const uint8_t *buffer)
+{
+       if (count == 0) {
+               LOG_WARNING("0-length write to 0x%" TARGET_PRIxADDR, address);
+               return ERROR_OK;
+       }
+
+       if (riscv_select_current_hart(target) != ERROR_OK)
+               return ERROR_FAIL;
+
+       target_addr_t physical_addr;
+       if (target->type->virt2phys(target, address, &physical_addr) == ERROR_OK)
+               address = physical_addr;
+
+       struct target_type *tt = get_target_type(target);
+       return tt->write_memory(target, address, size, count, buffer);
+}
+
+const char *riscv_get_gdb_arch(struct target *target)
+{
+       switch (riscv_xlen(target)) {
+               case 32:
+                       return "riscv:rv32";
+               case 64:
+                       return "riscv:rv64";
+       }
+       LOG_ERROR("Unsupported xlen: %d", riscv_xlen(target));
+       return NULL;
+}
+
+static int riscv_get_gdb_reg_list_internal(struct target *target,
+               struct reg **reg_list[], int *reg_list_size,
+               enum target_register_class reg_class, bool read)
+{
+       RISCV_INFO(r);
+       LOG_DEBUG("rtos_hartid=%d, current_hartid=%d, reg_class=%d, read=%d",
+                       r->rtos_hartid, r->current_hartid, reg_class, read);
+
+       if (!target->reg_cache) {
+               LOG_ERROR("Target not initialized. Return ERROR_FAIL.");
+               return ERROR_FAIL;
+       }
+
+       if (riscv_select_current_hart(target) != ERROR_OK)
+               return ERROR_FAIL;
+
+       switch (reg_class) {
+               case REG_CLASS_GENERAL:
+                       *reg_list_size = 33;
+                       break;
+               case REG_CLASS_ALL:
+                       *reg_list_size = target->reg_cache->num_regs;
+                       break;
+               default:
+                       LOG_ERROR("Unsupported reg_class: %d", reg_class);
+                       return ERROR_FAIL;
+       }
+
+       *reg_list = calloc(*reg_list_size, sizeof(struct reg *));
+       if (!*reg_list)
+               return ERROR_FAIL;
+
+       for (int i = 0; i < *reg_list_size; i++) {
+               assert(!target->reg_cache->reg_list[i].valid ||
+                               target->reg_cache->reg_list[i].size > 0);
+               (*reg_list)[i] = &target->reg_cache->reg_list[i];
+               if (read &&
+                               target->reg_cache->reg_list[i].exist &&
+                               !target->reg_cache->reg_list[i].valid) {
+                       if (target->reg_cache->reg_list[i].type->get(
+                                               &target->reg_cache->reg_list[i]) != ERROR_OK)
+                               return ERROR_FAIL;
+               }
+       }
+
+       return ERROR_OK;
+}
+
+static int riscv_get_gdb_reg_list_noread(struct target *target,
+               struct reg **reg_list[], int *reg_list_size,
+               enum target_register_class reg_class)
+{
+       return riscv_get_gdb_reg_list_internal(target, reg_list, reg_list_size,
+                       reg_class, false);
+}
+
+static int riscv_get_gdb_reg_list(struct target *target,
+               struct reg **reg_list[], int *reg_list_size,
+               enum target_register_class reg_class)
+{
+       return riscv_get_gdb_reg_list_internal(target, reg_list, reg_list_size,
+                       reg_class, true);
+}
+
+static int riscv_arch_state(struct target *target)
+{
+       struct target_type *tt = get_target_type(target);
+       return tt->arch_state(target);
+}
+
+/* Algorithm must end with a software breakpoint instruction. */
+static int riscv_run_algorithm(struct target *target, int num_mem_params,
+               struct mem_param *mem_params, int num_reg_params,
+               struct reg_param *reg_params, target_addr_t entry_point,
+               target_addr_t exit_point, int timeout_ms, void *arch_info)
+{
+       riscv_info_t *info = (riscv_info_t *) target->arch_info;
+       int hartid = riscv_current_hartid(target);
+
+       if (num_mem_params > 0) {
+               LOG_ERROR("Memory parameters are not supported for RISC-V algorithms.");
+               return ERROR_FAIL;
+       }
 
        if (target->state != TARGET_HALTED) {
                LOG_WARNING("target not halted");
@@ -1009,18 +1716,16 @@ static int riscv_run_algorithm(struct target *target, int num_mem_params,
        }
 
        /* Save registers */
-       struct reg *reg_pc = register_get_by_name(target->reg_cache, "pc", 1);
+       struct reg *reg_pc = register_get_by_name(target->reg_cache, "pc", true);
        if (!reg_pc || reg_pc->type->get(reg_pc) != ERROR_OK)
                return ERROR_FAIL;
        uint64_t saved_pc = buf_get_u64(reg_pc->value, 0, reg_pc->size);
+       LOG_DEBUG("saved_pc=0x%" PRIx64, saved_pc);
 
        uint64_t saved_regs[32];
        for (int i = 0; i < num_reg_params; i++) {
-               if (reg_params[i].direction == PARAM_IN)
-                       continue;
-
                LOG_DEBUG("save %s", reg_params[i].reg_name);
-               struct reg *r = register_get_by_name(target->reg_cache, reg_params[i].reg_name, 0);
+               struct reg *r = register_get_by_name(target->reg_cache, reg_params[i].reg_name, false);
                if (!r) {
                        LOG_ERROR("Couldn't find register named '%s'", reg_params[i].reg_name);
                        return ERROR_FAIL;
@@ -1040,8 +1745,11 @@ static int riscv_run_algorithm(struct target *target, int num_mem_params,
                if (r->type->get(r) != ERROR_OK)
                        return ERROR_FAIL;
                saved_regs[r->number] = buf_get_u64(r->value, 0, r->size);
-               if (r->type->set(r, reg_params[i].value) != ERROR_OK)
-                       return ERROR_FAIL;
+
+               if (reg_params[i].direction == PARAM_OUT || reg_params[i].direction == PARAM_IN_OUT) {
+                       if (r->type->set(r, reg_params[i].value) != ERROR_OK)
+                               return ERROR_FAIL;
+               }
        }
 
 
@@ -1051,7 +1759,7 @@ static int riscv_run_algorithm(struct target *target, int num_mem_params,
 
        LOG_DEBUG("Disabling Interrupts");
        struct reg *reg_mstatus = register_get_by_name(target->reg_cache,
-                       "mstatus", 1);
+                       "mstatus", true);
        if (!reg_mstatus) {
                LOG_ERROR("Couldn't find mstatus!");
                return ERROR_FAIL;
@@ -1067,7 +1775,7 @@ static int riscv_run_algorithm(struct target *target, int num_mem_params,
 
        /* Run algorithm */
        LOG_DEBUG("resume at 0x%" TARGET_PRIxADDR, entry_point);
-       if (oldriscv_resume(target, 0, entry_point, 0, 0) != ERROR_OK)
+       if (riscv_resume(target, 0, entry_point, 0, 0, true) != ERROR_OK)
                return ERROR_FAIL;
 
        int64_t start = timeval_ms();
@@ -1075,11 +1783,28 @@ static int riscv_run_algorithm(struct target *target, int num_mem_params,
                LOG_DEBUG("poll()");
                int64_t now = timeval_ms();
                if (now - start > timeout_ms) {
-                       LOG_ERROR("Algorithm timed out after %d ms.", timeout_ms);
-                       LOG_ERROR("  now   = 0x%08x", (uint32_t) now);
-                       LOG_ERROR("  start = 0x%08x", (uint32_t) start);
-                       oldriscv_halt(target);
+                       LOG_ERROR("Algorithm timed out after %" PRId64 " ms.", now - start);
+                       riscv_halt(target);
                        old_or_new_riscv_poll(target);
+                       enum gdb_regno regnums[] = {
+                               GDB_REGNO_RA, GDB_REGNO_SP, GDB_REGNO_GP, GDB_REGNO_TP,
+                               GDB_REGNO_T0, GDB_REGNO_T1, GDB_REGNO_T2, GDB_REGNO_FP,
+                               GDB_REGNO_S1, GDB_REGNO_A0, GDB_REGNO_A1, GDB_REGNO_A2,
+                               GDB_REGNO_A3, GDB_REGNO_A4, GDB_REGNO_A5, GDB_REGNO_A6,
+                               GDB_REGNO_A7, GDB_REGNO_S2, GDB_REGNO_S3, GDB_REGNO_S4,
+                               GDB_REGNO_S5, GDB_REGNO_S6, GDB_REGNO_S7, GDB_REGNO_S8,
+                               GDB_REGNO_S9, GDB_REGNO_S10, GDB_REGNO_S11, GDB_REGNO_T3,
+                               GDB_REGNO_T4, GDB_REGNO_T5, GDB_REGNO_T6,
+                               GDB_REGNO_PC,
+                               GDB_REGNO_MSTATUS, GDB_REGNO_MEPC, GDB_REGNO_MCAUSE,
+                       };
+                       for (unsigned i = 0; i < ARRAY_SIZE(regnums); i++) {
+                               enum gdb_regno regno = regnums[i];
+                               riscv_reg_t reg_value;
+                               if (riscv_get_register(target, &reg_value, regno) != ERROR_OK)
+                                       break;
+                               LOG_ERROR("%s = 0x%" PRIx64, gdb_regno_name(regno), reg_value);
+                       }
                        return ERROR_TARGET_TIMEOUT;
                }
 
@@ -1088,10 +1813,14 @@ static int riscv_run_algorithm(struct target *target, int num_mem_params,
                        return result;
        }
 
+       /* The current hart id might have been changed in poll(). */
+       if (riscv_set_current_hartid(target, hartid) != ERROR_OK)
+               return ERROR_FAIL;
+
        if (reg_pc->type->get(reg_pc) != ERROR_OK)
                return ERROR_FAIL;
        uint64_t final_pc = buf_get_u64(reg_pc->value, 0, reg_pc->size);
-       if (final_pc != exit_point) {
+       if (exit_point && final_pc != exit_point) {
                LOG_ERROR("PC ended up at 0x%" PRIx64 " instead of 0x%"
                                TARGET_PRIxADDR, final_pc, exit_point);
                return ERROR_FAIL;
@@ -1109,26 +1838,111 @@ static int riscv_run_algorithm(struct target *target, int num_mem_params,
                return ERROR_FAIL;
 
        for (int i = 0; i < num_reg_params; i++) {
+               if (reg_params[i].direction == PARAM_IN ||
+                               reg_params[i].direction == PARAM_IN_OUT) {
+                       struct reg *r = register_get_by_name(target->reg_cache, reg_params[i].reg_name, false);
+                       if (r->type->get(r) != ERROR_OK) {
+                               LOG_ERROR("get(%s) failed", r->name);
+                               return ERROR_FAIL;
+                       }
+                       buf_cpy(r->value, reg_params[i].value, reg_params[i].size);
+               }
                LOG_DEBUG("restore %s", reg_params[i].reg_name);
-               struct reg *r = register_get_by_name(target->reg_cache, reg_params[i].reg_name, 0);
+               struct reg *r = register_get_by_name(target->reg_cache, reg_params[i].reg_name, false);
                buf_set_u64(buf, 0, info->xlen[0], saved_regs[r->number]);
-               if (r->type->set(r, buf) != ERROR_OK)
+               if (r->type->set(r, buf) != ERROR_OK) {
+                       LOG_ERROR("set(%s) failed", r->name);
                        return ERROR_FAIL;
+               }
        }
 
        return ERROR_OK;
 }
 
-/* Should run code on the target to perform CRC of
-memory. Not yet implemented.
-*/
-
 static int riscv_checksum_memory(struct target *target,
                target_addr_t address, uint32_t count,
                uint32_t *checksum)
 {
-       *checksum = 0xFFFFFFFF;
-       return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+       struct working_area *crc_algorithm;
+       struct reg_param reg_params[2];
+       int retval;
+
+       LOG_DEBUG("address=0x%" TARGET_PRIxADDR "; count=0x%" PRIx32, address, count);
+
+       static const uint8_t riscv32_crc_code[] = {
+#include "contrib/loaders/checksum/riscv32_crc.inc"
+       };
+       static const uint8_t riscv64_crc_code[] = {
+#include "contrib/loaders/checksum/riscv64_crc.inc"
+       };
+
+       static const uint8_t *crc_code;
+
+       unsigned xlen = riscv_xlen(target);
+       unsigned crc_code_size;
+       if (xlen == 32) {
+               crc_code = riscv32_crc_code;
+               crc_code_size = sizeof(riscv32_crc_code);
+       } else {
+               crc_code = riscv64_crc_code;
+               crc_code_size = sizeof(riscv64_crc_code);
+       }
+
+       if (count < crc_code_size * 4) {
+               /* Don't use the algorithm for relatively small buffers. It's faster
+                * just to read the memory.  target_checksum_memory() will take care of
+                * that if we fail. */
+               return ERROR_FAIL;
+       }
+
+       retval = target_alloc_working_area(target, crc_code_size, &crc_algorithm);
+       if (retval != ERROR_OK)
+               return retval;
+
+       if (crc_algorithm->address + crc_algorithm->size > address &&
+                       crc_algorithm->address < address + count) {
+               /* Region to checksum overlaps with the work area we've been assigned.
+                * Bail. (Would be better to manually checksum what we read there, and
+                * use the algorithm for the rest.) */
+               target_free_working_area(target, crc_algorithm);
+               return ERROR_FAIL;
+       }
+
+       retval = target_write_buffer(target, crc_algorithm->address, crc_code_size,
+                       crc_code);
+       if (retval != ERROR_OK) {
+               LOG_ERROR("Failed to write code to " TARGET_ADDR_FMT ": %d",
+                               crc_algorithm->address, retval);
+               target_free_working_area(target, crc_algorithm);
+               return retval;
+       }
+
+       init_reg_param(&reg_params[0], "a0", xlen, PARAM_IN_OUT);
+       init_reg_param(&reg_params[1], "a1", xlen, PARAM_OUT);
+       buf_set_u64(reg_params[0].value, 0, xlen, address);
+       buf_set_u64(reg_params[1].value, 0, xlen, count);
+
+       /* 20 second timeout/megabyte */
+       int timeout = 20000 * (1 + (count / (1024 * 1024)));
+
+       retval = target_run_algorithm(target, 0, NULL, 2, reg_params,
+                       crc_algorithm->address,
+                       0,      /* Leave exit point unspecified because we don't know. */
+                       timeout, NULL);
+
+       if (retval == ERROR_OK)
+               *checksum = buf_get_u32(reg_params[0].value, 0, 32);
+       else
+               LOG_ERROR("error executing RISC-V CRC algorithm");
+
+       destroy_reg_param(&reg_params[0]);
+       destroy_reg_param(&reg_params[1]);
+
+       target_free_working_area(target, crc_algorithm);
+
+       LOG_DEBUG("checksum=0x%" PRIx32 ", result=%d", *checksum, retval);
+
+       return retval;
 }
 
 /*** OpenOCD Helper Functions ***/
@@ -1157,15 +1971,16 @@ static enum riscv_poll_hart riscv_poll_hart(struct target *target, int hartid)
        } else if (target->state != TARGET_RUNNING && !halted) {
                LOG_DEBUG("  triggered running");
                target->state = TARGET_RUNNING;
+               target->debug_reason = DBG_REASON_NOTHALTED;
                return RPH_DISCOVERED_RUNNING;
        }
 
        return RPH_NO_CHANGE;
 }
 
-int set_debug_reason(struct target *target, int hartid)
+int set_debug_reason(struct target *target, enum riscv_halt_reason halt_reason)
 {
-       switch (riscv_halt_reason(target, hartid)) {
+       switch (halt_reason) {
                case RISCV_HALT_BREAKPOINT:
                        target->debug_reason = DBG_REASON_BREAKPOINT;
                        break;
@@ -1173,6 +1988,7 @@ int set_debug_reason(struct target *target, int hartid)
                        target->debug_reason = DBG_REASON_WATCHPOINT;
                        break;
                case RISCV_HALT_INTERRUPT:
+               case RISCV_HALT_GROUP:
                        target->debug_reason = DBG_REASON_DBGRQ;
                        break;
                case RISCV_HALT_SINGLESTEP:
@@ -1184,6 +2000,7 @@ int set_debug_reason(struct target *target, int hartid)
                case RISCV_HALT_ERROR:
                        return ERROR_FAIL;
        }
+       LOG_DEBUG("[%s] debug_reason=%d", target_name(target), target->debug_reason);
        return ERROR_OK;
 }
 
@@ -1213,217 +2030,141 @@ int riscv_openocd_poll(struct target *target)
                }
                LOG_DEBUG("  hart %d halted", halted_hart);
 
-               /* If we're here then at least one hart triggered.  That means
-                * we want to go and halt _every_ hart in the system, as that's
-                * the invariant we hold here.  Some harts might have already
-                * halted (as we're either in single-step mode or they also
-                * triggered a breakpoint), so don't attempt to halt those
-                * harts. */
-               for (int i = 0; i < riscv_count_harts(target); ++i)
-                       riscv_halt_one_hart(target, i);
+               target->state = TARGET_HALTED;
+               enum riscv_halt_reason halt_reason = riscv_halt_reason(target, halted_hart);
+               if (set_debug_reason(target, halt_reason) != ERROR_OK)
+                       return ERROR_FAIL;
+
+               target->rtos->current_threadid = halted_hart + 1;
+               target->rtos->current_thread = halted_hart + 1;
+               riscv_set_rtos_hartid(target, halted_hart);
+
+               /* If we're here then at least one hart triggered.  That means we want
+                * to go and halt _every_ hart (configured with -rtos riscv) in the
+                * system, as that's the invariant we hold here.  Some harts might have
+                * already halted (as we're either in single-step mode or they also
+                * triggered a breakpoint), so don't attempt to halt those harts.
+                * riscv_halt() will do all that for us. */
+               riscv_halt(target);
 
        } else if (target->smp) {
-               bool halt_discovered = false;
-               bool newly_halted[128] = {0};
+               unsigned halts_discovered = 0;
+               unsigned total_targets = 0;
+               unsigned should_remain_halted = 0;
+               unsigned should_resume = 0;
                unsigned i = 0;
-               for (struct target_list *list = target->head; list != NULL;
+               for (struct target_list *list = target->head; list;
                                list = list->next, i++) {
+                       total_targets++;
                        struct target *t = list->target;
                        riscv_info_t *r = riscv_info(t);
-                       assert(i < DIM(newly_halted));
                        enum riscv_poll_hart out = riscv_poll_hart(t, r->current_hartid);
                        switch (out) {
-                               case RPH_NO_CHANGE:
-                                       break;
-                               case RPH_DISCOVERED_RUNNING:
-                                       t->state = TARGET_RUNNING;
-                                       break;
-                               case RPH_DISCOVERED_HALTED:
-                                       halt_discovered = true;
-                                       newly_halted[i] = true;
-                                       t->state = TARGET_HALTED;
-                                       if (set_debug_reason(t, r->current_hartid) != ERROR_OK)
-                                               return ERROR_FAIL;
-                                       break;
-                               case RPH_ERROR:
+                       case RPH_NO_CHANGE:
+                               break;
+                       case RPH_DISCOVERED_RUNNING:
+                               t->state = TARGET_RUNNING;
+                               t->debug_reason = DBG_REASON_NOTHALTED;
+                               break;
+                       case RPH_DISCOVERED_HALTED:
+                               halts_discovered++;
+                               t->state = TARGET_HALTED;
+                               enum riscv_halt_reason halt_reason =
+                                       riscv_halt_reason(t, r->current_hartid);
+                               if (set_debug_reason(t, halt_reason) != ERROR_OK)
                                        return ERROR_FAIL;
-                       }
-               }
 
-               if (halt_discovered) {
-                       LOG_DEBUG("Halt other targets in this SMP group.");
-                       i = 0;
-                       for (struct target_list *list = target->head; list != NULL;
-                                       list = list->next, i++) {
-                               struct target *t = list->target;
-                               riscv_info_t *r = riscv_info(t);
-                               if (t->state != TARGET_HALTED) {
-                                       if (riscv_halt_one_hart(t, r->current_hartid) != ERROR_OK)
-                                               return ERROR_FAIL;
-                                       t->state = TARGET_HALTED;
-                                       if (set_debug_reason(t, r->current_hartid) != ERROR_OK)
-                                               return ERROR_FAIL;
-                                       newly_halted[i] = true;
+                               if (halt_reason == RISCV_HALT_BREAKPOINT) {
+                                       int retval;
+                                       switch (riscv_semihosting(t, &retval)) {
+                                       case SEMI_NONE:
+                                       case SEMI_WAITING:
+                                               /* This hart should remain halted. */
+                                               should_remain_halted++;
+                                               break;
+                                       case SEMI_HANDLED:
+                                               /* This hart should be resumed, along with any other
+                                                        * harts that halted due to haltgroups. */
+                                               should_resume++;
+                                               break;
+                                       case SEMI_ERROR:
+                                               return retval;
+                                       }
+                               } else if (halt_reason != RISCV_HALT_GROUP) {
+                                       should_remain_halted++;
                                }
-                       }
+                               break;
 
-                       /* Now that we have all our ducks in a row, tell the higher layers
-                        * what just happened. */
-                       i = 0;
-                       for (struct target_list *list = target->head; list != NULL;
-                                       list = list->next, i++) {
-                               struct target *t = list->target;
-                               if (newly_halted[i])
-                                       target_call_event_callbacks(t, TARGET_EVENT_HALTED);
+                       case RPH_ERROR:
+                               return ERROR_FAIL;
                        }
                }
+
+               LOG_DEBUG("should_remain_halted=%d, should_resume=%d",
+                                 should_remain_halted, should_resume);
+               if (should_remain_halted && should_resume) {
+                       LOG_WARNING("%d harts should remain halted, and %d should resume.",
+                                               should_remain_halted, should_resume);
+               }
+               if (should_remain_halted) {
+                       LOG_DEBUG("halt all");
+                       riscv_halt(target);
+               } else if (should_resume) {
+                       LOG_DEBUG("resume all");
+                       riscv_resume(target, true, 0, 0, 0, false);
+               }
                return ERROR_OK;
 
        } else {
                enum riscv_poll_hart out = riscv_poll_hart(target,
                                riscv_current_hartid(target));
                if (out == RPH_NO_CHANGE || out == RPH_DISCOVERED_RUNNING)
-                       return ERROR_OK;
-               else if (out == RPH_ERROR)
-                       return ERROR_FAIL;
-
-               halted_hart = riscv_current_hartid(target);
-               LOG_DEBUG("  hart %d halted", halted_hart);
-       }
-
-       target->state = TARGET_HALTED;
-       if (set_debug_reason(target, halted_hart) != ERROR_OK)
-               return ERROR_FAIL;
-
-       if (riscv_rtos_enabled(target)) {
-               target->rtos->current_threadid = halted_hart + 1;
-               target->rtos->current_thread = halted_hart + 1;
-               riscv_set_rtos_hartid(target, halted_hart);
-       }
-
-       target->state = TARGET_HALTED;
-
-       if (target->debug_reason == DBG_REASON_BREAKPOINT) {
-               int retval;
-               if (riscv_semihosting(target, &retval) != 0)
-                       return retval;
-       }
-
-       target_call_event_callbacks(target, TARGET_EVENT_HALTED);
-       return ERROR_OK;
-}
-
-int riscv_openocd_halt(struct target *target)
-{
-       RISCV_INFO(r);
-       int result;
-
-       LOG_DEBUG("[%d] halting all harts", target->coreid);
-
-       if (target->smp) {
-               LOG_DEBUG("Halt other targets in this SMP group.");
-               struct target_list *targets = target->head;
-               result = ERROR_OK;
-               while (targets) {
-                       struct target *t = targets->target;
-                       targets = targets->next;
-                       if (t->state != TARGET_HALTED) {
-                               if (riscv_halt_all_harts(t) != ERROR_OK)
-                                       result = ERROR_FAIL;
-                       }
-               }
-       } else {
-               result = riscv_halt_all_harts(target);
-       }
-
-       if (riscv_rtos_enabled(target)) {
-               if (r->rtos_hartid != -1) {
-                       LOG_DEBUG("halt requested on RTOS hartid %d", r->rtos_hartid);
-                       target->rtos->current_threadid = r->rtos_hartid + 1;
-                       target->rtos->current_thread = r->rtos_hartid + 1;
-               } else
-                       LOG_DEBUG("halt requested, but no known RTOS hartid");
-       }
-
-       target->state = TARGET_HALTED;
-       target->debug_reason = DBG_REASON_DBGRQ;
-       target_call_event_callbacks(target, TARGET_EVENT_HALTED);
-       return result;
-}
-
-int riscv_openocd_resume(
-               struct target *target,
-               int current,
-               target_addr_t address,
-               int handle_breakpoints,
-               int debug_execution)
-{
-       LOG_DEBUG("debug_reason=%d", target->debug_reason);
-
-       if (!current)
-               riscv_set_register(target, GDB_REGNO_PC, address);
-
-       if (target->debug_reason == DBG_REASON_WATCHPOINT) {
-               /* To be able to run off a trigger, disable all the triggers, step, and
-                * then resume as usual. */
-               struct watchpoint *watchpoint = target->watchpoints;
-               bool trigger_temporarily_cleared[RISCV_MAX_HWBPS] = {0};
-
-               int i = 0;
-               int result = ERROR_OK;
-               while (watchpoint && result == ERROR_OK) {
-                       LOG_DEBUG("watchpoint %d: set=%d", i, watchpoint->set);
-                       trigger_temporarily_cleared[i] = watchpoint->set;
-                       if (watchpoint->set)
-                               result = riscv_remove_watchpoint(target, watchpoint);
-                       watchpoint = watchpoint->next;
-                       i++;
-               }
-
-               if (result == ERROR_OK)
-                       result = riscv_step_rtos_hart(target);
-
-               watchpoint = target->watchpoints;
-               i = 0;
-               while (watchpoint) {
-                       LOG_DEBUG("watchpoint %d: cleared=%d", i, trigger_temporarily_cleared[i]);
-                       if (trigger_temporarily_cleared[i]) {
-                               if (result == ERROR_OK)
-                                       result = riscv_add_watchpoint(target, watchpoint);
-                               else
-                                       riscv_add_watchpoint(target, watchpoint);
-                       }
-                       watchpoint = watchpoint->next;
-                       i++;
-               }
+                       return ERROR_OK;
+               else if (out == RPH_ERROR)
+                       return ERROR_FAIL;
 
-               if (result != ERROR_OK)
-                       return result;
+               halted_hart = riscv_current_hartid(target);
+               LOG_DEBUG("  hart %d halted", halted_hart);
+
+               enum riscv_halt_reason halt_reason = riscv_halt_reason(target, halted_hart);
+               if (set_debug_reason(target, halt_reason) != ERROR_OK)
+                       return ERROR_FAIL;
+               target->state = TARGET_HALTED;
        }
 
-       int out = riscv_resume_all_harts(target);
-       if (out != ERROR_OK) {
-               LOG_ERROR("unable to resume all harts");
-               return out;
+       if (target->debug_reason == DBG_REASON_BREAKPOINT) {
+               int retval;
+               switch (riscv_semihosting(target, &retval)) {
+                       case SEMI_NONE:
+                       case SEMI_WAITING:
+                               target_call_event_callbacks(target, TARGET_EVENT_HALTED);
+                               break;
+                       case SEMI_HANDLED:
+                               if (riscv_resume(target, true, 0, 0, 0, false) != ERROR_OK)
+                                       return ERROR_FAIL;
+                               break;
+                       case SEMI_ERROR:
+                               return retval;
+               }
+       } else {
+               target_call_event_callbacks(target, TARGET_EVENT_HALTED);
        }
 
-       register_cache_invalidate(target->reg_cache);
-       target->state = TARGET_RUNNING;
-       target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
-       return out;
+       return ERROR_OK;
 }
 
-int riscv_openocd_step(
-               struct target *target,
-               int current,
-               target_addr_t address,
-               int handle_breakpoints
-) {
+int riscv_openocd_step(struct target *target, int current,
+               target_addr_t address, int handle_breakpoints)
+{
        LOG_DEBUG("stepping rtos hart");
 
        if (!current)
                riscv_set_register(target, GDB_REGNO_PC, address);
 
+       riscv_reg_t trigger_state[RISCV_MAX_HWBPS] = {0};
+       if (disable_triggers(target, trigger_state) != ERROR_OK)
+               return ERROR_FAIL;
+
        int out = riscv_step_rtos_hart(target);
        if (out != ERROR_OK) {
                LOG_ERROR("unable to step rtos hart");
@@ -1431,6 +2172,10 @@ int riscv_openocd_step(
        }
 
        register_cache_invalidate(target->reg_cache);
+
+       if (enable_triggers(target, trigger_state) != ERROR_OK)
+               return ERROR_FAIL;
+
        target->state = TARGET_RUNNING;
        target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
        target->state = TARGET_HALTED;
@@ -1502,6 +2247,16 @@ COMMAND_HANDLER(riscv_set_prefer_sba)
        return ERROR_OK;
 }
 
+COMMAND_HANDLER(riscv_set_enable_virtual)
+{
+       if (CMD_ARGC != 1) {
+               LOG_ERROR("Command takes exactly 1 parameter");
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+       COMMAND_PARSE_ON_OFF(CMD_ARGV[0], riscv_enable_virtual);
+       return ERROR_OK;
+}
+
 void parse_error(const char *string, char c, unsigned position)
 {
        char buf[position+2];
@@ -1568,9 +2323,10 @@ int parse_ranges(range_t **ranges, const char **argv)
                }
 
                if (pass == 0) {
-                       if (*ranges)
-                               free(*ranges);
+                       free(*ranges);
                        *ranges = calloc(range + 2, sizeof(range_t));
+                       if (!*ranges)
+                               return ERROR_FAIL;
                } else {
                        (*ranges)[range].low = 1;
                        (*ranges)[range].high = 0;
@@ -1623,7 +2379,7 @@ COMMAND_HANDLER(riscv_authdata_read)
                uint32_t value;
                if (r->authdata_read(target, &value) != ERROR_OK)
                        return ERROR_FAIL;
-               command_print(CMD, "0x%" PRIx32, value);
+               command_print_sameline(CMD, "0x%08" PRIx32, value);
                return ERROR_OK;
        } else {
                LOG_ERROR("authdata_read is not implemented for this target.");
@@ -1764,55 +2520,147 @@ COMMAND_HANDLER(riscv_set_ir)
        uint32_t value;
        COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value);
 
-       if (!strcmp(CMD_ARGV[0], "idcode")) {
+       if (!strcmp(CMD_ARGV[0], "idcode"))
                buf_set_u32(ir_idcode, 0, 32, value);
-               return ERROR_OK;
-       } else if (!strcmp(CMD_ARGV[0], "dtmcs")) {
+       else if (!strcmp(CMD_ARGV[0], "dtmcs"))
                buf_set_u32(ir_dtmcontrol, 0, 32, value);
-               return ERROR_OK;
-       } else if (!strcmp(CMD_ARGV[0], "dmi")) {
+       else if (!strcmp(CMD_ARGV[0], "dmi"))
                buf_set_u32(ir_dbus, 0, 32, value);
-               return ERROR_OK;
+       else
+               return ERROR_FAIL;
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(riscv_resume_order)
+{
+       if (CMD_ARGC > 1) {
+               LOG_ERROR("Command takes at most one argument");
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+
+       if (!strcmp(CMD_ARGV[0], "normal")) {
+               resume_order = RO_NORMAL;
+       } else if (!strcmp(CMD_ARGV[0], "reversed")) {
+               resume_order = RO_REVERSED;
        } else {
+               LOG_ERROR("Unsupported resume order: %s", CMD_ARGV[0]);
                return ERROR_FAIL;
        }
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(riscv_use_bscan_tunnel)
+{
+       int irwidth = 0;
+       int tunnel_type = BSCAN_TUNNEL_NESTED_TAP;
+
+       if (CMD_ARGC > 2) {
+               LOG_ERROR("Command takes at most two arguments");
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       } else if (CMD_ARGC == 1) {
+               COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], irwidth);
+       } else if (CMD_ARGC == 2) {
+               COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], irwidth);
+               COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], tunnel_type);
+       }
+       if (tunnel_type == BSCAN_TUNNEL_NESTED_TAP)
+               LOG_INFO("Nested Tap based Bscan Tunnel Selected");
+       else if (tunnel_type == BSCAN_TUNNEL_DATA_REGISTER)
+               LOG_INFO("Simple Register based Bscan Tunnel Selected");
+       else
+               LOG_INFO("Invalid Tunnel type selected ! : selecting default Nested Tap Type");
+
+       bscan_tunnel_type = tunnel_type;
+       bscan_tunnel_ir_width = irwidth;
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(riscv_set_enable_virt2phys)
+{
+       if (CMD_ARGC != 1) {
+               LOG_ERROR("Command takes exactly 1 parameter");
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+       COMMAND_PARSE_ON_OFF(CMD_ARGV[0], riscv_enable_virt2phys);
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(riscv_set_ebreakm)
+{
+       if (CMD_ARGC != 1) {
+               LOG_ERROR("Command takes exactly 1 parameter");
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+       COMMAND_PARSE_ON_OFF(CMD_ARGV[0], riscv_ebreakm);
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(riscv_set_ebreaks)
+{
+       if (CMD_ARGC != 1) {
+               LOG_ERROR("Command takes exactly 1 parameter");
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+       COMMAND_PARSE_ON_OFF(CMD_ARGV[0], riscv_ebreaks);
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(riscv_set_ebreaku)
+{
+       if (CMD_ARGC != 1) {
+               LOG_ERROR("Command takes exactly 1 parameter");
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+       COMMAND_PARSE_ON_OFF(CMD_ARGV[0], riscv_ebreaku);
+       return ERROR_OK;
 }
 
 static const struct command_registration riscv_exec_command_handlers[] = {
        {
                .name = "test_compliance",
                .handler = riscv_test_compliance,
+               .usage = "",
                .mode = COMMAND_EXEC,
-               .usage = "riscv test_compliance",
                .help = "Runs a basic compliance test suite against the RISC-V Debug Spec."
        },
        {
                .name = "set_command_timeout_sec",
                .handler = riscv_set_command_timeout_sec,
                .mode = COMMAND_ANY,
-               .usage = "riscv set_command_timeout_sec [sec]",
+               .usage = "[sec]",
                .help = "Set the wall-clock timeout (in seconds) for individual commands"
        },
        {
                .name = "set_reset_timeout_sec",
                .handler = riscv_set_reset_timeout_sec,
                .mode = COMMAND_ANY,
-               .usage = "riscv set_reset_timeout_sec [sec]",
+               .usage = "[sec]",
                .help = "Set the wall-clock timeout (in seconds) after reset is deasserted"
        },
        {
                .name = "set_prefer_sba",
                .handler = riscv_set_prefer_sba,
                .mode = COMMAND_ANY,
-               .usage = "riscv set_prefer_sba on|off",
+               .usage = "on|off",
                .help = "When on, prefer to use System Bus Access to access memory. "
-                       "When off, prefer to use the Program Buffer to access memory."
+                       "When off (default), prefer to use the Program Buffer to access memory."
+       },
+       {
+               .name = "set_enable_virtual",
+               .handler = riscv_set_enable_virtual,
+               .mode = COMMAND_ANY,
+               .usage = "on|off",
+               .help = "When on, memory accesses are performed on physical or virtual "
+                               "memory depending on the current system configuration. "
+                               "When off (default), all memory accessses are performed on physical memory."
        },
        {
                .name = "expose_csrs",
                .handler = riscv_set_expose_csrs,
                .mode = COMMAND_ANY,
-               .usage = "riscv expose_csrs n0[-m0][,n1[-m1]]...",
+               .usage = "n0[-m0][,n1[-m1]]...",
                .help = "Configure a list of inclusive ranges for CSRs to expose in "
                                "addition to the standard ones. This must be executed before "
                                "`init`."
@@ -1821,7 +2669,7 @@ static const struct command_registration riscv_exec_command_handlers[] = {
                .name = "expose_custom",
                .handler = riscv_set_expose_custom,
                .mode = COMMAND_ANY,
-               .usage = "riscv expose_custom n0[-m0][,n1[-m1]]...",
+               .usage = "n0[-m0][,n1[-m1]]...",
                .help = "Configure a list of inclusive ranges for custom registers to "
                        "expose. custom0 is accessed as abstract register number 0xc000, "
                        "etc. This must be executed before `init`."
@@ -1829,36 +2677,36 @@ static const struct command_registration riscv_exec_command_handlers[] = {
        {
                .name = "authdata_read",
                .handler = riscv_authdata_read,
+               .usage = "",
                .mode = COMMAND_ANY,
-               .usage = "riscv authdata_read",
                .help = "Return the 32-bit value read from authdata."
        },
        {
                .name = "authdata_write",
                .handler = riscv_authdata_write,
                .mode = COMMAND_ANY,
-               .usage = "riscv authdata_write value",
+               .usage = "value",
                .help = "Write the 32-bit value to authdata."
        },
        {
                .name = "dmi_read",
                .handler = riscv_dmi_read,
                .mode = COMMAND_ANY,
-               .usage = "riscv dmi_read address",
+               .usage = "address",
                .help = "Perform a 32-bit DMI read at address, returning the value."
        },
        {
                .name = "dmi_write",
                .handler = riscv_dmi_write,
                .mode = COMMAND_ANY,
-               .usage = "riscv dmi_write address value",
+               .usage = "address value",
                .help = "Perform a 32-bit DMI write of value at address."
        },
        {
                .name = "test_sba_config_reg",
                .handler = riscv_test_sba_config_reg,
                .mode = COMMAND_ANY,
-               .usage = "riscv test_sba_config_reg legal_address num_words "
+               .usage = "legal_address num_words "
                        "illegal_address run_sbbusyerror_test[on/off]",
                .help = "Perform a series of tests on the SBCS register. "
                        "Inputs are a legal, 128-byte aligned address and a number of words to "
@@ -1871,19 +2719,71 @@ static const struct command_registration riscv_exec_command_handlers[] = {
                .name = "reset_delays",
                .handler = riscv_reset_delays,
                .mode = COMMAND_ANY,
-               .usage = "reset_delays [wait]",
+               .usage = "[wait]",
                .help = "OpenOCD learns how many Run-Test/Idle cycles are required "
                        "between scans to avoid encountering the target being busy. This "
                        "command resets those learned values after `wait` scans. It's only "
                        "useful for testing OpenOCD itself."
        },
+       {
+               .name = "resume_order",
+               .handler = riscv_resume_order,
+               .mode = COMMAND_ANY,
+               .usage = "normal|reversed",
+               .help = "Choose the order that harts are resumed in when `hasel` is not "
+                       "supported. Normal order is from lowest hart index to highest. "
+                       "Reversed order is from highest hart index to lowest."
+       },
        {
                .name = "set_ir",
                .handler = riscv_set_ir,
                .mode = COMMAND_ANY,
-               .usage = "riscv set_ir_idcode [idcode|dtmcs|dmi] value",
+               .usage = "[idcode|dtmcs|dmi] value",
                .help = "Set IR value for specified JTAG register."
        },
+       {
+               .name = "use_bscan_tunnel",
+               .handler = riscv_use_bscan_tunnel,
+               .mode = COMMAND_ANY,
+               .usage = "value [type]",
+               .help = "Enable or disable use of a BSCAN tunnel to reach DM.  Supply "
+                       "the width of the DM transport TAP's instruction register to "
+                       "enable.  Supply a value of 0 to disable. Pass A second argument "
+                       "(optional) to indicate Bscan Tunnel Type {0:(default) NESTED_TAP , "
+                       "1: DATA_REGISTER}"
+       },
+       {
+               .name = "set_enable_virt2phys",
+               .handler = riscv_set_enable_virt2phys,
+               .mode = COMMAND_ANY,
+               .usage = "on|off",
+               .help = "When on (default), enable translation from virtual address to "
+                       "physical address."
+       },
+       {
+               .name = "set_ebreakm",
+               .handler = riscv_set_ebreakm,
+               .mode = COMMAND_ANY,
+               .usage = "on|off",
+               .help = "Control dcsr.ebreakm. When off, M-mode ebreak instructions "
+                       "don't trap to OpenOCD. Defaults to on."
+       },
+       {
+               .name = "set_ebreaks",
+               .handler = riscv_set_ebreaks,
+               .mode = COMMAND_ANY,
+               .usage = "on|off",
+               .help = "Control dcsr.ebreaks. When off, S-mode ebreak instructions "
+                       "don't trap to OpenOCD. Defaults to on."
+       },
+       {
+               .name = "set_ebreaku",
+               .handler = riscv_set_ebreaku,
+               .mode = COMMAND_ANY,
+               .usage = "on|off",
+               .help = "Control dcsr.ebreaku. When off, U-mode ebreak instructions "
+                       "don't trap to OpenOCD. Defaults to on."
+       },
        COMMAND_REGISTRATION_DONE
 };
 
@@ -1920,8 +2820,16 @@ const struct command_registration riscv_command_handlers[] = {
        COMMAND_REGISTRATION_DONE
 };
 
-unsigned riscv_address_bits(struct target *target)
+static unsigned riscv_xlen_nonconst(struct target *target)
+{
+       return riscv_xlen(target);
+}
+
+static unsigned int riscv_data_bits(struct target *target)
 {
+       RISCV_INFO(r);
+       if (r->data_bits)
+               return r->data_bits(target);
        return riscv_xlen(target);
 }
 
@@ -1935,8 +2843,8 @@ struct target_type riscv_target = {
        /* poll current target status */
        .poll = old_or_new_riscv_poll,
 
-       .halt = old_or_new_riscv_halt,
-       .resume = old_or_new_riscv_resume,
+       .halt = riscv_halt,
+       .resume = riscv_target_resume,
        .step = old_or_new_riscv_step,
 
        .assert_reset = riscv_assert_reset,
@@ -1944,10 +2852,17 @@ struct target_type riscv_target = {
 
        .read_memory = riscv_read_memory,
        .write_memory = riscv_write_memory,
+       .read_phys_memory = riscv_read_phys_memory,
+       .write_phys_memory = riscv_write_phys_memory,
 
        .checksum_memory = riscv_checksum_memory,
 
+       .mmu = riscv_mmu,
+       .virt2phys = riscv_virt2phys,
+
+       .get_gdb_arch = riscv_get_gdb_arch,
        .get_gdb_reg_list = riscv_get_gdb_reg_list,
+       .get_gdb_reg_list_noread = riscv_get_gdb_reg_list_noread,
 
        .add_breakpoint = riscv_add_breakpoint,
        .remove_breakpoint = riscv_remove_breakpoint,
@@ -1962,7 +2877,8 @@ struct target_type riscv_target = {
 
        .commands = riscv_command_handlers,
 
-       .address_bits = riscv_address_bits
+       .address_bits = riscv_xlen_nonconst,
+       .data_bits = riscv_data_bits
 };
 
 /*** RISC-V Interface ***/
@@ -1976,72 +2892,52 @@ void riscv_info_init(struct target *target, riscv_info_t *r)
 
        memset(r->trigger_unique_id, 0xff, sizeof(r->trigger_unique_id));
 
-       for (size_t h = 0; h < RISCV_MAX_HARTS; ++h) {
+       for (size_t h = 0; h < RISCV_MAX_HARTS; ++h)
                r->xlen[h] = -1;
-
-               for (size_t e = 0; e < RISCV_MAX_REGISTERS; ++e)
-                       r->valid_saved_registers[h][e] = false;
-       }
-}
-
-int riscv_halt_all_harts(struct target *target)
-{
-       for (int i = 0; i < riscv_count_harts(target); ++i) {
-               if (!riscv_hart_enabled(target, i))
-                       continue;
-
-               riscv_halt_one_hart(target, i);
-       }
-
-       riscv_invalidate_register_cache(target);
-
-       return ERROR_OK;
 }
 
-int riscv_halt_one_hart(struct target *target, int hartid)
+static int riscv_resume_go_all_harts(struct target *target)
 {
        RISCV_INFO(r);
-       LOG_DEBUG("halting hart %d", hartid);
-       if (riscv_set_current_hartid(target, hartid) != ERROR_OK)
-               return ERROR_FAIL;
-       if (riscv_is_halted(target)) {
-               LOG_DEBUG("  hart %d requested halt, but was already halted", hartid);
-               return ERROR_OK;
-       }
 
-       int result = r->halt_current_hart(target);
-       register_cache_invalidate(target->reg_cache);
-       return result;
-}
+       /* Dummy variables to make mingw32-gcc happy. */
+       int first = 0;
+       int last = 1;
+       int step = 1;
+       switch (resume_order) {
+               case RO_NORMAL:
+                       first = 0;
+                       last = riscv_count_harts(target) - 1;
+                       step = 1;
+                       break;
+               case RO_REVERSED:
+                       first = riscv_count_harts(target) - 1;
+                       last = 0;
+                       step = -1;
+                       break;
+               default:
+                       assert(0);
+       }
 
-int riscv_resume_all_harts(struct target *target)
-{
-       for (int i = 0; i < riscv_count_harts(target); ++i) {
+       for (int i = first; i != last + step; i += step) {
                if (!riscv_hart_enabled(target, i))
                        continue;
 
-               riscv_resume_one_hart(target, i);
+               LOG_DEBUG("resuming hart %d", i);
+               if (riscv_set_current_hartid(target, i) != ERROR_OK)
+                       return ERROR_FAIL;
+               if (riscv_is_halted(target)) {
+                       if (r->resume_go(target) != ERROR_OK)
+                               return ERROR_FAIL;
+               } else {
+                       LOG_DEBUG("  hart %d requested resume, but was already resumed", i);
+               }
        }
 
        riscv_invalidate_register_cache(target);
        return ERROR_OK;
 }
 
-int riscv_resume_one_hart(struct target *target, int hartid)
-{
-       RISCV_INFO(r);
-       LOG_DEBUG("resuming hart %d", hartid);
-       if (riscv_set_current_hartid(target, hartid) != ERROR_OK)
-               return ERROR_FAIL;
-       if (!riscv_is_halted(target)) {
-               LOG_DEBUG("  hart %d requested resume, but was already resumed", hartid);
-               return ERROR_OK;
-       }
-
-       r->on_resume(target);
-       return r->resume_current_hart(target);
-}
-
 int riscv_step_rtos_hart(struct target *target)
 {
        RISCV_INFO(r);
@@ -2087,7 +2983,7 @@ bool riscv_supports_extension(struct target *target, int hartid, char letter)
        return r->misa[hartid] & (1 << num);
 }
 
-int riscv_xlen(const struct target *target)
+unsigned riscv_xlen(const struct target *target)
 {
        return riscv_xlen_of_hart(target, riscv_current_hartid(target));
 }
@@ -2099,7 +2995,6 @@ int riscv_xlen_of_hart(const struct target *target, int hartid)
        return r->xlen[hartid];
 }
 
-extern struct rtos_type riscv_rtos;
 bool riscv_rtos_enabled(const struct target *target)
 {
        return false;
@@ -2161,12 +3056,12 @@ void riscv_set_rtos_hartid(struct target *target, int hartid)
 
 int riscv_count_harts(struct target *target)
 {
-       if (target == NULL)
+       if (!target)
                return 1;
        RISCV_INFO(r);
-       if (r == NULL)
+       if (!r || !r->hart_count)
                return 1;
-       return r->hart_count;
+       return r->hart_count(target);
 }
 
 bool riscv_has_register(struct target *target, int hartid, int regid)
@@ -2174,6 +3069,55 @@ bool riscv_has_register(struct target *target, int hartid, int regid)
        return 1;
 }
 
+/**
+ * If write is true:
+ *   return true iff we are guaranteed that the register will contain exactly
+ *       the value we just wrote when it's read.
+ * If write is false:
+ *   return true iff we are guaranteed that the register will read the same
+ *       value in the future as the value we just read.
+ */
+static bool gdb_regno_cacheable(enum gdb_regno regno, bool write)
+{
+       /* GPRs, FPRs, vector registers are just normal data stores. */
+       if (regno <= GDB_REGNO_XPR31 ||
+                       (regno >= GDB_REGNO_FPR0 && regno <= GDB_REGNO_FPR31) ||
+                       (regno >= GDB_REGNO_V0 && regno <= GDB_REGNO_V31))
+               return true;
+
+       /* Most CSRs won't change value on us, but we can't assume it about rbitrary
+        * CSRs. */
+       switch (regno) {
+               case GDB_REGNO_DPC:
+                       return true;
+
+               case GDB_REGNO_VSTART:
+               case GDB_REGNO_VXSAT:
+               case GDB_REGNO_VXRM:
+               case GDB_REGNO_VLENB:
+               case GDB_REGNO_VL:
+               case GDB_REGNO_VTYPE:
+               case GDB_REGNO_MISA:
+               case GDB_REGNO_DCSR:
+               case GDB_REGNO_DSCRATCH0:
+               case GDB_REGNO_MSTATUS:
+               case GDB_REGNO_MEPC:
+               case GDB_REGNO_MCAUSE:
+               case GDB_REGNO_SATP:
+                       /*
+                        * WARL registers might not contain the value we just wrote, but
+                        * these ones won't spontaneously change their value either. *
+                        */
+                       return !write;
+
+               case GDB_REGNO_TSELECT: /* I think this should be above, but then it doesn't work. */
+               case GDB_REGNO_TDATA1:  /* Changes value when tselect is changed. */
+               case GDB_REGNO_TDATA2:  /* Changse value when tselect is changed. */
+               default:
+                       return false;
+       }
+}
+
 /**
  * This function is called when the debug user wants to change the value of a
  * register. The new value may be cached, and may not be written until the hart
@@ -2189,7 +3133,23 @@ int riscv_set_register_on_hart(struct target *target, int hartid,
        RISCV_INFO(r);
        LOG_DEBUG("{%d} %s <- %" PRIx64, hartid, gdb_regno_name(regid), value);
        assert(r->set_register);
-       return r->set_register(target, hartid, regid, value);
+
+       /* TODO: Hack to deal with gdb that thinks these registers still exist. */
+       if (regid > GDB_REGNO_XPR15 && regid <= GDB_REGNO_XPR31 && value == 0 &&
+                       riscv_supports_extension(target, hartid, 'E'))
+               return ERROR_OK;
+
+       struct reg *reg = &target->reg_cache->reg_list[regid];
+       buf_set_u64(reg->value, 0, reg->size, value);
+
+       int result = r->set_register(target, hartid, regid, value);
+       if (result == ERROR_OK)
+               reg->valid = gdb_regno_cacheable(regid, true);
+       else
+               reg->valid = false;
+       LOG_DEBUG("[%s]{%d} wrote 0x%" PRIx64 " to %s valid=%d",
+                         target_name(target), hartid, value, reg->name, reg->valid);
+       return result;
 }
 
 int riscv_get_register(struct target *target, riscv_reg_t *value,
@@ -2205,14 +3165,31 @@ int riscv_get_register_on_hart(struct target *target, riscv_reg_t *value,
        RISCV_INFO(r);
 
        struct reg *reg = &target->reg_cache->reg_list[regid];
+       if (!reg->exist) {
+               LOG_DEBUG("[%s]{%d} %s does not exist.",
+                                 target_name(target), hartid, gdb_regno_name(regid));
+               return ERROR_FAIL;
+       }
 
        if (reg && reg->valid && hartid == riscv_current_hartid(target)) {
                *value = buf_get_u64(reg->value, 0, reg->size);
+               LOG_DEBUG("{%d} %s: %" PRIx64 " (cached)", hartid,
+                                 gdb_regno_name(regid), *value);
+               return ERROR_OK;
+       }
+
+       /* TODO: Hack to deal with gdb that thinks these registers still exist. */
+       if (regid > GDB_REGNO_XPR15 && regid <= GDB_REGNO_XPR31 &&
+                       riscv_supports_extension(target, hartid, 'E')) {
+               *value = 0;
                return ERROR_OK;
        }
 
        int result = r->get_register(target, value, hartid, regid);
 
+       if (result == ERROR_OK)
+               reg->valid = gdb_regno_cacheable(regid, false);
+
        LOG_DEBUG("{%d} %s: %" PRIx64, hartid, gdb_regno_name(regid), *value);
        return result;
 }
@@ -2323,7 +3300,9 @@ int riscv_enumerate_triggers(struct target *target)
                for (unsigned t = 0; t < RISCV_MAX_TRIGGERS; ++t) {
                        r->trigger_count[hartid] = t;
 
-                       riscv_set_register_on_hart(target, hartid, GDB_REGNO_TSELECT, t);
+                       /* If we can't write tselect, then this hart does not support triggers. */
+                       if (riscv_set_register_on_hart(target, hartid, GDB_REGNO_TSELECT, t) != ERROR_OK)
+                               break;
                        uint64_t tselect_rb;
                        result = riscv_get_register_on_hart(target, &tselect_rb, hartid,
                                        GDB_REGNO_TSELECT);
@@ -2341,6 +3320,8 @@ int riscv_enumerate_triggers(struct target *target)
                                return result;
 
                        int type = get_field(tdata1, MCONTROL_TYPE(riscv_xlen(target)));
+                       if (type == 0)
+                               break;
                        switch (type) {
                                case 1:
                                        /* On these older cores we don't support software using
@@ -2369,10 +3350,68 @@ const char *gdb_regno_name(enum gdb_regno regno)
        switch (regno) {
                case GDB_REGNO_ZERO:
                        return "zero";
+               case GDB_REGNO_RA:
+                       return "ra";
+               case GDB_REGNO_SP:
+                       return "sp";
+               case GDB_REGNO_GP:
+                       return "gp";
+               case GDB_REGNO_TP:
+                       return "tp";
+               case GDB_REGNO_T0:
+                       return "t0";
+               case GDB_REGNO_T1:
+                       return "t1";
+               case GDB_REGNO_T2:
+                       return "t2";
                case GDB_REGNO_S0:
                        return "s0";
                case GDB_REGNO_S1:
                        return "s1";
+               case GDB_REGNO_A0:
+                       return "a0";
+               case GDB_REGNO_A1:
+                       return "a1";
+               case GDB_REGNO_A2:
+                       return "a2";
+               case GDB_REGNO_A3:
+                       return "a3";
+               case GDB_REGNO_A4:
+                       return "a4";
+               case GDB_REGNO_A5:
+                       return "a5";
+               case GDB_REGNO_A6:
+                       return "a6";
+               case GDB_REGNO_A7:
+                       return "a7";
+               case GDB_REGNO_S2:
+                       return "s2";
+               case GDB_REGNO_S3:
+                       return "s3";
+               case GDB_REGNO_S4:
+                       return "s4";
+               case GDB_REGNO_S5:
+                       return "s5";
+               case GDB_REGNO_S6:
+                       return "s6";
+               case GDB_REGNO_S7:
+                       return "s7";
+               case GDB_REGNO_S8:
+                       return "s8";
+               case GDB_REGNO_S9:
+                       return "s9";
+               case GDB_REGNO_S10:
+                       return "s10";
+               case GDB_REGNO_S11:
+                       return "s11";
+               case GDB_REGNO_T3:
+                       return "t3";
+               case GDB_REGNO_T4:
+                       return "t4";
+               case GDB_REGNO_T5:
+                       return "t5";
+               case GDB_REGNO_T6:
+                       return "t6";
                case GDB_REGNO_PC:
                        return "pc";
                case GDB_REGNO_FPR0:
@@ -2393,12 +3432,86 @@ const char *gdb_regno_name(enum gdb_regno regno)
                        return "dpc";
                case GDB_REGNO_DCSR:
                        return "dcsr";
-               case GDB_REGNO_DSCRATCH:
-                       return "dscratch";
+               case GDB_REGNO_DSCRATCH0:
+                       return "dscratch0";
                case GDB_REGNO_MSTATUS:
                        return "mstatus";
+               case GDB_REGNO_MEPC:
+                       return "mepc";
+               case GDB_REGNO_MCAUSE:
+                       return "mcause";
                case GDB_REGNO_PRIV:
                        return "priv";
+               case GDB_REGNO_SATP:
+                       return "satp";
+               case GDB_REGNO_VTYPE:
+                       return "vtype";
+               case GDB_REGNO_VL:
+                       return "vl";
+               case GDB_REGNO_V0:
+                       return "v0";
+               case GDB_REGNO_V1:
+                       return "v1";
+               case GDB_REGNO_V2:
+                       return "v2";
+               case GDB_REGNO_V3:
+                       return "v3";
+               case GDB_REGNO_V4:
+                       return "v4";
+               case GDB_REGNO_V5:
+                       return "v5";
+               case GDB_REGNO_V6:
+                       return "v6";
+               case GDB_REGNO_V7:
+                       return "v7";
+               case GDB_REGNO_V8:
+                       return "v8";
+               case GDB_REGNO_V9:
+                       return "v9";
+               case GDB_REGNO_V10:
+                       return "v10";
+               case GDB_REGNO_V11:
+                       return "v11";
+               case GDB_REGNO_V12:
+                       return "v12";
+               case GDB_REGNO_V13:
+                       return "v13";
+               case GDB_REGNO_V14:
+                       return "v14";
+               case GDB_REGNO_V15:
+                       return "v15";
+               case GDB_REGNO_V16:
+                       return "v16";
+               case GDB_REGNO_V17:
+                       return "v17";
+               case GDB_REGNO_V18:
+                       return "v18";
+               case GDB_REGNO_V19:
+                       return "v19";
+               case GDB_REGNO_V20:
+                       return "v20";
+               case GDB_REGNO_V21:
+                       return "v21";
+               case GDB_REGNO_V22:
+                       return "v22";
+               case GDB_REGNO_V23:
+                       return "v23";
+               case GDB_REGNO_V24:
+                       return "v24";
+               case GDB_REGNO_V25:
+                       return "v25";
+               case GDB_REGNO_V26:
+                       return "v26";
+               case GDB_REGNO_V27:
+                       return "v27";
+               case GDB_REGNO_V28:
+                       return "v28";
+               case GDB_REGNO_V29:
+                       return "v29";
+               case GDB_REGNO_V30:
+                       return "v30";
+               case GDB_REGNO_V31:
+                       return "v31";
                default:
                        if (regno <= GDB_REGNO_XPR31)
                                sprintf(buf, "x%d", regno - GDB_REGNO_ZERO);
@@ -2416,20 +3529,29 @@ static int register_get(struct reg *reg)
 {
        riscv_reg_info_t *reg_info = reg->arch_info;
        struct target *target = reg_info->target;
-       uint64_t value;
-       int result = riscv_get_register(target, &value, reg->number);
-       if (result != ERROR_OK)
-               return result;
-       buf_set_u64(reg->value, 0, reg->size, value);
-       /* CSRs (and possibly other extension) registers may change value at any
-        * time. */
-       if (reg->number <= GDB_REGNO_XPR31 ||
-                       (reg->number >= GDB_REGNO_FPR0 && reg->number <= GDB_REGNO_FPR31) ||
-                       reg->number == GDB_REGNO_PC)
-               reg->valid = true;
-       LOG_DEBUG("[%d]{%d} read 0x%" PRIx64 " from %s (valid=%d)",
-                       target->coreid, riscv_current_hartid(target), value, reg->name,
-                       reg->valid);
+       RISCV_INFO(r);
+
+       if (reg->number >= GDB_REGNO_V0 && reg->number <= GDB_REGNO_V31) {
+               if (!r->get_register_buf) {
+                       LOG_ERROR("Reading register %s not supported on this RISC-V target.",
+                                       gdb_regno_name(reg->number));
+                       return ERROR_FAIL;
+               }
+
+               if (r->get_register_buf(target, reg->value, reg->number) != ERROR_OK)
+                       return ERROR_FAIL;
+       } else {
+               uint64_t value;
+               int result = riscv_get_register(target, &value, reg->number);
+               if (result != ERROR_OK)
+                       return result;
+               buf_set_u64(reg->value, 0, reg->size, value);
+       }
+       reg->valid = gdb_regno_cacheable(reg->number, false);
+       char *str = buf_to_hex_str(reg->value, reg->size);
+       LOG_DEBUG("[%d]{%d} read 0x%s from %s (valid=%d)", target->coreid,
+                       riscv_current_hartid(target), str, reg->name, reg->valid);
+       free(str);
        return ERROR_OK;
 }
 
@@ -2437,22 +3559,42 @@ static int register_set(struct reg *reg, uint8_t *buf)
 {
        riscv_reg_info_t *reg_info = reg->arch_info;
        struct target *target = reg_info->target;
+       RISCV_INFO(r);
+
+       char *str = buf_to_hex_str(buf, reg->size);
+       LOG_DEBUG("[%d]{%d} write 0x%s to %s (valid=%d)", target->coreid,
+                       riscv_current_hartid(target), str, reg->name, reg->valid);
+       free(str);
+
+       memcpy(reg->value, buf, DIV_ROUND_UP(reg->size, 8));
+       reg->valid = gdb_regno_cacheable(reg->number, true);
+
+       if (reg->number == GDB_REGNO_TDATA1 ||
+                       reg->number == GDB_REGNO_TDATA2) {
+               r->manual_hwbp_set = true;
+               /* When enumerating triggers, we clear any triggers with DMODE set,
+                * assuming they were left over from a previous debug session. So make
+                * sure that is done before a user might be setting their own triggers.
+                */
+               if (riscv_enumerate_triggers(target) != ERROR_OK)
+                       return ERROR_FAIL;
+       }
+
+       if (reg->number >= GDB_REGNO_V0 && reg->number <= GDB_REGNO_V31) {
+               if (!r->set_register_buf) {
+                       LOG_ERROR("Writing register %s not supported on this RISC-V target.",
+                                       gdb_regno_name(reg->number));
+                       return ERROR_FAIL;
+               }
+
+               if (r->set_register_buf(target, reg->number, reg->value) != ERROR_OK)
+                       return ERROR_FAIL;
+       } else {
+               uint64_t value = buf_get_u64(buf, 0, reg->size);
+               if (riscv_set_register(target, reg->number, value) != ERROR_OK)
+                       return ERROR_FAIL;
+       }
 
-       uint64_t value = buf_get_u64(buf, 0, reg->size);
-
-       LOG_DEBUG("[%d]{%d} write 0x%" PRIx64 " to %s (valid=%d)",
-                       target->coreid, riscv_current_hartid(target), value, reg->name,
-                       reg->valid);
-       struct reg *r = &target->reg_cache->reg_list[reg->number];
-       /* CSRs (and possibly other extension) registers may change value at any
-        * time. */
-       if (reg->number <= GDB_REGNO_XPR31 ||
-                       (reg->number >= GDB_REGNO_FPR0 && reg->number <= GDB_REGNO_FPR31) ||
-                       reg->number == GDB_REGNO_PC)
-               r->valid = true;
-       memcpy(r->value, buf, (r->size + 7) / 8);
-
-       riscv_set_register(target, reg->number, value);
        return ERROR_OK;
 }
 
@@ -2478,6 +3620,8 @@ int riscv_init_registers(struct target *target)
        riscv_free_registers(target);
 
        target->reg_cache = calloc(1, sizeof(*target->reg_cache));
+       if (!target->reg_cache)
+               return ERROR_FAIL;
        target->reg_cache->name = "RISC-V Registers";
        target->reg_cache->num_regs = GDB_REGNO_COUNT;
 
@@ -2495,14 +3639,19 @@ int riscv_init_registers(struct target *target)
 
        target->reg_cache->reg_list =
                calloc(target->reg_cache->num_regs, sizeof(struct reg));
+       if (!target->reg_cache->reg_list)
+               return ERROR_FAIL;
 
        const unsigned int max_reg_name_len = 12;
-       if (info->reg_names)
-               free(info->reg_names);
+       free(info->reg_names);
        info->reg_names =
                calloc(target->reg_cache->num_regs, max_reg_name_len);
+       if (!info->reg_names)
+               return ERROR_FAIL;
        char *reg_name = info->reg_names;
 
+       int hartid = riscv_current_hartid(target);
+
        static struct reg_feature feature_cpu = {
                .name = "org.gnu.gdb.riscv.cpu"
        };
@@ -2512,6 +3661,9 @@ int riscv_init_registers(struct target *target)
        static struct reg_feature feature_csr = {
                .name = "org.gnu.gdb.riscv.csr"
        };
+       static struct reg_feature feature_vector = {
+               .name = "org.gnu.gdb.riscv.vector"
+       };
        static struct reg_feature feature_virtual = {
                .name = "org.gnu.gdb.riscv.virtual"
        };
@@ -2519,27 +3671,132 @@ int riscv_init_registers(struct target *target)
                .name = "org.gnu.gdb.riscv.custom"
        };
 
-       static struct reg_data_type type_ieee_single = {
-               .type = REG_TYPE_IEEE_SINGLE,
-               .id = "ieee_single"
+       /* These types are built into gdb. */
+       static struct reg_data_type type_ieee_single = { .type = REG_TYPE_IEEE_SINGLE, .id = "ieee_single" };
+       static struct reg_data_type type_ieee_double = { .type = REG_TYPE_IEEE_DOUBLE, .id = "ieee_double" };
+       static struct reg_data_type_union_field single_double_fields[] = {
+               {"float", &type_ieee_single, single_double_fields + 1},
+               {"double", &type_ieee_double, NULL},
+       };
+       static struct reg_data_type_union single_double_union = {
+               .fields = single_double_fields
        };
-       static struct reg_data_type type_ieee_double = {
-               .type = REG_TYPE_IEEE_DOUBLE,
-               .id = "ieee_double"
+       static struct reg_data_type type_ieee_single_double = {
+               .type = REG_TYPE_ARCH_DEFINED,
+               .id = "FPU_FD",
+               .type_class = REG_TYPE_CLASS_UNION,
+               .reg_type_union = &single_double_union
        };
+       static struct reg_data_type type_uint8 = { .type = REG_TYPE_UINT8, .id = "uint8" };
+       static struct reg_data_type type_uint16 = { .type = REG_TYPE_UINT16, .id = "uint16" };
+       static struct reg_data_type type_uint32 = { .type = REG_TYPE_UINT32, .id = "uint32" };
+       static struct reg_data_type type_uint64 = { .type = REG_TYPE_UINT64, .id = "uint64" };
+       static struct reg_data_type type_uint128 = { .type = REG_TYPE_UINT128, .id = "uint128" };
+
+       /* This is roughly the XML we want:
+        * <vector id="bytes" type="uint8" count="16"/>
+        * <vector id="shorts" type="uint16" count="8"/>
+        * <vector id="words" type="uint32" count="4"/>
+        * <vector id="longs" type="uint64" count="2"/>
+        * <vector id="quads" type="uint128" count="1"/>
+        * <union id="riscv_vector_type">
+        *   <field name="b" type="bytes"/>
+        *   <field name="s" type="shorts"/>
+        *   <field name="w" type="words"/>
+        *   <field name="l" type="longs"/>
+        *   <field name="q" type="quads"/>
+        * </union>
+        */
+
+       info->vector_uint8.type = &type_uint8;
+       info->vector_uint8.count = info->vlenb[hartid];
+       info->type_uint8_vector.type = REG_TYPE_ARCH_DEFINED;
+       info->type_uint8_vector.id = "bytes";
+       info->type_uint8_vector.type_class = REG_TYPE_CLASS_VECTOR;
+       info->type_uint8_vector.reg_type_vector = &info->vector_uint8;
+
+       info->vector_uint16.type = &type_uint16;
+       info->vector_uint16.count = info->vlenb[hartid] / 2;
+       info->type_uint16_vector.type = REG_TYPE_ARCH_DEFINED;
+       info->type_uint16_vector.id = "shorts";
+       info->type_uint16_vector.type_class = REG_TYPE_CLASS_VECTOR;
+       info->type_uint16_vector.reg_type_vector = &info->vector_uint16;
+
+       info->vector_uint32.type = &type_uint32;
+       info->vector_uint32.count = info->vlenb[hartid] / 4;
+       info->type_uint32_vector.type = REG_TYPE_ARCH_DEFINED;
+       info->type_uint32_vector.id = "words";
+       info->type_uint32_vector.type_class = REG_TYPE_CLASS_VECTOR;
+       info->type_uint32_vector.reg_type_vector = &info->vector_uint32;
+
+       info->vector_uint64.type = &type_uint64;
+       info->vector_uint64.count = info->vlenb[hartid] / 8;
+       info->type_uint64_vector.type = REG_TYPE_ARCH_DEFINED;
+       info->type_uint64_vector.id = "longs";
+       info->type_uint64_vector.type_class = REG_TYPE_CLASS_VECTOR;
+       info->type_uint64_vector.reg_type_vector = &info->vector_uint64;
+
+       info->vector_uint128.type = &type_uint128;
+       info->vector_uint128.count = info->vlenb[hartid] / 16;
+       info->type_uint128_vector.type = REG_TYPE_ARCH_DEFINED;
+       info->type_uint128_vector.id = "quads";
+       info->type_uint128_vector.type_class = REG_TYPE_CLASS_VECTOR;
+       info->type_uint128_vector.reg_type_vector = &info->vector_uint128;
+
+       info->vector_fields[0].name = "b";
+       info->vector_fields[0].type = &info->type_uint8_vector;
+       if (info->vlenb[hartid] >= 2) {
+               info->vector_fields[0].next = info->vector_fields + 1;
+               info->vector_fields[1].name = "s";
+               info->vector_fields[1].type = &info->type_uint16_vector;
+       } else {
+               info->vector_fields[0].next = NULL;
+       }
+       if (info->vlenb[hartid] >= 4) {
+               info->vector_fields[1].next = info->vector_fields + 2;
+               info->vector_fields[2].name = "w";
+               info->vector_fields[2].type = &info->type_uint32_vector;
+       } else {
+               info->vector_fields[1].next = NULL;
+       }
+       if (info->vlenb[hartid] >= 8) {
+               info->vector_fields[2].next = info->vector_fields + 3;
+               info->vector_fields[3].name = "l";
+               info->vector_fields[3].type = &info->type_uint64_vector;
+       } else {
+               info->vector_fields[2].next = NULL;
+       }
+       if (info->vlenb[hartid] >= 16) {
+               info->vector_fields[3].next = info->vector_fields + 4;
+               info->vector_fields[4].name = "q";
+               info->vector_fields[4].type = &info->type_uint128_vector;
+       } else {
+               info->vector_fields[3].next = NULL;
+       }
+       info->vector_fields[4].next = NULL;
+
+       info->vector_union.fields = info->vector_fields;
+
+       info->type_vector.type = REG_TYPE_ARCH_DEFINED;
+       info->type_vector.id = "riscv_vector";
+       info->type_vector.type_class = REG_TYPE_CLASS_UNION;
+       info->type_vector.reg_type_union = &info->vector_union;
+
        struct csr_info csr_info[] = {
 #define DECLARE_CSR(name, number) { number, #name },
 #include "encoding.h"
 #undef DECLARE_CSR
        };
        /* encoding.h does not contain the registers in sorted order. */
-       qsort(csr_info, DIM(csr_info), sizeof(*csr_info), cmp_csr_info);
+       qsort(csr_info, ARRAY_SIZE(csr_info), sizeof(*csr_info), cmp_csr_info);
        unsigned csr_info_index = 0;
 
        unsigned custom_range_index = 0;
        int custom_within_range = 0;
 
        riscv_reg_info_t *shared_reg_info = calloc(1, sizeof(riscv_reg_info_t));
+       if (!shared_reg_info)
+               return ERROR_FAIL;
        shared_reg_info->target = target;
 
        /* When gdb requests register N, gdb_get_register_packet() assumes that this
@@ -2560,6 +3817,11 @@ int riscv_init_registers(struct target *target)
                 * target is in theory allowed to change XLEN on us. But I expect a lot
                 * of other things to break in that case as well. */
                if (number <= GDB_REGNO_XPR31) {
+                       r->exist = number <= GDB_REGNO_XPR15 ||
+                               !riscv_supports_extension(target, hartid, 'E');
+                       /* TODO: For now we fake that all GPRs exist because otherwise gdb
+                        * doesn't work. */
+                       r->exist = true;
                        r->caller_save = true;
                        switch (number) {
                                case GDB_REGNO_ZERO:
@@ -2668,12 +3930,13 @@ int riscv_init_registers(struct target *target)
                        r->feature = &feature_cpu;
                } else if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) {
                        r->caller_save = true;
-                       if (riscv_supports_extension(target, riscv_current_hartid(target),
-                                               'D')) {
-                               r->reg_data_type = &type_ieee_double;
+                       if (riscv_supports_extension(target, hartid, 'D')) {
                                r->size = 64;
-                       } else if (riscv_supports_extension(target,
-                                               riscv_current_hartid(target), 'F')) {
+                               if (riscv_supports_extension(target, hartid, 'F'))
+                                       r->reg_data_type = &type_ieee_single_double;
+                               else
+                                       r->reg_data_type = &type_ieee_double;
+                       } else if (riscv_supports_extension(target, hartid, 'F')) {
                                r->reg_data_type = &type_ieee_single;
                                r->size = 32;
                        } else {
@@ -2785,7 +4048,7 @@ int riscv_init_registers(struct target *target)
                        unsigned csr_number = number - GDB_REGNO_CSR0;
 
                        while (csr_info[csr_info_index].number < csr_number &&
-                                       csr_info_index < DIM(csr_info) - 1) {
+                                       csr_info_index < ARRAY_SIZE(csr_info) - 1) {
                                csr_info_index++;
                        }
                        if (csr_info[csr_info_index].number == csr_number) {
@@ -2804,8 +4067,7 @@ int riscv_init_registers(struct target *target)
                                case CSR_FFLAGS:
                                case CSR_FRM:
                                case CSR_FCSR:
-                                       r->exist = riscv_supports_extension(target,
-                                                       riscv_current_hartid(target), 'F');
+                                       r->exist = riscv_supports_extension(target, hartid, 'F');
                                        r->group = "float";
                                        r->feature = &feature_fpu;
                                        break;
@@ -2819,18 +4081,19 @@ int riscv_init_registers(struct target *target)
                                case CSR_SCAUSE:
                                case CSR_STVAL:
                                case CSR_SATP:
-                                       r->exist = riscv_supports_extension(target,
-                                                       riscv_current_hartid(target), 'S');
+                                       r->exist = riscv_supports_extension(target, hartid, 'S');
                                        break;
                                case CSR_MEDELEG:
                                case CSR_MIDELEG:
                                        /* "In systems with only M-mode, or with both M-mode and
                                         * U-mode but without U-mode trap support, the medeleg and
                                         * mideleg registers should not exist." */
-                                       r->exist = riscv_supports_extension(target, riscv_current_hartid(target), 'S') ||
-                                               riscv_supports_extension(target, riscv_current_hartid(target), 'N');
+                                       r->exist = riscv_supports_extension(target, hartid, 'S') ||
+                                               riscv_supports_extension(target, hartid, 'N');
                                        break;
 
+                               case CSR_PMPCFG1:
+                               case CSR_PMPCFG3:
                                case CSR_CYCLEH:
                                case CSR_TIMEH:
                                case CSR_INSTRETH:
@@ -2896,6 +4159,15 @@ int riscv_init_registers(struct target *target)
                                case CSR_MHPMCOUNTER31H:
                                        r->exist = riscv_xlen(target) == 32;
                                        break;
+
+                               case CSR_VSTART:
+                               case CSR_VXSAT:
+                               case CSR_VXRM:
+                               case CSR_VL:
+                               case CSR_VTYPE:
+                               case CSR_VLENB:
+                                       r->exist = riscv_supports_extension(target, hartid, 'V');
+                                       break;
                        }
 
                        if (!r->exist && expose_csr) {
@@ -2914,7 +4186,16 @@ int riscv_init_registers(struct target *target)
                        r->feature = &feature_virtual;
                        r->size = 8;
 
-               } else {
+               } else if (number >= GDB_REGNO_V0 && number <= GDB_REGNO_V31) {
+                       r->caller_save = false;
+                       r->exist = riscv_supports_extension(target, hartid, 'V') && info->vlenb[hartid];
+                       r->size = info->vlenb[hartid] * 8;
+                       sprintf(reg_name, "v%d", number - GDB_REGNO_V0);
+                       r->group = "vector";
+                       r->feature = &feature_vector;
+                       r->reg_data_type = &info->type_vector;
+
+               } else if (number >= GDB_REGNO_COUNT) {
                        /* Custom registers. */
                        assert(expose_custom);
 
@@ -2925,7 +4206,8 @@ int riscv_init_registers(struct target *target)
                        r->group = "custom";
                        r->feature = &feature_custom;
                        r->arch_info = calloc(1, sizeof(riscv_reg_info_t));
-                       assert(r->arch_info);
+                       if (!r->arch_info)
+                               return ERROR_FAIL;
                        ((riscv_reg_info_t *) r->arch_info)->target = target;
                        ((riscv_reg_info_t *) r->arch_info)->custom_number = custom_number;
                        sprintf(reg_name, "custom%d", custom_number);
@@ -2942,8 +4224,48 @@ int riscv_init_registers(struct target *target)
                reg_name += strlen(reg_name) + 1;
                assert(reg_name < info->reg_names + target->reg_cache->num_regs *
                                max_reg_name_len);
-               r->value = &info->reg_cache_values[number];
+               r->value = info->reg_cache_values[number];
        }
 
        return ERROR_OK;
 }
+
+
+void riscv_add_bscan_tunneled_scan(struct target *target, struct scan_field *field,
+                                       riscv_bscan_tunneled_scan_context_t *ctxt)
+{
+       jtag_add_ir_scan(target->tap, &select_user4, TAP_IDLE);
+
+       memset(ctxt->tunneled_dr, 0, sizeof(ctxt->tunneled_dr));
+       if (bscan_tunnel_type == BSCAN_TUNNEL_DATA_REGISTER) {
+               ctxt->tunneled_dr[3].num_bits = 1;
+               ctxt->tunneled_dr[3].out_value = bscan_one;
+               ctxt->tunneled_dr[2].num_bits = 7;
+               ctxt->tunneled_dr_width = field->num_bits;
+               ctxt->tunneled_dr[2].out_value = &ctxt->tunneled_dr_width;
+               /* for BSCAN tunnel, there is a one-TCK skew between shift in and shift out, so
+                  scanning num_bits + 1, and then will right shift the input field after executing the queues */
+
+               ctxt->tunneled_dr[1].num_bits = field->num_bits + 1;
+               ctxt->tunneled_dr[1].out_value = field->out_value;
+               ctxt->tunneled_dr[1].in_value = field->in_value;
+
+               ctxt->tunneled_dr[0].num_bits = 3;
+               ctxt->tunneled_dr[0].out_value = bscan_zero;
+       } else {
+               /* BSCAN_TUNNEL_NESTED_TAP */
+               ctxt->tunneled_dr[0].num_bits = 1;
+               ctxt->tunneled_dr[0].out_value = bscan_one;
+               ctxt->tunneled_dr[1].num_bits = 7;
+               ctxt->tunneled_dr_width = field->num_bits;
+               ctxt->tunneled_dr[1].out_value = &ctxt->tunneled_dr_width;
+               /* for BSCAN tunnel, there is a one-TCK skew between shift in and shift out, so
+                  scanning num_bits + 1, and then will right shift the input field after executing the queues */
+               ctxt->tunneled_dr[2].num_bits = field->num_bits + 1;
+               ctxt->tunneled_dr[2].out_value = field->out_value;
+               ctxt->tunneled_dr[2].in_value = field->in_value;
+               ctxt->tunneled_dr[3].num_bits = 3;
+               ctxt->tunneled_dr[3].out_value = bscan_zero;
+       }
+       jtag_add_dr_scan(target->tap, ARRAY_SIZE(ctxt->tunneled_dr), ctxt->tunneled_dr, TAP_IDLE);
+}

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)