This is an automated email from Gerrit.

"Bjorn Schouteten <b_schoute...@hotmail.com>" just uploaded a new patch set to 
Gerrit, which you can find at https://review.openocd.org/c/openocd/+/7176

-- gerrit

commit 8e5f4c3b9150d63538bd0cf0ddee78f19cd26319
Author: Bjorn Schouteten <b_schoute...@hotmail.com>
Date:   Mon Aug 29 19:27:36 2022 +0200

    target/roalogic: Add roalogic RV12 support
    
    Added support for the RV12 processor of RoaLogic. The RV12 is a highly 
configurable single-issue, single-core RV32I, RV64I compliant RISC CPU intended 
for the embedded market. The debugging interface is based on advance debug 
interface from OpenCores.
    
    Change-Id: Id8bc599ae20b9574b0deb3ddb24352636bc076f2
    Signed-off-by: Bjorn Schouteten <b_schoute...@hotmail.com>

diff --git a/doc/openocd.texi b/doc/openocd.texi
index 0df25406ff..4d0a179e63 100644
--- a/doc/openocd.texi
+++ b/doc/openocd.texi
@@ -4902,6 +4902,7 @@ And two debug interfaces cores:
 @item @code{quark_d20xx} -- an Intel Quark D20xx core.
 @item @code{quark_x10xx} -- an Intel Quark X10xx core.
 @item @code{riscv} -- a RISC-V core.
+@item @code{rv12} -- Roa Logic RV12 processor, based on RISC-V.
 @item @code{stm8} -- implements an STM8 core.
 @item @code{testee} -- a dummy target for cases without a real CPU, e.g. CPLD.
 @item @code{xscale} -- this is actually an architecture,
@@ -10928,6 +10929,35 @@ This command is similar to @command{arc jtag 
get-aux-reg} but is for core
 registers.
 @end deffn
 
+@section RoaLogic RV12
+@uref{https://roalogic.com/, RV12} is a highly configurable single-issue,
+single-core RV32IMC, RV64IMC compliant RISC CPU intended for the embedded 
market.
+
+@deffn {Command} {rl_tap_list}
+Print the possible taps.
+@end deffn
+@deffn {Command} {rl_tap_select} (@option{rl_universal_tap})
+Select rl_universal_tap (RoaLogic Universal tap)
+@end deffn
+@deffn {Command} {rl_du_list}
+Print the possible debug units.
+@end deffn
+@deffn {Command} {rl_du_select} (@option{adv}) [option]
+Select Advanced Debug Interface .
+
+An option can be passed as a second argument to the debug unit.
+
+When using the Advanced Debug Interface, option = 1 means the RTL core is
+configured with ADBG_USE_HISPEED = 1. This configuration skips status checking
+between bytes while doing read or write bursts.
+@end deffn
+
+@deffn {Command} {rv12_test} [option]
+Test the RV12 debug interface.
+Bit 1: Test the read and write memroy commands into the SRAM.
+Bit 2: Test CPU debug interface, context save, single stepping and breakpoint 
hit.
+@end deffn
+
 @section STM8 Architecture
 @uref{http://st.com/stm8/, STM8} is a 8-bit microcontroller platform from
 STMicroelectronics, based on a proprietary 8-bit core architecture.
diff --git a/src/target/Makefile.am b/src/target/Makefile.am
index 46870922af..3f566466e0 100644
--- a/src/target/Makefile.am
+++ b/src/target/Makefile.am
@@ -3,7 +3,8 @@
 %C%_libtarget_la_LIBADD = %D%/openrisc/libopenrisc.la \
        %D%/riscv/libriscv.la \
        %D%/xtensa/libxtensa.la \
-       %D%/espressif/libespressif.la
+       %D%/espressif/libespressif.la \
+       %D%/roalogic/libroalogic.la
 
 %C%_libtarget_la_CPPFLAGS = $(AM_CPPFLAGS)
 
@@ -265,4 +266,5 @@ ARC_SRC = \
 include %D%/openrisc/Makefile.am
 include %D%/riscv/Makefile.am
 include %D%/xtensa/Makefile.am
-include %D%/espressif/Makefile.am
\ No newline at end of file
+include %D%/espressif/Makefile.am
+include %D%/roalogic/Makefile.am
\ No newline at end of file
diff --git a/src/target/roalogic/Makefile.am b/src/target/roalogic/Makefile.am
new file mode 100644
index 0000000000..9eeabf832b
--- /dev/null
+++ b/src/target/roalogic/Makefile.am
@@ -0,0 +1,7 @@
+noinst_LTLIBRARIES += %D%/libroalogic.la
+%C%_libroalogic_la_SOURCES = \
+       %D%/rv12.c \
+       %D%/rl_dbg_adv.c \
+       %D%/rl_universal_tap.c \
+       %D%/rv12.h \
+       %D%/rl_dbg_adv.h
diff --git a/src/target/roalogic/rl_dbg_adv.c b/src/target/roalogic/rl_dbg_adv.c
new file mode 100644
index 0000000000..8a6a4d4d3e
--- /dev/null
+++ b/src/target/roalogic/rl_dbg_adv.c
@@ -0,0 +1,1142 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/***************************************************************************
+ *   Copyright (C) 2022 by Richard Herveille                               *
+ *   richard.hervei...@roalogic.com                                        *
+ *                                                                         *
+ *   Copyright (C) 2022 by Bjorn Schouteten                                *
+ *   bjorn.schoute...@roalogic.com                                         *
+ *                                                                         *
+ *   Based on OR1K version                                                 *
+ *                                                                         *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "rl_tap.h"
+#include "rv12.h"
+#include "rl_dbg_adv.h"
+/*#include "jsp_server.h"*/
+
+#include <target/target.h>
+#include <jtag/jtag.h>
+
+#define JSP_BANNER "\n\r" \
+                  "******************************\n\r" \
+                  "**     JTAG Serial Port     **\n\r" \
+                  "******************************\n\r" \
+                  "\n\r"
+
+#define NO_OPTION                      0
+
+/* This an option to the adv debug unit.
+ * If this is defined, status bits will be skipped on burst
+ * reads and writes to improve download speeds.
+ * This option must match the RTL configured option.
+ */
+#define USE_HISPEED                    1
+
+
+/* This an option to the adv debug unit.
+ * If this is defined, the JTAG Serial Port Server is started.
+ * This option must match the RTL configured option.
+ */
+#define ENABLE_JSP_SERVER              2
+
+
+/* Define this if you intend to use the JSP in a system with multiple
+ * devices on the JTAG chain
+ */
+#define ENABLE_JSP_MULTI               4
+
+
+/* Definitions for the top-level debug unit.  This really just consists
+ * of a single register, used to select the active debug module ("chain").
+ */
+#define DBG_MODULE_SELECT_REG_SIZE     2
+#define DBG_MAX_MODULES                        4
+
+#define DC_NONE                                -1
+#define DC_SYSBUS                      0
+#define DC_CPU                         1
+#define DC_JSP                         2
+
+
+/* CPU control register bits mask */
+#define DBG_CPU_CR_STALL               0x01
+#define DBG_CPU_CR_RESET               0x02
+
+
+/* Polynomial for the CRC calculation
+ * Yes, it's backwards.  Yes, this is on purpose.
+ * The hardware is designed this way to save on logic and routing,
+ * and it's really all the same to us here.
+ */
+#define ADBG_CRC_POLY                  0xedb88320
+
+
+/* These are for the internal registers in the SystemBus module
+ * The first is the length of the index register,
+ * the indexes of the various registers are defined after that.
+ */
+#define DBG_SYSBUS_REG_SEL_LEN         1
+#define DBG_SYSBUS_REG_ERROR           0
+
+
+/* Opcode definitions for the SystemBus module. */
+#define DBG_SYSBUS_OPCODE_LEN          4
+#define DBG_SYSBUS_CMD_NOP             0x0
+#define DBG_SYSBUS_CMD_BWRITE8         0x1
+#define DBG_SYSBUS_CMD_BWRITE16                0x2
+#define DBG_SYSBUS_CMD_BWRITE32                0x3
+#define DBG_SYSBUS_CMD_BWRITE64                0x4
+#define DBG_SYSBUS_CMD_BREAD8          0x5
+#define DBG_SYSBUS_CMD_BREAD16         0x6
+#define DBG_SYSBUS_CMD_BREAD32         0x7
+#define DBG_SYSBUS_CMD_BREAD64         0x8
+#define DBG_SYSBUS_CMD_IREG_WR         0x9
+#define DBG_SYSBUS_CMD_IREG_SEL                0xd
+
+
+/* Internal register definitions for the CP module. */
+#define DBG_CPU_REG_SEL_LEN            1
+#define DBG_CPU_REG_STATUS             0
+
+
+/* CPU Select */
+#define DBG_CPU_CPUSEL_LEN             4
+
+
+/* Opcode definitions for the CPU module. */
+#define DBG_CPU_OPCODE_LEN             4
+#define DBG_CPU_CMD_NOP                        0x0
+#define DBG_CPU_CMD_BWRITE32           0x3
+#define DBG_CPU_CMD_BREAD32            0x7
+#define DBG_CPU_CMD_IREG_WR            0x9
+#define DBG_CPU_CMD_IREG_SEL           0xd
+
+
+#define MAX_READ_STATUS_WAIT           10
+#define MAX_READ_BUSY_RETRY            2
+#define MAX_READ_CRC_RETRY             2
+#define MAX_WRITE_CRC_RETRY            2
+#define BURST_READ_READY               1
+#define MAX_BUS_ERRORS                 2
+
+#define MAX_BURST_SIZE                 (4 * 1024)
+
+#define STATUS_BYTES                   1
+#define CRC_LEN                                4
+
+static struct rl_du rl_dbg_adv;
+
+static const char * const chain_name[] = {"SYSBUS", "CPU", "JSP"};
+
+static uint32_t adbg_compute_crc(uint32_t crc, uint32_t data_in,
+                               int length_bits)
+{
+       for (int i = 0; i < length_bits; i++) {
+               uint32_t d, c;
+               d = ((data_in >> i) & 0x1) ? 0xffffffff : 0;
+               c = (crc & 0x1) ? 0xffffffff : 0;
+               crc = crc >> 1;
+               crc = crc ^ ((d ^ c) & ADBG_CRC_POLY);
+       }
+
+       return crc;
+}
+
+static int find_status_bit(void *_buf, int len)
+{
+       int i = 0;
+       int count = 0;
+       int ret = -1;
+       uint8_t *buf = _buf;
+
+       while (!(buf[i] & (1 << count++)) && (i < len)) {
+               if (count == 8) {
+                       count = 0;
+                       i++;
+               }
+       }
+
+       if (i < len)
+               ret = (i * 8) + count;
+
+       return ret;
+}
+
+static int rl_adv_jtag_init(struct rl_jtag *jtag_info)
+{
+       struct rl_tap_ip *tap_ip = jtag_info->tap_ip;
+
+       int retval = tap_ip->init(jtag_info);
+       if (retval != ERROR_OK) {
+               LOG_ERROR("TAP initialization failed");
+               return retval;
+       }
+
+       /* TAP is now configured to communicate with debug interface */
+       jtag_info->rl_jtag_inited = 1;
+
+       /* TODO hardcoded HW parameters */
+       jtag_info->rl_jtag_address_size = 32;
+       jtag_info->rl_jtag_cpu_selected = 0;
+
+       /* TAP reset - not sure what state debug module chain is in now */
+       jtag_info->rl_jtag_module_selected = DC_NONE;
+
+       jtag_info->current_reg_idx = malloc(DBG_MAX_MODULES * sizeof(uint8_t));
+       memset(jtag_info->current_reg_idx, 0, DBG_MAX_MODULES * 
sizeof(uint8_t));
+
+       if (rl_dbg_adv.options & USE_HISPEED)
+               LOG_INFO("Roa Logic adv debug unit is configured with option 
USE_HISPEED");
+
+/*     if (rl_dbg_adv.options & ENABLE_JSP_SERVER) {
+               if (rl_dbg_adv.options & ENABLE_JSP_MULTI)
+                       LOG_INFO("Roa Logic adv debug unit is configured with 
option ENABLE_JSP_MULTI");
+               LOG_INFO("Roa Logic adv debug unit is configured with option 
ENABLE_JSP_SERVER");
+               retval = jsp_init(jtag_info, JSP_BANNER);
+               if (retval != ERROR_OK) {
+                       LOG_ERROR("Couldn't start the JSP server");
+                       return retval;
+               }
+       }
+*/
+       LOG_DEBUG("Init done");
+
+       return ERROR_OK;
+
+}
+
+/* Selects one of the modules in the debug unit
+ * (e.g. SYSBUS, CPU, JSP)
+ */
+static int adbg_select_module(struct rl_jtag *jtag_info, int chain)
+{
+       if (jtag_info->rl_jtag_module_selected == chain)
+               return ERROR_OK;
+
+       /* MSB of the data out must be set to 1, indicating a module
+        * select command
+        */
+       uint8_t data = chain | (1 << DBG_MODULE_SELECT_REG_SIZE);
+
+       LOG_DEBUG("Select module: %s", chain_name[chain]);
+
+       struct scan_field field;
+
+       field.num_bits = (DBG_MODULE_SELECT_REG_SIZE + 1);
+       field.out_value = &data;
+       field.in_value = NULL;
+       jtag_add_dr_scan(jtag_info->tap, 1, &field, TAP_IDLE);
+
+       int retval = jtag_execute_queue();
+       if (retval != ERROR_OK)
+               return retval;
+
+       jtag_info->rl_jtag_module_selected = chain;
+
+       return ERROR_OK;
+}
+
+/* Set the index of the desired register in the currently selected module
+ * 1 bit module select command
+ * 4 bits opcode
+ * n bits index
+ */
+static int adbg_select_ctrl_reg(struct rl_jtag *jtag_info, uint8_t regidx)
+{
+       int index_len;
+       uint32_t opcode;
+       uint32_t opcode_len;
+
+       /* If this reg is already selected, don't do a JTAG transaction */
+       if (jtag_info->current_reg_idx[jtag_info->rl_jtag_module_selected] == 
regidx)
+               return ERROR_OK;
+
+       switch (jtag_info->rl_jtag_module_selected) {
+       case DC_SYSBUS:
+               index_len = DBG_SYSBUS_REG_SEL_LEN;
+               opcode = DBG_SYSBUS_CMD_IREG_SEL;
+               opcode_len = DBG_SYSBUS_OPCODE_LEN;
+               break;
+       case DC_CPU:
+               index_len = DBG_CPU_REG_SEL_LEN;
+               opcode = DBG_CPU_CMD_IREG_SEL;
+               opcode_len = DBG_CPU_OPCODE_LEN;
+               break;
+       default:
+               LOG_ERROR("Illegal debug chain selected (%i) while selecting 
control register",
+                         jtag_info->rl_jtag_module_selected);
+               return ERROR_FAIL;
+       }
+
+       /* MSB must be 0 to access modules */
+       uint32_t data = (opcode & ~(1 << opcode_len)) << index_len;
+       data |= regidx;
+
+       struct scan_field field;
+
+       field.num_bits = (opcode_len + 1) + index_len;
+       field.out_value = (uint8_t *)&data;
+       field.in_value = NULL;
+       jtag_add_dr_scan(jtag_info->tap, 1, &field, TAP_IDLE);
+
+       int retval = jtag_execute_queue();
+       if (retval != ERROR_OK)
+               return retval;
+
+       jtag_info->current_reg_idx[jtag_info->rl_jtag_module_selected] = regidx;
+
+       return ERROR_OK;
+}
+
+/* Write control register (internal to the debug unit) */
+static int adbg_ctrl_write(struct rl_jtag *jtag_info, uint8_t regidx,
+                          uint32_t *cmd_data, int length_bits)
+{
+       int index_len;
+       int cpusel_len;
+       int cpusel;
+       uint32_t opcode;
+       uint32_t opcode_len;
+
+       LOG_DEBUG("Write control register %" PRId8 ": 0x%08" PRIx32, regidx, 
cmd_data[0]);
+
+       int retval = adbg_select_ctrl_reg(jtag_info, regidx);
+       if (retval != ERROR_OK) {
+               LOG_ERROR("Error while calling adbg_select_ctrl_reg");
+               return retval;
+       }
+
+       switch (jtag_info->rl_jtag_module_selected) {
+       case DC_SYSBUS:
+               index_len  = DBG_SYSBUS_REG_SEL_LEN;
+               cpusel     = 0;
+               cpusel_len = 0;
+               opcode     = DBG_SYSBUS_CMD_IREG_WR;
+               opcode_len = DBG_SYSBUS_OPCODE_LEN;
+               break;
+       case DC_CPU:
+               index_len  = DBG_CPU_REG_SEL_LEN;
+               cpusel     = jtag_info->rl_jtag_cpu_selected;
+               cpusel_len = DBG_CPU_CPUSEL_LEN;
+               opcode     = DBG_CPU_CMD_IREG_WR;
+               opcode_len = DBG_CPU_OPCODE_LEN;
+               break;
+       default:
+               LOG_ERROR("Illegal debug chain selected (%i) while doing 
control write",
+                         jtag_info->rl_jtag_module_selected);
+               return ERROR_FAIL;
+       }
+
+       struct scan_field field[2];
+
+       /* MSB must be 0 to access modules */
+       uint32_t data = ~(1 << (opcode_len + cpusel_len + index_len));
+       data &= (((opcode << cpusel_len) | cpusel) << index_len);
+       data |= regidx;
+
+       field[0].num_bits  = length_bits;
+       field[0].out_value = (uint8_t *)cmd_data;
+       field[0].in_value  = NULL;
+
+       field[1].num_bits  = 1 + opcode_len + cpusel_len + index_len;
+       field[1].out_value = (uint8_t *)&data;
+       field[1].in_value  = NULL;
+
+       jtag_add_dr_scan(jtag_info->tap, 2, field, TAP_IDLE);
+
+       return jtag_execute_queue();
+}
+
+/* Reads control register (internal to the debug unit) */
+static int adbg_ctrl_read(struct rl_jtag *jtag_info, uint32_t regidx,
+                         uint32_t *data, int length_bits)
+{
+
+       int retval = adbg_select_ctrl_reg(jtag_info, regidx);
+       if (retval != ERROR_OK) {
+               LOG_ERROR("Error while calling adbg_select_ctrl_reg");
+               return retval;
+       }
+
+       int cpusel = 0;
+       int cpusel_len;
+       int opcode_len;
+       uint32_t opcode;
+
+       /* There is no 'read' command, We write a NOP to read */
+       switch (jtag_info->rl_jtag_module_selected) {
+       case DC_SYSBUS:
+               cpusel_len = 0;
+               opcode     = DBG_SYSBUS_CMD_NOP;
+               opcode_len = DBG_SYSBUS_OPCODE_LEN;
+               break;
+       case DC_CPU:
+               cpusel     = jtag_info->rl_jtag_cpu_selected;
+               cpusel_len = DBG_CPU_CPUSEL_LEN;
+               opcode     = DBG_CPU_CMD_NOP;
+               opcode_len = DBG_CPU_OPCODE_LEN;
+               break;
+       default:
+               LOG_ERROR("Illegal debug chain selected (%i) while doing 
control read",
+                         jtag_info->rl_jtag_module_selected);
+               return ERROR_FAIL;
+       }
+
+       /* Zero MSB = op for module, not top-level debug unit */
+       uint32_t outdata = ~(1 << (opcode_len + cpusel_len));
+       outdata &= (opcode << cpusel_len) | cpusel;
+
+       struct scan_field field[2];
+
+       field[0].num_bits  = length_bits;
+       field[0].out_value = NULL;
+       field[0].in_value  = (uint8_t *)data;
+
+       field[1].num_bits  = opcode_len + cpusel_len + 1;
+       field[1].out_value = (uint8_t *)&outdata;
+       field[1].in_value  = NULL;
+
+       jtag_add_dr_scan(jtag_info->tap, 2, field, TAP_IDLE);
+
+       return jtag_execute_queue();
+}
+
+/* sends out a burst command to the selected module in the debug unit (MSB to 
LSB):
+ * 1-bit module command
+ * 4-bit opcode
+ * 4-bit CPU (optional)
+ * 32/64-bit address
+ * 16-bit length (of the burst, in words)
+ */
+static int adbg_burst_command(struct rl_jtag *jtag_info,
+                             uint32_t opcode, uint8_t opcode_len,
+                             uint64_t address, uint8_t address_len,
+                             uint32_t cpusel, uint8_t cpusel_len,
+                             uint16_t length_words)
+{
+       uint32_t bitcount;
+       uint32_t data[3];
+
+       /* Total bitcount */
+       bitcount  = 1;            /* 1bit module command */
+       bitcount += opcode_len;   /* 4bit opcode */
+       bitcount += cpusel_len;   /* 4bit CPU select */
+       bitcount += address_len;  /* Address */
+       bitcount += 16;           /* Burst Length */
+
+       /* Set up the data */
+       switch (address_len) {
+       case 32:
+               data[0] = (address << 16) | length_words;
+               data[1] = opcode;
+               if (cpusel_len)
+                       data[1] = (data[1] << cpusel_len) | cpusel;
+
+               data[1] = (data[1] << 16) | (address >> 16);
+
+               /* MSB must be 0 to access modules */
+               data[1] &= ~(1 << (16 + cpusel_len + opcode_len));
+               break;
+       case 64:
+               data[0] = (address << 16) | length_words;
+               data[1] = address >> 16;
+               data[2] = opcode;
+               if (cpusel_len)
+                       data[2] = (data[2] << cpusel_len) | cpusel;
+
+               data[2] = (data[2] << 16) | (address >> 48);
+               data[2] &= ~(1 << (16 + cpusel_len + opcode_len));
+               break;
+       default:
+               LOG_ERROR("Unsupported address-length (%i)", address_len);
+               return ERROR_FAIL;
+       }
+
+       struct scan_field field;
+
+       field.num_bits  = bitcount;
+       field.out_value = (uint8_t *)&data[0];
+       field.in_value  = NULL;
+
+       jtag_add_dr_scan(jtag_info->tap, 1, &field, TAP_IDLE);
+
+       return jtag_execute_queue();
+}
+
+static int adbg_sysbus_burst_read(struct rl_jtag *jtag_info, int size,
+                                       int count, uint32_t start_address, 
uint8_t *data)
+{
+       int retry_full_crc = 0;
+       int retry_full_busy = 0;
+       int retval;
+
+       uint8_t opcode;
+       uint8_t opcode_len;
+       uint8_t cpusel = 0;
+       uint8_t cpusel_len;
+       uint8_t address_len;
+
+       LOG_DEBUG("Doing burst read, word size %d, word count %d, start address 
0x%08" PRIx32,
+                 size, count, start_address);
+
+       /* Select the appropriate opcode */
+       switch (jtag_info->rl_jtag_module_selected) {
+       case DC_SYSBUS:
+               if (size == 1)
+                       opcode = DBG_SYSBUS_CMD_BREAD8;
+               else if (size == 2)
+                       opcode = DBG_SYSBUS_CMD_BREAD16;
+               else if (size == 4)
+                       opcode = DBG_SYSBUS_CMD_BREAD32;
+               else if (size == 8)
+                       opcode = DBG_SYSBUS_CMD_BREAD64;
+               else {
+                       LOG_WARNING("Tried burst read with invalid word size 
(%d),"
+                                 "defaulting to 4-byte words", size);
+                       opcode = DBG_SYSBUS_CMD_BREAD32;
+               }
+               opcode_len = DBG_SYSBUS_OPCODE_LEN;
+               cpusel_len = 0;
+               break;
+       case DC_CPU:
+               if (size == 4)
+                       opcode = DBG_CPU_CMD_BREAD32;
+               else {
+                       LOG_WARNING("Tried burst read with invalid word size 
(%d),"
+                                 "defaulting to 4-byte words", size);
+                       opcode = DBG_CPU_CMD_BREAD32;
+               }
+               opcode_len = DBG_CPU_OPCODE_LEN;
+               cpusel     = jtag_info->rl_jtag_cpu_selected;
+               cpusel_len = DBG_CPU_CPUSEL_LEN;
+               break;
+       default:
+               LOG_ERROR("Illegal debug chain selected (%i) while doing burst 
read",
+                         jtag_info->rl_jtag_module_selected);
+               return ERROR_FAIL;
+       }
+       address_len = jtag_info->rl_jtag_address_size;
+
+
+       int total_size_bytes = count * size;
+       struct scan_field field;
+       uint8_t *in_buffer = malloc(total_size_bytes + CRC_LEN + STATUS_BYTES);
+
+retry_read_full:
+
+       /* Send the BURST READ command, returns TAP to idle state */
+       retval = adbg_burst_command(jtag_info, opcode, opcode_len,
+                                       start_address, address_len, cpusel, 
cpusel_len, count);
+
+       if (retval != ERROR_OK)
+               goto out;
+
+       field.num_bits = (total_size_bytes + CRC_LEN + STATUS_BYTES) * 8;
+       field.out_value = NULL;
+       field.in_value = in_buffer;
+
+       jtag_add_dr_scan(jtag_info->tap, 1, &field, TAP_IDLE);
+
+       retval = jtag_execute_queue();
+       if (retval != ERROR_OK)
+               goto out;
+
+       /* Look for the start bit in the first (STATUS_BYTES * 8) bits */
+       int shift = find_status_bit(in_buffer, STATUS_BYTES);
+
+       /* We expect the status bit to be in the first byte */
+       if (shift < 0) {
+               if (retry_full_busy++ < MAX_READ_BUSY_RETRY) {
+                       LOG_WARNING("Burst read timed out");
+                       goto retry_read_full;
+               } else {
+                       LOG_ERROR("Burst read failed");
+                       retval = ERROR_FAIL;
+                       goto out;
+               }
+       }
+
+       buffer_shr(in_buffer, total_size_bytes + CRC_LEN + STATUS_BYTES, shift);
+
+       uint32_t crc_read;
+       memcpy(data, in_buffer, total_size_bytes);
+       memcpy(&crc_read, &in_buffer[total_size_bytes], 4);
+
+       uint32_t crc_calc = 0xffffffff;
+       for (int i = 0; i < total_size_bytes; i++)
+               crc_calc = adbg_compute_crc(crc_calc, data[i], 8);
+
+       if (crc_calc != crc_read) {
+               LOG_WARNING("CRC ERROR! Computed 0x%08" PRIx32 ", read CRC 
0x%08" PRIx32, crc_calc, crc_read);
+               if (retry_full_crc++ < MAX_READ_CRC_RETRY)
+                       goto retry_read_full;
+               else {
+                       LOG_ERROR("Burst read failed");
+                       retval = ERROR_FAIL;
+                       goto out;
+               }
+       } else
+               LOG_DEBUG("CRC OK!");
+
+       /* Now, read the error register, and retry/recompute as necessary */
+       if (jtag_info->rl_jtag_module_selected == DC_SYSBUS &&
+           !(rl_dbg_adv.options & USE_HISPEED)) {
+
+               uint32_t err_data[2] = {0, 0};
+               uint32_t addr;
+               int bus_error_retries = 0;
+
+               /* First, just get 1 bit...read address only if necessary */
+               retval = adbg_ctrl_read(jtag_info, DBG_SYSBUS_REG_ERROR, 
err_data, 1);
+               if (retval != ERROR_OK)
+                       goto out;
+
+               /* Then we have a problem */
+               if (err_data[0] & 0x1) {
+
+                       retval = adbg_ctrl_read(jtag_info, 
DBG_SYSBUS_REG_ERROR, err_data, 33);
+                       if (retval != ERROR_OK)
+                               goto out;
+
+                       addr = (err_data[0] >> 1) | (err_data[1] << 31);
+                       LOG_WARNING("SYSBUS bus error during burst read, 
address 0x%08" PRIx32 ", retrying!", addr);
+
+                       bus_error_retries++;
+                       if (bus_error_retries > MAX_BUS_ERRORS) {
+                               LOG_ERROR("Max SYSBUS bus errors reached during 
burst read");
+                               retval = ERROR_FAIL;
+                               goto out;
+                       }
+
+                       /* Don't call retry_do(), a JTAG reset won't help a 
SYSBUS bus error */
+                       /* Write 1 bit, to reset the error register */
+                       err_data[0] = 1;
+                       retval = adbg_ctrl_write(jtag_info, 
DBG_SYSBUS_REG_ERROR, err_data, 1);
+                       if (retval != ERROR_OK)
+                               goto out;
+
+                       goto retry_read_full;
+               }
+       }
+
+out:
+       free(in_buffer);
+
+       return retval;
+}
+
+/* Set up and execute a burst write to a contiguous set of addresses */
+static int adbg_sysbus_burst_write(struct rl_jtag *jtag_info, const uint8_t 
*data, int size,
+                                   int count, unsigned long start_address)
+{
+       int retry_full_crc = 0;
+       int retval;
+
+       uint8_t opcode;
+       uint8_t opcode_len;
+       uint8_t cpusel = 0;
+       uint8_t cpusel_len;
+       uint8_t address_len;
+
+       LOG_DEBUG("Doing burst write, word size %d, word count %d,"
+                 "start address 0x%08lx", size, count, start_address);
+
+       /* Select the appropriate opcode */
+       switch (jtag_info->rl_jtag_module_selected) {
+       case DC_SYSBUS:
+               if (size == 1)
+                       opcode = DBG_SYSBUS_CMD_BWRITE8;
+               else if (size == 2)
+                       opcode = DBG_SYSBUS_CMD_BWRITE16;
+               else if (size == 4)
+                       opcode = DBG_SYSBUS_CMD_BWRITE32;
+               else if (size == 8)
+                       opcode = DBG_SYSBUS_CMD_BWRITE64;
+               else {
+                       LOG_DEBUG("Tried SYSBUS burst write with invalid word 
size (%d),"
+                                 "defaulting to 4-byte words", size);
+                       opcode = DBG_SYSBUS_CMD_BWRITE32;
+               }
+               opcode_len = DBG_SYSBUS_OPCODE_LEN;
+               cpusel_len = 0;
+               break;
+       case DC_CPU:
+               if (size == 4)
+                       opcode = DBG_CPU_CMD_BWRITE32;
+               else {
+                       LOG_DEBUG("Tried CPU burst write with invalid word size 
(%d),"
+                                 "defaulting to 4-byte words", size);
+                       opcode = DBG_CPU_CMD_BWRITE32;
+               }
+               opcode_len = DBG_CPU_OPCODE_LEN;
+               cpusel     = jtag_info->rl_jtag_cpu_selected;
+               cpusel_len = DBG_CPU_CPUSEL_LEN;
+               break;
+       default:
+               LOG_ERROR("Illegal debug chain selected (%i) while doing burst 
write",
+                         jtag_info->rl_jtag_module_selected);
+               return ERROR_FAIL;
+       }
+       address_len = jtag_info->rl_jtag_address_size;
+
+
+retry_full_write:
+
+       /* Send the BURST WRITE command, returns TAP to idle state */
+       retval = adbg_burst_command(jtag_info, opcode, opcode_len,
+                               start_address, address_len, cpusel, cpusel_len, 
count);
+
+       if (retval != ERROR_OK)
+               return retval;
+
+       struct scan_field field[3];
+
+       /* Write a start bit so it knows when to start counting */
+       uint8_t value = 1;
+       field[0].num_bits = 1;
+       field[0].out_value = &value;
+       field[0].in_value = NULL;
+
+       uint32_t crc_calc = 0xffffffff;
+       for (int i = 0; i < (count * size); i++)
+               crc_calc = adbg_compute_crc(crc_calc, data[i], 8);
+
+       field[1].num_bits = count * size * 8;
+       field[1].out_value = data;
+       field[1].in_value = NULL;
+
+       field[2].num_bits = 32;
+       field[2].out_value = (uint8_t *)&crc_calc;
+       field[2].in_value = NULL;
+
+       jtag_add_dr_scan(jtag_info->tap, 3, field, TAP_DRSHIFT);
+
+       /* Read the 'CRC match' bit, and go to idle */
+       field[0].num_bits = 1;
+       field[0].out_value = NULL;
+       field[0].in_value = &value;
+       jtag_add_dr_scan(jtag_info->tap, 1, field, TAP_IDLE);
+
+       retval = jtag_execute_queue();
+       if (retval != ERROR_OK)
+               return retval;
+
+       if (!value) {
+               LOG_WARNING("CRC ERROR! match bit after write is %" PRIi8 " 
(computed CRC 0x%08" PRIx32 ")", value, crc_calc);
+               if (retry_full_crc++ < MAX_WRITE_CRC_RETRY)
+                       goto retry_full_write;
+               else
+                       return ERROR_FAIL;
+       } else
+               LOG_DEBUG("CRC OK!\n");
+
+       /* Now, read the error register, and retry/recompute as necessary */
+       if (jtag_info->rl_jtag_module_selected == DC_SYSBUS &&
+           !(rl_dbg_adv.options & USE_HISPEED)) {
+               uint32_t addr;
+               int bus_error_retries = 0;
+               uint32_t err_data[2] = {0, 0};
+
+               /* First, just get 1 bit...read address only if necessary */
+               retval = adbg_ctrl_read(jtag_info, DBG_SYSBUS_REG_ERROR, 
err_data, 1);
+               if (retval != ERROR_OK)
+                       return retval;
+
+               /* Then we have a problem */
+               if (err_data[0] & 0x1) {
+
+                       retval = adbg_ctrl_read(jtag_info, 
DBG_SYSBUS_REG_ERROR, err_data, 33);
+                       if (retval != ERROR_OK)
+                               return retval;
+
+                       addr = (err_data[0] >> 1) | (err_data[1] << 31);
+                       LOG_WARNING("SYSBUS bus error during burst write, 
address 0x%08" PRIx32 ", retrying!", addr);
+
+                       bus_error_retries++;
+                       if (bus_error_retries > MAX_BUS_ERRORS) {
+                               LOG_ERROR("Max SYSBUS bus errors reached during 
burst read");
+                               retval = ERROR_FAIL;
+                               return retval;
+                       }
+
+                       /* Don't call retry_do(), a JTAG reset won't help a 
SYSBUS bus error */
+                       /* Write 1 bit, to reset the error register */
+                       err_data[0] = 1;
+                       retval = adbg_ctrl_write(jtag_info, 
DBG_SYSBUS_REG_ERROR, err_data, 1);
+                       if (retval != ERROR_OK)
+                               return retval;
+
+                       goto retry_full_write;
+               }
+       }
+
+       return ERROR_OK;
+}
+
+/* Currently hard set in functions to 32-bits */
+static int rl_adv_jtag_read_cpu(struct rl_jtag *jtag_info,
+               uint32_t addr, int count, uint32_t *value)
+{
+       int retval;
+       if (!jtag_info->rl_jtag_inited) {
+               retval = rl_adv_jtag_init(jtag_info);
+               if (retval != ERROR_OK)
+                       return retval;
+       }
+
+       retval = adbg_select_module(jtag_info, DC_CPU);
+       if (retval != ERROR_OK)
+               return retval;
+
+       return adbg_sysbus_burst_read(jtag_info, 4, count, addr, (uint8_t 
*)value);
+}
+
+static int rl_adv_jtag_write_cpu(struct rl_jtag *jtag_info,
+               uint32_t addr, int count, const uint32_t *value)
+{
+       int retval;
+       if (!jtag_info->rl_jtag_inited) {
+               retval = rl_adv_jtag_init(jtag_info);
+               if (retval != ERROR_OK)
+                       return retval;
+       }
+
+       retval = adbg_select_module(jtag_info, DC_CPU);
+       if (retval != ERROR_OK)
+               return retval;
+
+       return adbg_sysbus_burst_write(jtag_info, (uint8_t *)value, 4, count, 
addr);
+}
+
+static int rl_adv_cpu_stall(struct rl_jtag *jtag_info, int action)
+{
+       int retval;
+       if (!jtag_info->rl_jtag_inited) {
+               retval = rl_adv_jtag_init(jtag_info);
+               if (retval != ERROR_OK)
+                       return retval;
+       }
+
+       retval = adbg_select_module(jtag_info, DC_CPU);
+       if (retval != ERROR_OK)
+               return retval;
+
+       /* TODO: the '2' length should be NumberOfCPU */
+       uint32_t cpu_cr;
+       retval = adbg_ctrl_read(jtag_info, DBG_CPU_REG_STATUS, &cpu_cr, 2);
+       if (retval != ERROR_OK)
+               return retval;
+
+       if (action == CPU_STALL)
+               cpu_cr |= DBG_CPU_CR_STALL;
+       else
+               cpu_cr &= ~DBG_CPU_CR_STALL;
+
+       retval = adbg_select_module(jtag_info, DC_CPU);
+       if (retval != ERROR_OK)
+               return retval;
+
+               /* TODO: the '2' length should be number of CPUs */
+       return adbg_ctrl_write(jtag_info, DBG_CPU_REG_STATUS, &cpu_cr, 2);
+}
+
+static int rl_adv_is_cpu_running(struct rl_jtag *jtag_info, int *running)
+{
+       int retval;
+       if (!jtag_info->rl_jtag_inited) {
+               retval = rl_adv_jtag_init(jtag_info);
+               if (retval != ERROR_OK)
+                       return retval;
+       }
+
+       int current = jtag_info->rl_jtag_module_selected;
+
+       retval = adbg_select_module(jtag_info, DC_CPU);
+       if (retval != ERROR_OK)
+               return retval;
+
+       uint32_t cpu_cr = 0;
+       retval = adbg_ctrl_read(jtag_info, DBG_CPU_REG_STATUS, &cpu_cr, 2);
+       if (retval != ERROR_OK)
+               return retval;
+
+       if (cpu_cr & DBG_CPU_CR_STALL)
+               *running = 0;
+       else
+               *running = 1;
+
+       if (current != DC_NONE) {
+               retval = adbg_select_module(jtag_info, current);
+               if (retval != ERROR_OK)
+                       return retval;
+       }
+
+       return ERROR_OK;
+}
+
+static int rl_adv_cpu_reset(struct rl_jtag *jtag_info, int action)
+{
+       int retval;
+       if (!jtag_info->rl_jtag_inited) {
+               retval = rl_adv_jtag_init(jtag_info);
+               if (retval != ERROR_OK)
+                       return retval;
+       }
+
+       retval = adbg_select_module(jtag_info, DC_CPU);
+       if (retval != ERROR_OK)
+               return retval;
+
+       uint32_t cpu_cr;
+       retval = adbg_ctrl_read(jtag_info, DBG_CPU_REG_STATUS, &cpu_cr, 2);
+       if (retval != ERROR_OK)
+               return retval;
+
+       if (action == CPU_RESET)
+               cpu_cr |= DBG_CPU_CR_RESET;
+       else
+               cpu_cr &= ~DBG_CPU_CR_RESET;
+
+       retval = adbg_select_module(jtag_info, DC_CPU);
+       if (retval != ERROR_OK)
+               return retval;
+
+       return adbg_ctrl_write(jtag_info, DBG_CPU_REG_STATUS, &cpu_cr, 2);
+}
+
+static int rl_adv_jtag_read_memory(struct rl_jtag *jtag_info,
+                               uint32_t addr, uint32_t size, int count, 
uint8_t *buffer)
+{
+       LOG_DEBUG("Reading SYSBUS%" PRIu32 " at 0x%08" PRIx32, size * 8, addr);
+
+       int retval;
+       if (!jtag_info->rl_jtag_inited) {
+               retval = rl_adv_jtag_init(jtag_info);
+               if (retval != ERROR_OK)
+                       return retval;
+       }
+
+       retval = adbg_select_module(jtag_info, DC_SYSBUS);
+       if (retval != ERROR_OK)
+               return retval;
+
+       int block_count_left = count;
+       uint32_t block_count_address = addr;
+       uint8_t *block_count_buffer = buffer;
+
+       while (block_count_left) {
+
+               int blocks_this_round = (block_count_left > MAX_BURST_SIZE) ?
+                       MAX_BURST_SIZE : block_count_left;
+
+               retval = adbg_sysbus_burst_read(jtag_info, size, 
blocks_this_round,
+                                                       block_count_address, 
block_count_buffer);
+               if (retval != ERROR_OK)
+                       return retval;
+
+               block_count_left    -= blocks_this_round;
+               block_count_address += size * MAX_BURST_SIZE;
+               block_count_buffer  += size * MAX_BURST_SIZE;
+       }
+
+       /* The adv_debug_if always return words and half words in
+        * little-endian order no matter what the target endian is.
+        * So if the target endian is big, change the order.
+        */
+
+       struct target *target = jtag_info->target;
+       if ((target->endianness == TARGET_BIG_ENDIAN) && (size != 1)) {
+               switch (size) {
+               case 4:
+                       buf_bswap32(buffer, buffer, size * count);
+                       break;
+               case 2:
+                       buf_bswap16(buffer, buffer, size * count);
+                       break;
+               }
+       }
+
+       return ERROR_OK;
+}
+
+static int rl_adv_jtag_write_memory(struct rl_jtag *jtag_info,
+                            uint32_t addr, uint32_t size, int count, const 
uint8_t *buffer)
+{
+       LOG_DEBUG("Writing SYSBUS%" PRIu32 " at 0x%08" PRIx32, size * 8, addr);
+
+       int retval;
+       if (!jtag_info->rl_jtag_inited) {
+               retval = rl_adv_jtag_init(jtag_info);
+               if (retval != ERROR_OK)
+                       return retval;
+       }
+
+       retval = adbg_select_module(jtag_info, DC_SYSBUS);
+       if (retval != ERROR_OK)
+               return retval;
+
+       /* The adv_debug_if wants words and half words in little-endian
+        * order no matter what the target endian is. So if the target
+        * endian is big, change the order.
+        */
+
+       void *t = NULL;
+       struct target *target = jtag_info->target;
+       if ((target->endianness == TARGET_BIG_ENDIAN) && (size != 1)) {
+               t = malloc(count * size * sizeof(uint8_t));
+               if (!t) {
+                       LOG_ERROR("Out of memory");
+                       return ERROR_FAIL;
+               }
+
+               switch (size) {
+               /*      case 8: */
+               /*      bus_bswap64(t, buffer, size * count); */
+               /*      break; */
+               case 4:
+                       buf_bswap32(t, buffer, size * count);
+                       break;
+               case 2:
+                       buf_bswap16(t, buffer, size * count);
+                       break;
+               }
+               buffer = t;
+       }
+
+       int block_count_left = count;
+       uint32_t block_count_address = addr;
+       uint8_t *block_count_buffer = (uint8_t *)buffer;
+
+       while (block_count_left) {
+
+               int blocks_this_round = (block_count_left > MAX_BURST_SIZE) ?
+                       MAX_BURST_SIZE : block_count_left;
+
+               retval = adbg_sysbus_burst_write(jtag_info, block_count_buffer,
+                                                       size, blocks_this_round,
+                                                       block_count_address);
+               if (retval != ERROR_OK) {
+                       free(t);
+                       return retval;
+               }
+
+               block_count_left    -= blocks_this_round;
+               block_count_address += size * MAX_BURST_SIZE;
+               block_count_buffer  += size * MAX_BURST_SIZE;
+       }
+
+       free(t);
+       return ERROR_OK;
+}
+
+int rl_adv_jtag_jsp_xfer(struct rl_jtag *jtag_info,
+                                 int *out_len, unsigned char *out_buffer,
+                                 int *in_len, unsigned char *in_buffer)
+{
+       LOG_DEBUG("JSP transfer");
+
+       int retval;
+       if (!jtag_info->rl_jtag_inited)
+               return ERROR_OK;
+
+       retval = adbg_select_module(jtag_info, DC_JSP);
+       if (retval != ERROR_OK)
+               return retval;
+
+       /* return nb char xmit */
+       int xmitsize;
+       if (*out_len > 8)
+               xmitsize = 8;
+       else
+               xmitsize = *out_len;
+
+       uint8_t out_data[10];
+       uint8_t in_data[10];
+       struct scan_field field;
+       int startbit, stopbit, wrapbit;
+
+       memset(out_data, 0, 10);
+
+       if (rl_dbg_adv.options & ENABLE_JSP_MULTI) {
+
+               startbit = 1;
+               wrapbit = (xmitsize >> 3) & 0x1;
+               out_data[0] = (xmitsize << 5) | 0x1;  /* set the start bit */
+
+               int i;
+               /* don't copy off the end of the input array */
+               for (i = 0; i < xmitsize; i++) {
+                       out_data[i + 1] = (out_buffer[i] << 1) | wrapbit;
+                       wrapbit = (out_buffer[i] >> 7) & 0x1;
+               }
+
+               if (i < 8)
+                       out_data[i + 1] = wrapbit;
+               else
+                       out_data[9] = wrapbit;
+
+               /* If the last data bit is a '1', then we need to append a '0' 
so the top-level module
+                * won't treat the burst as a 'module select' command.
+                */
+               stopbit = !!(out_data[9] & 0x01);
+
+       } else {
+               startbit = 0;
+               /* First byte out has write count in upper nibble */
+               out_data[0] = 0x0 | (xmitsize << 4);
+               if (xmitsize > 0)
+                       memcpy(&out_data[1], out_buffer, xmitsize);
+
+               /* If the last data bit is a '1', then we need to append a '0' 
so the top-level module
+                * won't treat the burst as a 'module select' command.
+                */
+               stopbit = !!(out_data[8] & 0x80);
+       }
+
+       field.num_bits = 72 + startbit + stopbit;
+       field.out_value = out_data;
+       field.in_value = in_data;
+
+       jtag_add_dr_scan(jtag_info->tap, 1, &field, TAP_IDLE);
+
+       retval = jtag_execute_queue();
+       if (retval != ERROR_OK)
+               return retval;
+
+       /* bytes available is in the upper nibble */
+       *in_len = (in_data[0] >> 4) & 0xF;
+       memcpy(in_buffer, &in_data[1], *in_len);
+
+       int bytes_free = in_data[0] & 0x0F;
+       *out_len = (bytes_free < xmitsize) ? bytes_free : xmitsize;
+
+       return ERROR_OK;
+}
+
+static struct rl_du rl_dbg_adv = {
+       .name                   = "rl_dbg_adv",
+       .options                = NO_OPTION,
+       .rl_jtag_init           = rl_adv_jtag_init,
+
+       .rl_is_cpu_running      = rl_adv_is_cpu_running,
+       .rl_cpu_stall           = rl_adv_cpu_stall,
+       .rl_cpu_reset           = rl_adv_cpu_reset,
+
+       .rl_jtag_read_cpu       = rl_adv_jtag_read_cpu,
+       .rl_jtag_write_cpu      = rl_adv_jtag_write_cpu,
+
+       .rl_jtag_read_memory    = rl_adv_jtag_read_memory,
+       .rl_jtag_write_memory   = rl_adv_jtag_write_memory
+};
+
+int rl_dbg_adv_register(void)
+{
+       list_add_tail(&rl_dbg_adv.list, &rl_du_list);
+       return 0;
+}
diff --git a/src/target/roalogic/rl_dbg_adv.h b/src/target/roalogic/rl_dbg_adv.h
new file mode 100644
index 0000000000..deaaa68de7
--- /dev/null
+++ b/src/target/roalogic/rl_dbg_adv.h
@@ -0,0 +1,71 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/***************************************************************************
+ *   Copyright (C) 2022 Richard Herveille                                  *
+ *   richard.hervei...@roalogic.com                                        *
+ *                                                                         *
+ *   Copyright (C) 2022 by Bjorn Schouteten                                *
+ *   bjorn.schoute...@roalogic.com                                         *
+ *                                                                         *
+ ***************************************************************************/
+
+#ifndef OPENOCD_TARGET_ROALOGIC_DBG_ADV_H
+#define OPENOCD_TARGET_ROALOGIC_DBG_ADV_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#define CPU_STALL      0
+#define CPU_UNSTALL    1
+
+#define CPU_RESET      0
+#define CPU_NOT_RESET  1
+
+int rl_dbg_adv_register(void);
+
+/* Linear list over all available or1k debug unit */
+extern struct list_head rl_du_list;
+
+struct rl_du {
+       const char *name;
+       struct list_head list;
+       int options;
+
+       int (*rl_jtag_init)(struct rl_jtag *jtag_info);
+
+       int (*rl_is_cpu_running)(struct rl_jtag *jtag_info, int *running);
+
+       int (*rl_cpu_stall)(struct rl_jtag *jtag_info, int action);
+
+       int (*rl_cpu_reset)(struct rl_jtag *jtag_info, int action);
+
+       int (*rl_jtag_read_cpu)(struct rl_jtag *jtag_info,
+                               uint32_t addr, int count, uint32_t *value);
+
+       int (*rl_jtag_write_cpu)(struct rl_jtag *jtag_info,
+                               uint32_t addr, int count, const uint32_t 
*value);
+
+       int (*rl_jtag_read_memory)(struct rl_jtag *jtag_info, uint32_t addr, 
uint32_t size,
+                                       int count, uint8_t *buffer);
+
+       int (*rl_jtag_write_memory)(struct rl_jtag *jtag_info, uint32_t addr, 
uint32_t size,
+                                       int count, const uint8_t *buffer);
+};
+
+static inline struct rl_du *rl_jtag_to_du(struct rl_jtag *jtag_info)
+{
+       return (struct rl_du *)jtag_info->du_core;
+}
+
+static inline struct rl_du *rl_to_du(struct rv12_common *rvl)
+{
+       struct rl_jtag *jtag = &rvl->jtag;
+       return (struct rl_du *)jtag->du_core;
+}
+
+int rl_adv_jtag_jsp_xfer(struct rl_jtag *jtag_info,
+                       int *out_len, unsigned char *out_buffer,
+                       int *in_len, unsigned char *in_buffer);
+
+#endif /* OPENOCD_TARGET_ROALOGIC_DBG_ADV_H */
diff --git a/src/target/roalogic/rl_tap.h b/src/target/roalogic/rl_tap.h
new file mode 100644
index 0000000000..1a64fe4ce5
--- /dev/null
+++ b/src/target/roalogic/rl_tap.h
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/***************************************************************************
+ *   Copyright (C) 2022 by Richard Herveille                               *
+ *   richard.hervei...@roalogic.com                                        *
+ *                                                                         *
+ *   Copyright (C) 2022 by Bjorn Schouteten                                *
+ *   bjorn.schoute...@roalogic.com                                         *
+ *                                                                         *
+ ***************************************************************************/
+
+#ifndef OPENOCD_TARGET_ROALOGIC_RL_TAP_H
+#define OPENOCD_TARGET_ROALOGIC_RL_TAP_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <helper/list.h>
+#include "rv12.h"
+
+int rl_tap_vjtag_register(void);
+int rl_universal_tap_register(void);
+
+/* Linear list over all available Roa Logic TAPs */
+extern struct list_head rl_tap_list;
+
+struct rl_tap_ip {
+       struct list_head list;
+       int (*init)(struct rl_jtag *jtag_info);
+       const char *name;
+};
+
+#endif /* OPENOCD_TARGET_ROALOGIC_RL_TAP_H */
diff --git a/src/target/roalogic/rl_universal_tap.c 
b/src/target/roalogic/rl_universal_tap.c
new file mode 100644
index 0000000000..898e7b849c
--- /dev/null
+++ b/src/target/roalogic/rl_universal_tap.c
@@ -0,0 +1,58 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/***************************************************************************
+ *   Copyright (C) 2022 by Richard Herveille                               *
+ *   richard.hervei...@roalogic.com                                        *
+ *                                                                         *
+ *   Copyright (C) 2022 by Bjorn Schouteten                                *
+ *   bjorn.schoute...@roalogic.com                                         *
+ *                                                                         *
+ *   Based on OR1k Version                                                 *
+ *                                                                         *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "rl_tap.h"
+#include "rv12.h"
+
+#include <jtag/jtag.h>
+
+#define RL_TAP_INST_DEBUG      0x8
+
+static int rl_universal_tap_init(struct rl_jtag *jtag_info)
+{
+       LOG_DEBUG("Initialising Roa Logic Universal JTAG TAP");
+
+       /* Put TAP into state where it can talk to the debug interface
+        * by shifting in correct value to IR.
+        */
+
+       /* Ensure TAP is reset - maybe not necessary*/
+       jtag_add_tlr();
+
+       struct jtag_tap *tap = jtag_info->tap;
+       struct scan_field field;
+       uint8_t ir_value = RL_TAP_INST_DEBUG;
+
+       field.num_bits = tap->ir_length;
+       field.out_value = &ir_value;
+       field.in_value = NULL;
+
+       jtag_add_ir_scan(tap, &field, TAP_IDLE);
+
+       return jtag_execute_queue();
+}
+
+static struct rl_tap_ip universal_tap = {
+       .name = "rl_universal_tap",
+       .init = rl_universal_tap_init,
+};
+
+int rl_universal_tap_register(void)
+{
+       list_add_tail(&universal_tap.list, &rl_tap_list);
+       return 0;
+}
diff --git a/src/target/roalogic/rv12.c b/src/target/roalogic/rv12.c
new file mode 100644
index 0000000000..e4865fffe9
--- /dev/null
+++ b/src/target/roalogic/rv12.c
@@ -0,0 +1,1774 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/***************************************************************************
+ *   Copyright (C) 2022 by Richard Herveille                               *
+ *   richard.hervei...@roalogic.com                                        *
+ *                                                                         *
+ *   Copyright (C) 2022 by Bjorn Schouteten                                *
+ *   bjorn.schoute...@roalogic.com                                         *
+ *                                                                         *
+ *   Based on OR1K version                                                 *
+ *                                                                         *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <jtag/jtag.h>
+#include <target/register.h>
+#include <target/target.h>
+#include <target/breakpoints.h>
+#include <target/target_type.h>
+#include <helper/time_support.h>
+#include <helper/fileio.h>
+#include "rl_tap.h"
+#include "rv12.h"
+#include "rl_dbg_adv.h"
+
+LIST_HEAD(rl_tap_list);
+LIST_HEAD(rl_du_list);
+
+static int rv12_remove_breakpoint(struct target *target,
+                                        struct breakpoint *breakpoint);
+
+static int rv12_read_core_reg(struct target *target, int num);
+static int rv12_write_core_reg(struct target *target, int num);
+
+static struct rv12_core_reg *rv12_core_reg_list_arch_info;
+
+/* Combination of RISC-V and rv12 names
+ * until rv12 uses RISC-V debug spec */
+static const struct rv12_core_reg_init rv12_init_reg_list[] = {
+       /* Integer Register File */
+       {"zero",          GROUP_RF   +  0,             "org.gnu.gdb.riscv.cpu", 
NULL},
+       {"ra",            GROUP_RF   +  1,             "org.gnu.gdb.riscv.cpu", 
NULL},
+       {"sp",            GROUP_RF   +  2,             "org.gnu.gdb.riscv.cpu", 
NULL},
+       {"gp",            GROUP_RF   +  3,             "org.gnu.gdb.riscv.cpu", 
NULL},
+       {"tp",            GROUP_RF   +  4,             "org.gnu.gdb.riscv.cpu", 
NULL},
+       {"t0",            GROUP_RF   +  5,             "org.gnu.gdb.riscv.cpu", 
NULL},
+       {"t1",            GROUP_RF   +  6,             "org.gnu.gdb.riscv.cpu", 
NULL},
+       {"t2",            GROUP_RF   +  7,             "org.gnu.gdb.riscv.cpu", 
NULL},
+       {"s0",            GROUP_RF   +  8,             "org.gnu.gdb.riscv.cpu", 
NULL},
+       {"s1",            GROUP_RF   +  9,             "org.gnu.gdb.riscv.cpu", 
NULL},
+       {"a0",            GROUP_RF   + 10,             "org.gnu.gdb.riscv.cpu", 
NULL},
+       {"a1",            GROUP_RF   + 11,             "org.gnu.gdb.riscv.cpu", 
NULL},
+       {"a2",            GROUP_RF   + 12,             "org.gnu.gdb.riscv.cpu", 
NULL},
+       {"a3",            GROUP_RF   + 13,             "org.gnu.gdb.riscv.cpu", 
NULL},
+       {"a4",            GROUP_RF   + 14,             "org.gnu.gdb.riscv.cpu", 
NULL},
+       {"a5",            GROUP_RF   + 15,             "org.gnu.gdb.riscv.cpu", 
NULL},
+       {"a6",            GROUP_RF   + 16,             "org.gnu.gdb.riscv.cpu", 
NULL},
+       {"a7",            GROUP_RF   + 17,             "org.gnu.gdb.riscv.cpu", 
NULL},
+       {"s2",            GROUP_RF   + 18,             "org.gnu.gdb.riscv.cpu", 
NULL},
+       {"s3",            GROUP_RF   + 19,             "org.gnu.gdb.riscv.cpu", 
NULL},
+       {"s4",            GROUP_RF   + 20,             "org.gnu.gdb.riscv.cpu", 
NULL},
+       {"s5",            GROUP_RF   + 21,             "org.gnu.gdb.riscv.cpu", 
NULL},
+       {"s6",            GROUP_RF   + 22,             "org.gnu.gdb.riscv.cpu", 
NULL},
+       {"s7",            GROUP_RF   + 23,             "org.gnu.gdb.riscv.cpu", 
NULL},
+       {"s8",            GROUP_RF   + 24,             "org.gnu.gdb.riscv.cpu", 
NULL},
+       {"s9",            GROUP_RF   + 25,             "org.gnu.gdb.riscv.cpu", 
NULL},
+       {"s10",           GROUP_RF   + 26,             "org.gnu.gdb.riscv.cpu", 
NULL},
+       {"s11",           GROUP_RF   + 27,             "org.gnu.gdb.riscv.cpu", 
NULL},
+       {"t3",            GROUP_RF   + 28,             "org.gnu.gdb.riscv.cpu", 
NULL},
+       {"t4",            GROUP_RF   + 29,             "org.gnu.gdb.riscv.cpu", 
NULL},
+       {"t5",            GROUP_RF   + 30,             "org.gnu.gdb.riscv.cpu", 
NULL},
+       {"t6",            GROUP_RF   + 31,             "org.gnu.gdb.riscv.cpu", 
NULL},
+
+       /* PC */
+       {"pc",            GROUP_GPRS + 0x201,          "org.gnu.gdb.rv12.dbg",  
NULL},
+
+       /* CSRs */
+       {"ustatus",       GROUP_CSR  + CSR_USTATUS,    "org.gnu.gdb.riscv.csr", 
NULL},
+       {"uie",           GROUP_CSR  + CSR_UIE,        "org.gnu.gdb.riscv.csr", 
NULL},
+       {"utvec",         GROUP_CSR  + CSR_UTVEC,      "org.gnu.gdb.riscv.csr", 
NULL},
+       {"uscratch",      GROUP_CSR  + CSR_USCRATCH,   "org.gnu.gdb.riscv.csr", 
NULL},
+       {"uepc",          GROUP_CSR  + CSR_UEPC,       "org.gnu.gdb.riscv.csr", 
NULL},
+       {"ucause",        GROUP_CSR  + CSR_UCAUSE,     "org.gnu.gdb.riscv.csr", 
NULL},
+       {"utval",         GROUP_CSR  + CSR_UTVAL,      "org.gnu.gdb.riscv.csr", 
NULL},
+       {"uip",           GROUP_CSR  + CSR_UIP,        "org.gnu.gdb.riscv.csr", 
NULL},
+       {"fflags",        GROUP_CSR  + CSR_FFLAGS,     "org.gnu.gdb.riscv.csr", 
NULL},
+       {"frm",           GROUP_CSR  + CSR_FRM,        "org.gnu.gdb.riscv.csr", 
NULL},
+       {"fcsr",          GROUP_CSR  + CSR_FCSR,       "org.gnu.gdb.riscv.csr", 
NULL},
+       {"cycle",         GROUP_CSR  + CSR_CYCLE,      "org.gnu.gdb.riscv.csr", 
NULL},
+       {"time",          GROUP_CSR  + CSR_TIME,       "org.gnu.gdb.riscv.csr", 
NULL},
+       {"instret",       GROUP_CSR  + CSR_INSTRET,    "org.gnu.gdb.riscv.csr", 
NULL},
+       {"cycleh",        GROUP_CSR  + CSR_CYCLEH,     "org.gnu.gdb.riscv.csr", 
NULL},
+       {"timeh",         GROUP_CSR  + CSR_TIMEH,      "org.gnu.gdb.riscv.csr", 
NULL},
+       {"instreth",      GROUP_CSR  + CSR_INSTRETH,   "org.gnu.gdb.riscv.csr", 
NULL},
+
+       {"sstatus",       GROUP_CSR  + CSR_SSTATUS,    "org.gnu.gdb.riscv.csr", 
NULL},
+       {"sedeleg",       GROUP_CSR  + CSR_SEDELEG,    "org.gnu.gdb.riscv.csr", 
NULL},
+       {"sideleg",       GROUP_CSR  + CSR_SIDELEG,    "org.gnu.gdb.riscv.csr", 
NULL},
+       {"sie",           GROUP_CSR  + CSR_SIE,        "org.gnu.gdb.riscv.csr", 
NULL},
+       {"stvec",         GROUP_CSR  + CSR_STVEC,      "org.gnu.gdb.riscv.csr", 
NULL},
+       {"scounteren",    GROUP_CSR  + CSR_SCOUNTEREN, "org.gnu.gdb.riscv.csr", 
NULL},
+       {"sscratch",      GROUP_CSR  + CSR_SSCRATCH,   "org.gnu.gdb.riscv.csr", 
NULL},
+       {"sepc",          GROUP_CSR  + CSR_SEPC,       "org.gnu.gdb.riscv.csr", 
NULL},
+       {"scause",        GROUP_CSR  + CSR_SCAUSE,     "org.gnu.gdb.riscv.csr", 
NULL},
+       {"stval",         GROUP_CSR  + CSR_STVAL,      "org.gnu.gdb.riscv.csr", 
NULL},
+       {"sip",           GROUP_CSR  + CSR_SIP,        "org.gnu.gdb.riscv.csr", 
NULL},
+       {"satp",          GROUP_CSR  + CSR_SATP,       "org.gnu.gdb.riscv.csr", 
NULL},
+
+       {"mvendorid",     GROUP_CSR  + CSR_MVENDORID,  "org.gnu.gdb.riscv.csr", 
NULL},
+       {"marchid",       GROUP_CSR  + CSR_MARCHID,    "org.gnu.gdb.riscv.csr", 
NULL},
+       {"mimpid",        GROUP_CSR  + CSR_MIMPID,     "org.gnu.gdb.riscv.csr", 
NULL},
+       {"mhartid",       GROUP_CSR  + CSR_MHARTID,    "org.gnu.gdb.riscv.csr", 
NULL},
+       {"mstatus",       GROUP_CSR  + CSR_MSTATUS,    "org.gnu.gdb.riscv.csr", 
NULL},
+       {"misa",          GROUP_CSR  + CSR_MISA,       "org.gnu.gdb.riscv.csr", 
NULL},
+       {"medeleg",       GROUP_CSR  + CSR_MEDELEG,    "org.gnu.gdb.riscv.csr", 
NULL},
+       {"mideleg",       GROUP_CSR  + CSR_MIDELEG,    "org.gnu.gdb.riscv.csr", 
NULL},
+       {"mie",           GROUP_CSR  + CSR_MIE,        "org.gnu.gdb.riscv.csr", 
NULL},
+       {"mnmivec",       GROUP_CSR  + CSR_MNMIVEC,    "org.gnu.gdb.riscv.csr", 
NULL},
+       {"mtvec",         GROUP_CSR  + CSR_MTVEC,      "org.gnu.gdb.riscv.csr", 
NULL},
+       {"mcounteren",    GROUP_CSR  + CSR_MCOUNTEREN, "org.gnu.gdb.riscv.csr", 
NULL},
+       {"mscratch",      GROUP_CSR  + CSR_MSCRATCH,   "org.gnu.gdb.riscv.csr", 
NULL},
+       {"mepc",          GROUP_CSR  + CSR_MEPC,       "org.gnu.gdb.riscv.csr", 
NULL},
+       {"mcause",        GROUP_CSR  + CSR_MCAUSE,     "org.gnu.gdb.riscv.csr", 
NULL},
+       {"mtval",         GROUP_CSR  + CSR_MTVAL,      "org.gnu.gdb.riscv.csr", 
NULL},
+       {"mip",           GROUP_CSR  + CSR_MIP,        "org.gnu.gdb.riscv.csr", 
NULL},
+
+       {"pmpcfg0",       GROUP_CSR  + CSR_PMPCFG0,    "org.gnu.gdb.riscv.csr", 
NULL},
+       {"pmpcfg1",       GROUP_CSR  + CSR_PMPCFG1,    "org.gnu.gdb.riscv.csr", 
NULL},
+       {"pmpcfg2",       GROUP_CSR  + CSR_PMPCFG2,    "org.gnu.gdb.riscv.csr", 
NULL},
+       {"pmpcfg3",       GROUP_CSR  + CSR_PMPCFG3,    "org.gnu.gdb.riscv.csr", 
NULL},
+       {"pmpadr0",       GROUP_CSR  + CSR_PMPADDR0,   "org.gnu.gdb.riscv.csr", 
NULL},
+       {"pmpadr1",       GROUP_CSR  + CSR_PMPADDR1,   "org.gnu.gdb.riscv.csr", 
NULL},
+       {"pmpadr2",       GROUP_CSR  + CSR_PMPADDR2,   "org.gnu.gdb.riscv.csr", 
NULL},
+       {"pmpadr3",       GROUP_CSR  + CSR_PMPADDR3,   "org.gnu.gdb.riscv.csr", 
NULL},
+       {"pmpadr4",       GROUP_CSR  + CSR_PMPADDR4,   "org.gnu.gdb.riscv.csr", 
NULL},
+       {"pmpadr5",       GROUP_CSR  + CSR_PMPADDR5,   "org.gnu.gdb.riscv.csr", 
NULL},
+       {"pmpadr6",       GROUP_CSR  + CSR_PMPADDR6,   "org.gnu.gdb.riscv.csr", 
NULL},
+       {"pmpadr7",       GROUP_CSR  + CSR_PMPADDR7,   "org.gnu.gdb.riscv.csr", 
NULL},
+       {"pmpadr8",       GROUP_CSR  + CSR_PMPADDR8,   "org.gnu.gdb.riscv.csr", 
NULL},
+       {"pmpadr9",       GROUP_CSR  + CSR_PMPADDR9,   "org.gnu.gdb.riscv.csr", 
NULL},
+       {"pmpadr10",      GROUP_CSR  + CSR_PMPADDR10,  "org.gnu.gdb.riscv.csr", 
NULL},
+       {"pmpadr11",      GROUP_CSR  + CSR_PMPADDR11,  "org.gnu.gdb.riscv.csr", 
NULL},
+       {"pmpadr12",      GROUP_CSR  + CSR_PMPADDR12,  "org.gnu.gdb.riscv.csr", 
NULL},
+       {"pmpadr13",      GROUP_CSR  + CSR_PMPADDR13,  "org.gnu.gdb.riscv.csr", 
NULL},
+       {"pmpadr14",      GROUP_CSR  + CSR_PMPADDR14,  "org.gnu.gdb.riscv.csr", 
NULL},
+       {"pmpadr15",      GROUP_CSR  + CSR_PMPADDR15,  "org.gnu.gdb.riscv.csr", 
NULL},
+
+       {"mcycle",        GROUP_CSR  + CSR_MCYCLE,     "org.gnu.gdb.riscv.csr", 
NULL},
+       {"minstret",      GROUP_CSR  + CSR_MINSTRET,   "org.gnu.gdb.riscv.csr", 
NULL},
+       {"mcycleh",       GROUP_CSR  + CSR_MCYCLEH,    "org.gnu.gdb.riscv.csr", 
NULL},
+       {"minstreth",     GROUP_CSR  + CSR_MINSTRETH,  "org.gnu.gdb.riscv.csr", 
NULL},
+
+       /* Debug Unit Internals */
+       {"npc",           GROUP_GPRS + 0x200,          "org.gnu.gdb.rv12.dbg", 
NULL},
+       {"dbgctrl",       GROUP_DBG  +  0x00,          "org.gnu.gdb.rv12.dbg", 
NULL},
+       {"dbghit",        GROUP_DBG  +  0x01,          "org.gnu.gdb.rv12.dbg", 
NULL},
+       {"dbgie",         GROUP_DBG  +  0x02,          "org.gnu.gdb.rv12.dbg", 
NULL},
+       {"dbgcause",      GROUP_DBG  +  0x03,          "org.gnu.gdb.rv12.dbg", 
NULL},
+       {"dbg.bpctrl0",   GROUP_DBG  +  0x10,          "org.gnu.gdb.rv12.dbg", 
NULL},
+       {"dbg.bpdata0",   GROUP_DBG  +  0x11,          "org.gnu.gdb.rv12.dbg", 
NULL},
+       {"dbg.bpctrl1",   GROUP_DBG  +  0x12,          "org.gnu.gbd.rv12.dbg", 
NULL},
+       {"dbg.bpdata1",   GROUP_DBG  +  0x13,          "org.gnu.gdb.rv12.dbg", 
NULL},
+       {"dbg.bpctrl2",   GROUP_DBG  +  0x14,          "org.gnu.gdb.rv12.dbg", 
NULL},
+       {"dbg.bpdata2",   GROUP_DBG  +  0x15,          "org.gnu.gdb.rv12.dbg", 
NULL},
+};
+
+/*static int rv12_add_reg(struct target *target, struct rv12_core_reg *new_reg)
+{
+       struct rv12_common *rv12 = target_to_rv12(target);
+       int reg_list_size = rv12->nb_regs * sizeof(struct rv12_core_reg);
+
+       rv12_core_reg_list_arch_info = realloc(rv12_core_reg_list_arch_info,
+                               reg_list_size + sizeof(struct rv12_core_reg));
+
+       memcpy(&rv12_core_reg_list_arch_info[rv12->nb_regs], new_reg,
+               sizeof(struct rv12_core_reg));
+
+       rv12_core_reg_list_arch_info[rv12->nb_regs].list_num = rv12->nb_regs;
+
+       rv12->nb_regs++;
+
+       return ERROR_OK;
+}*/
+
+static int rv12_create_reg_list(struct target *target)
+{
+       struct rv12_common *rv12 = target_to_rv12(target);
+
+       LOG_DEBUG("-");
+
+       rv12_core_reg_list_arch_info = malloc(ARRAY_SIZE(rv12_init_reg_list) *
+                                               sizeof(struct rv12_core_reg));
+
+       for (int i = 0; i < (int)ARRAY_SIZE(rv12_init_reg_list); i++) {
+               rv12_core_reg_list_arch_info[i].name = 
rv12_init_reg_list[i].name;
+               rv12_core_reg_list_arch_info[i].spr_num = 
rv12_init_reg_list[i].spr_num;
+               rv12_core_reg_list_arch_info[i].group = 
rv12_init_reg_list[i].group;
+               rv12_core_reg_list_arch_info[i].feature = 
rv12_init_reg_list[i].feature;
+               rv12_core_reg_list_arch_info[i].list_num = i;
+               rv12_core_reg_list_arch_info[i].target = NULL;
+               rv12_core_reg_list_arch_info[i].rv12_common = NULL;
+       }
+
+       rv12->nb_regs = ARRAY_SIZE(rv12_init_reg_list);
+
+       return ERROR_OK;
+}
+
+static int rv12_jtag_read_regs(struct rv12_common *rv12, uint32_t *regs)
+{
+       struct rl_du *du_core = rl_jtag_to_du(&rv12->jtag);
+
+       LOG_DEBUG("-");
+
+       return du_core->rl_jtag_read_cpu(&rv12->jtag,
+                       rv12->arch_info[GDB_REGNO_ZERO].spr_num, 
GDB_REGNO_XPR31 + 1,
+                       regs + GDB_REGNO_ZERO);
+}
+
+static int rv12_jtag_write_regs(struct rv12_common *rv12, uint32_t *regs)
+{
+       struct rl_du *du_core = rl_jtag_to_du(&rv12->jtag);
+
+       LOG_DEBUG("-");
+
+       return du_core->rl_jtag_write_cpu(&rv12->jtag,
+                       rv12->arch_info[GDB_REGNO_ZERO].spr_num, 
GDB_REGNO_XPR31 + 1,
+                       &regs[GDB_REGNO_ZERO]);
+}
+
+static int rv12_save_context(struct target *target)
+{
+       struct rv12_common *rv12 = target_to_rv12(target);
+       struct rl_du *du_core = rl_to_du(rv12);
+       int regs_read = 0;
+       int retval;
+
+       LOG_DEBUG("-");
+
+       for (int i = 0; i < GDB_REGNO_FPR0; i++) {
+               if (!rv12->core_cache->reg_list[i].valid) {
+                       /* Read the PC for the PPC */
+                       if (i == GDB_REGNO_PC) {
+                               /* Read the PPC register */
+                               retval = du_core->rl_jtag_read_cpu(&rv12->jtag,
+                                               (GROUP_GPRS + 0x201), 1,
+                                               &rv12->core_regs[i]);
+
+                               LOG_DEBUG("Read PC: Value: %08x\n", 
rv12->core_regs[i]);
+                               if (retval != ERROR_OK)
+                                       return retval;
+                       } else if (!regs_read) {
+                               /* read gpr registers at once (but only one 
time in this loop) */
+                               retval = rv12_jtag_read_regs(rv12, 
rv12->core_regs);
+                               if (retval != ERROR_OK)
+                                       return retval;
+                               /* prevent next reads in this loop */
+                               regs_read = 1;
+                       }
+                       /* We've just updated the core_reg[i], now update
+                               the core cache */
+                       rv12_read_core_reg(target, i);
+               }
+       }
+
+       return ERROR_OK;
+}
+
+static int rv12_restore_context(struct target *target)
+{
+       struct rv12_common *rv12 = target_to_rv12(target);
+       struct rl_du *du_core = rl_to_du(rv12);
+       int reg_write = 0;
+       int retval;
+
+       LOG_DEBUG("-");
+
+       for (int i = 0; i < GDB_REGNO_FPR0; i++) {
+               if (rv12->core_cache->reg_list[i].dirty) {
+                       rv12_write_core_reg(target, i);
+
+                       if (i == GDB_REGNO_PC) {
+                               retval = du_core->rl_jtag_write_cpu(&rv12->jtag,
+                                               /* Write the PC to the NPC reg 
*/
+                                               (GROUP_GPRS + 0x200), 1,
+                                               &rv12->core_regs[i]);
+                               if (retval != ERROR_OK) {
+                                       LOG_ERROR("Error while restoring 
context");
+                                       return retval;
+                               }
+                       } else
+                               reg_write = 1;
+               }
+       }
+
+       if (reg_write) {
+               /* read gpr registers at once (but only one time in this loop) 
*/
+               retval = rv12_jtag_write_regs(rv12, rv12->core_regs);
+               if (retval != ERROR_OK) {
+                       LOG_ERROR("Error while restoring context");
+                       return retval;
+               }
+       }
+
+       return ERROR_OK;
+}
+
+static int rv12_read_core_reg(struct target *target, int num)
+{
+       struct rv12_common *rv12 = target_to_rv12(target);
+       struct rl_du *du_core = rl_to_du(rv12);
+       uint32_t reg_value;
+
+       LOG_DEBUG("-");
+
+       if ((num < 0) || (num >= rv12->nb_regs))
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       if ((num >= 0) && (num < GDB_REGNO_COUNT)) {
+               reg_value = rv12->core_regs[num];
+               buf_set_u32(rv12->core_cache->reg_list[num].value, 0, 32, 
reg_value);
+               LOG_DEBUG("Read core reg %i value 0x%08" PRIx32, num, 
reg_value);
+               rv12->core_cache->reg_list[num].valid = true;
+               rv12->core_cache->reg_list[num].dirty = false;
+       } else  {
+               /* This is an spr, always read value from HW */
+               int retval = du_core->rl_jtag_read_cpu(&rv12->jtag,
+                                                        
rv12->arch_info[num].spr_num, 1, &reg_value);
+               if (retval != ERROR_OK) {
+                       LOG_ERROR("Error while reading spr 0x%08" PRIx32, 
rv12->arch_info[num].spr_num);
+                       return retval;
+               }
+               buf_set_u32(rv12->core_cache->reg_list[num].value, 0, 32, 
reg_value);
+               LOG_DEBUG("Read spr reg %i value 0x%08" PRIx32, num, reg_value);
+       }
+
+       return ERROR_OK;
+}
+
+static int rv12_write_core_reg(struct target *target, int num)
+{
+       struct rv12_common *rv12 = target_to_rv12(target);
+
+       LOG_DEBUG("-");
+
+       if ((num < 0) || (num >= GDB_REGNO_COUNT))
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       uint32_t reg_value = buf_get_u32(rv12->core_cache->reg_list[num].value, 
0, 32);
+       rv12->core_regs[num] = reg_value;
+       LOG_DEBUG("Write core reg %i value 0x%08" PRIx32, num, reg_value);
+       rv12->core_cache->reg_list[num].valid = true;
+       rv12->core_cache->reg_list[num].dirty = false;
+
+       return ERROR_OK;
+}
+
+static int rv12_get_core_reg(struct reg *reg)
+{
+       struct rv12_core_reg *rv12_reg = reg->arch_info;
+       struct target *target = rv12_reg->target;
+
+       LOG_DEBUG("-");
+
+       if (target->state != TARGET_HALTED)
+               return ERROR_TARGET_NOT_HALTED;
+
+       /* First get the register before returning the values */
+       int retval = rv12_save_context(target);
+
+       if (retval != ERROR_OK) {
+               LOG_ERROR("Error while calling rv12_save_context");
+               return retval;
+       }
+
+       return rv12_read_core_reg(target, rv12_reg->list_num);
+}
+
+static int rv12_set_core_reg(struct reg *reg, uint8_t *buf)
+{
+       struct rv12_core_reg *rv12_reg = reg->arch_info;
+       struct target *target = rv12_reg->target;
+       struct rv12_common *rv12 = target_to_rv12(target);
+       struct rl_du *du_core = rl_to_du(rv12);
+       uint32_t value = buf_get_u32(buf, 0, 32);
+
+       LOG_DEBUG("-");
+       LOG_DEBUG("Set core reg: %u, value: %08x\n", rv12_reg->list_num, value);
+
+       if (target->state != TARGET_HALTED)
+               return ERROR_TARGET_NOT_HALTED;
+
+       /* If the register is lower then the Floating Point registers, write it 
to the cache */
+       /* At the moment a continue or a step is provoked, it shall be written 
to the CPU */
+       if (rv12_reg->list_num < GDB_REGNO_FPR0) {
+               
buf_set_u32(rv12->core_cache->reg_list[rv12_reg->list_num].value, 0, 32, value);
+               rv12->core_cache->reg_list[rv12_reg->list_num].dirty = true;
+               rv12->core_cache->reg_list[rv12_reg->list_num].valid = true;
+       } else {
+               /* Non cached register, so write to CPU immediately */
+               int retval = du_core->rl_jtag_write_cpu(&rv12->jtag, 
rv12_reg->spr_num, 1, &value);
+
+               if (retval != ERROR_OK) {
+                       LOG_ERROR("Error while writing spr 0x%08" PRIx32, 
rv12_reg->spr_num);
+                       return retval;
+               }
+       }
+
+       return ERROR_OK;
+}
+
+static const struct reg_arch_type rv12_reg_type = {
+       .get = rv12_get_core_reg,
+       .set = rv12_set_core_reg,
+};
+
+static struct reg_cache *rv12_build_reg_cache(struct target *target)
+{
+       struct rv12_common *rv12 = target_to_rv12(target);
+       struct reg_cache **cache_p = 
register_get_last_cache_p(&target->reg_cache);
+       struct reg_cache *cache = malloc(sizeof(struct reg_cache));
+       struct reg *reg_list = calloc(rv12->nb_regs, sizeof(struct reg));
+       struct rv12_core_reg *arch_info = malloc((rv12->nb_regs) * 
sizeof(struct rv12_core_reg));
+       struct reg_feature *feature;
+
+       LOG_DEBUG("-");
+
+       /* Build the process context cache */
+       cache->name = "Roa Logic RISC-V Registers";
+       cache->next = NULL;
+       cache->reg_list = reg_list;
+       cache->num_regs = rv12->nb_regs;
+       (*cache_p) = cache;
+       rv12->core_cache = cache;
+       rv12->arch_info = arch_info;
+
+       for (int i = 0; i < rv12->nb_regs; i++) {
+               arch_info[i] = rv12_core_reg_list_arch_info[i];
+               arch_info[i].target = target;
+               arch_info[i].rv12_common = rv12;
+               reg_list[i].name = rv12_core_reg_list_arch_info[i].name;
+
+               feature = malloc(sizeof(struct reg_feature));
+               feature->name = rv12_core_reg_list_arch_info[i].feature;
+               reg_list[i].feature = feature;
+
+               reg_list[i].group = rv12_core_reg_list_arch_info[i].group;
+               reg_list[i].size = 32;
+               reg_list[i].value = calloc(1, 4);
+               reg_list[i].dirty = false;
+               reg_list[i].valid = false;
+               reg_list[i].type = &rv12_reg_type;
+               reg_list[i].arch_info = &arch_info[i];
+               reg_list[i].number = i;
+               reg_list[i].exist = true;
+       }
+
+       return cache;
+}
+
+static int rv12_debug_entry(struct target *target)
+{
+       LOG_DEBUG("-");
+       uint32_t value = 0;
+
+       int retval = rv12_save_context(target);
+       if (retval != ERROR_OK) {
+               LOG_ERROR("Error while calling rv12_save_context");
+               return retval;
+       }
+
+       struct rv12_common *rv12 = target_to_rv12(target);
+       struct rl_du *du_core = rl_to_du(rv12);
+       uint32_t addr = rv12->core_regs[GDB_REGNO_PC];
+
+       /* value |= DBG_IE_INST_MISALIGNED | DBG_IE_ILLEGAL | DBG_IE_BREAKPOINT 
|
+       DBG_IE_LOAD_MISALIGNED | DBG_IE_AMO_MISALIGNED; */
+       value |= DBG_IE_BREAKPOINT;
+
+       /* printf("Set DBG IE with value: %08x\n", value); */
+       if (du_core->rl_jtag_write_cpu(&rv12->jtag, (GROUP_DBG + 0x02), 1, 
&value) != ERROR_OK) {
+               LOG_ERROR("Error: cannot set DBG IE reg\n");
+               return ERROR_FAIL;
+       }
+
+       if (breakpoint_find(target, addr)) {
+               buf_set_u32(rv12->core_cache->reg_list[GDB_REGNO_PC].value, 0, 
32, addr);
+               rv12->core_cache->reg_list[GDB_REGNO_PC].dirty = true;
+               rv12->core_cache->reg_list[GDB_REGNO_PC].valid = true;
+       }
+
+       return retval;
+}
+
+static int rv12_halt(struct target *target)
+{
+       struct rv12_common *rv12 = target_to_rv12(target);
+       struct rl_du *du_core = rl_to_du(rv12);
+
+       LOG_DEBUG("target->state: %s", target_state_name(target));
+
+       if (target->state == TARGET_HALTED) {
+               LOG_DEBUG("Target was already halted");
+               return ERROR_OK;
+       }
+
+       if (target->state == TARGET_UNKNOWN)
+               LOG_WARNING("Target was in unknown state when halt was 
requested");
+
+       if (target->state == TARGET_RESET) {
+               if ((jtag_get_reset_config() & RESET_SRST_PULLS_TRST) && 
jtag_get_srst()) {
+                       LOG_ERROR("Can't request a halt while in reset if nSRST 
pulls nTRST");
+                       return ERROR_TARGET_FAILURE;
+               } else {
+                       target->debug_reason = DBG_REASON_DBGRQ;
+                       return ERROR_OK;
+               }
+       }
+
+       int retval = du_core->rl_cpu_stall(&rv12->jtag, CPU_STALL);
+       if (retval != ERROR_OK) {
+               LOG_ERROR("Impossible to stall the CPU");
+               return retval;
+       }
+
+       target->debug_reason = DBG_REASON_DBGRQ;
+
+       return ERROR_OK;
+}
+
+static int rl_is_cpu_running(struct target *target, int *running)
+{
+       struct rv12_common *rv12 = target_to_rv12(target);
+       struct rl_du *du_core = rl_to_du(rv12);
+       int retval;
+       int tries = 0;
+       const int RETRIES_MAX = 5;
+
+       /* Have a retry loop to determine of the CPU is running.
+          If target has been hard reset for any reason, it might take a couple
+          of goes before it's ready again.
+       */
+       while (tries < RETRIES_MAX) {
+
+               tries++;
+
+               retval = du_core->rl_is_cpu_running(&rv12->jtag, running);
+               if (retval != ERROR_OK) {
+                       LOG_WARNING("Debug IF CPU control reg read failure.");
+                       /* Try once to restart the JTAG infrastructure -
+                          quite possibly the board has just been reset. */
+                       LOG_WARNING("Resetting JTAG TAP state and reconnecting 
to debug IF.");
+                       du_core->rl_jtag_init(&rv12->jtag);
+
+                       LOG_WARNING("...attempt %d of %d", tries, RETRIES_MAX);
+
+                       alive_sleep(2);
+
+                       continue;
+               } else
+                       return ERROR_OK;
+       }
+
+       LOG_ERROR("Could not re-establish communication with target");
+       return retval;
+}
+
+static int rv12_poll(struct target *target)
+{
+       int retval;
+       int running;
+
+       retval = rl_is_cpu_running(target, &running);
+       if (retval != ERROR_OK) {
+               LOG_ERROR("Error while calling rl_is_cpu_running");
+               return retval;
+       }
+
+       /* check for processor halted */
+       if (!running) {
+               /* It's actually stalled, so update our software's state */
+               if ((target->state == TARGET_RUNNING) ||
+                       (target->state == TARGET_RESET)) {
+
+                       target->state = TARGET_HALTED;
+
+                       retval = rv12_debug_entry(target);
+                       if (retval != ERROR_OK) {
+                               LOG_ERROR("Error while calling 
rv12_debug_entry");
+                               return retval;
+                       }
+
+                       target_call_event_callbacks(target, 
TARGET_EVENT_HALTED);
+               } else if (target->state == TARGET_DEBUG_RUNNING) {
+                       target->state = TARGET_HALTED;
+
+                       retval = rv12_debug_entry(target);
+                       if (retval != ERROR_OK) {
+                               LOG_ERROR("Error while calling 
rv12_debug_entry");
+                               return retval;
+                       }
+
+                       target_call_event_callbacks(target, 
TARGET_EVENT_DEBUG_HALTED);
+               }
+       } else { /* ... target is running */
+
+               /* If target was supposed to be stalled, stall it again */
+               if  (target->state == TARGET_HALTED) {
+                       target->state = TARGET_RUNNING;
+
+                       retval = rv12_halt(target);
+                       if (retval != ERROR_OK) {
+                               LOG_ERROR("Error while calling rv12_halt");
+                               return retval;
+                       }
+
+                       retval = rv12_debug_entry(target);
+                       if (retval != ERROR_OK) {
+                               LOG_ERROR("Error while calling 
rv12_debug_entry");
+                               return retval;
+                       }
+
+                       target_call_event_callbacks(target, 
TARGET_EVENT_DEBUG_HALTED);
+               }
+
+               target->state = TARGET_RUNNING;
+
+       }
+
+       return ERROR_OK;
+}
+
+static int rv12_assert_reset(struct target *target)
+{
+       struct rv12_common *rv12 = target_to_rv12(target);
+       struct rl_du *du_core = rl_to_du(rv12);
+
+       LOG_DEBUG("Assert reset\n");
+       int retval = du_core->rl_cpu_reset(&rv12->jtag, CPU_RESET);
+
+       if (retval != ERROR_OK) {
+               LOG_ERROR("Error while asserting RESET");
+               return retval;
+       }
+
+       return ERROR_OK;
+}
+
+static int rv12_deassert_reset(struct target *target)
+{
+       struct rv12_common *rv12 = target_to_rv12(target);
+       struct rl_du *du_core = rl_to_du(rv12);
+
+       LOG_DEBUG("-");
+       int retval = du_core->rl_cpu_reset(&rv12->jtag, CPU_NOT_RESET);
+       if (retval != ERROR_OK) {
+               LOG_ERROR("Error while deasserting RESET");
+               return retval;
+       }
+
+       /* Set the correpsponding debug flags again, since those are cleared */
+       retval = rv12_debug_entry(target);
+       if (retval != ERROR_OK) {
+               LOG_ERROR("Error while calling rv12_debug_entry");
+               return retval;
+       }
+
+       return ERROR_OK;
+}
+
+static int rv12_soft_reset_halt(struct target *target)
+{
+       struct rv12_common *rv12 = target_to_rv12(target);
+       struct rl_du *du_core = rl_to_du(rv12);
+
+       LOG_DEBUG("Soft reset\n");
+       int retval = du_core->rl_cpu_stall(&rv12->jtag, CPU_STALL);
+
+       if (retval != ERROR_OK) {
+               LOG_ERROR("Error while stalling the CPU");
+               return retval;
+       }
+
+       retval = rv12_assert_reset(target);
+       if (retval != ERROR_OK)
+               return retval;
+
+       retval = rv12_deassert_reset(target);
+       if (retval != ERROR_OK)
+               return retval;
+
+       return ERROR_OK;
+}
+
+static int rv12_resume_or_step(struct target *target, int current,
+                              uint32_t address, int handle_breakpoints,
+                              int debug_execution, int step)
+{
+       struct rv12_common *rv12 = target_to_rv12(target);
+       struct rl_du *du_core = rl_to_du(rv12);
+       struct breakpoint *breakpoint = NULL;
+       uint32_t resume_pc = 0;
+       uint32_t tempReg = 0;
+       uint32_t tempMStatusReg = 0;
+       bool globalInterruptActive = false;
+       int retval;
+
+       LOG_DEBUG("Addr: 0x%" PRIx32 ", stepping: %s, handle breakpoints %s\n",
+                 address, step ? "yes" : "no", handle_breakpoints ? "yes" : 
"no");
+
+       if (target->state != TARGET_HALTED) {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       /*  Free memory */
+       if (!debug_execution)
+               target_free_all_working_areas(target);
+
+       /* current ? continue on current pc : continue at <address> */
+       if (!current)
+               buf_set_u32(rv12->core_cache->reg_list[GDB_REGNO_PC].value, 0, 
32, address);
+
+       retval = rv12_restore_context(target);
+       if (retval != ERROR_OK) {
+               LOG_ERROR("Error while calling rv12_restore_context");
+               return retval;
+       }
+
+       /* Clear DBG HIT reg */
+       tempReg = 0;
+
+       if (du_core->rl_jtag_write_cpu(&rv12->jtag, (GROUP_DBG + 0x01), 1, 
&tempReg) != ERROR_OK) {
+               printf("Error: cannot clear HIT reg\n");
+               return ERROR_FAIL;
+       }
+
+       if (du_core->rl_jtag_read_cpu(&rv12->jtag, (GROUP_DBG + 0x00), 1, 
&tempReg) != ERROR_OK) {
+               printf("Error: cannot read DBG ctrl reg\n");
+               return ERROR_FAIL;
+       }
+
+       if (du_core->rl_jtag_read_cpu(&rv12->jtag, (GROUP_CSR  + CSR_MSTATUS), 
1, &tempMStatusReg) != ERROR_OK) {
+               printf("Error: cannot read MSTATUS reg\n");
+               return ERROR_FAIL;
+       }
+
+       if (tempMStatusReg & DBG_CSR_MSTASUS_MIE)
+               globalInterruptActive = true;
+
+       if (step) {
+               /* Set the single step trigger in Debug Mode Register 1 (DMR1) 
*/
+               tempReg |= DBG_CTRL_SINGLE_STEP_TRACE;
+
+               if (globalInterruptActive) {
+                       tempMStatusReg &= ~DBG_CSR_MSTASUS_MIE;
+
+                       if (du_core->rl_jtag_write_cpu(&rv12->jtag, (GROUP_CSR  
+ CSR_MSTATUS), 1, &tempMStatusReg) != ERROR_OK) {
+                               printf("Error: cannot read MSTATUS reg\n");
+                               return ERROR_FAIL;
+                       }
+               }
+       } else
+               /* Clear the single step trigger in Debug Mode Register 1 
(DMR1) */
+               tempReg &= ~DBG_CTRL_SINGLE_STEP_TRACE;
+
+       if (du_core->rl_jtag_write_cpu(&rv12->jtag, (GROUP_DBG + 0x00), 1, 
&tempReg) != ERROR_OK) {
+               printf("Error: cannot write DBG ctrl reg\n");
+               return ERROR_FAIL;
+       }
+
+       resume_pc = buf_get_u32(rv12->core_cache->reg_list[GDB_REGNO_PC].value, 
0, 32);
+
+       /* The front-end may request us not to handle breakpoints */
+       if (handle_breakpoints) {
+               /* Single step past breakpoint at current address */
+               breakpoint = breakpoint_find(target, resume_pc);
+               if (breakpoint) {
+                       LOG_DEBUG("Unset breakpoint at 0x%08" TARGET_PRIxADDR, 
breakpoint->address);
+                       retval = rv12_remove_breakpoint(target, breakpoint);
+                       if (retval != ERROR_OK)
+                               return retval;
+               }
+       }
+
+       /* Unstall time */
+       retval = du_core->rl_cpu_stall(&rv12->jtag, CPU_UNSTALL);
+       if (retval != ERROR_OK) {
+               LOG_ERROR("Error while unstalling the CPU");
+               return retval;
+       }
+
+       if (step) {
+               target->debug_reason = DBG_REASON_SINGLESTEP;
+
+               if (globalInterruptActive) {
+                       if (du_core->rl_jtag_read_cpu(&rv12->jtag, (GROUP_CSR  
+ CSR_MSTATUS), 1, &tempMStatusReg) != ERROR_OK) {
+                               printf("Error: cannot read MSTATUS reg\n");
+                               return ERROR_FAIL;
+                       }
+                       tempMStatusReg |= DBG_CSR_MSTASUS_MIE;
+
+                       if (du_core->rl_jtag_write_cpu(&rv12->jtag, (GROUP_CSR  
+ CSR_MSTATUS), 1, &tempMStatusReg) != ERROR_OK) {
+                               printf("Error: cannot read MSTATUS reg\n");
+                               return ERROR_FAIL;
+                       }
+               }
+       } else
+               target->debug_reason = DBG_REASON_NOTHALTED;
+
+       /* Invalidate current registers in local cache */
+       /* Nothing to do with CPU cache */
+       register_cache_invalidate(rv12->core_cache);
+
+       if (!debug_execution) {
+               target->state = TARGET_RUNNING;
+               target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
+               LOG_DEBUG("Target resumed at 0x%08" PRIx32, resume_pc);
+       } else {
+               target->state = TARGET_DEBUG_RUNNING;
+               target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED);
+               LOG_DEBUG("Target debug resumed at 0x%08" PRIx32, resume_pc);
+       }
+
+       return ERROR_OK;
+}
+
+static int rv12_resume(struct target *target, int current,
+                               target_addr_t address, int handle_breakpoints,
+                               int debug_execution)
+{
+       return rv12_resume_or_step(target, current, address,
+                                  handle_breakpoints,
+                                  debug_execution,
+                                  NO_SINGLE_STEP);
+}
+
+static int rv12_step(struct target *target, int current,
+                    target_addr_t address, int handle_breakpoints)
+{
+       return rv12_resume_or_step(target, current, address,
+                                  handle_breakpoints,
+                                  0,
+                                  SINGLE_STEP);
+
+}
+
+static int rv12_add_breakpoint(struct target *target,
+                              struct breakpoint *breakpoint)
+{
+       struct rv12_common *rv12 = target_to_rv12(target);
+       struct rl_du *du_core = rl_to_du(rv12);
+       uint32_t data;
+       int retval;
+
+       LOG_DEBUG("Adding breakpoint: addr 0x%08" TARGET_PRIxADDR ", len %d, 
type %d, set: %d, id: %" PRIu32,
+                 breakpoint->address, breakpoint->length, breakpoint->type,
+                 breakpoint->is_set, breakpoint->unique_id);
+
+       /* Only support SW breakpoints for now. */
+       if (breakpoint->type != BKPT_SOFT) {
+               LOG_ERROR("HW breakpoints not supported for now\n");
+               return ERROR_FAIL;
+       }
+
+       if (breakpoint->length != 2 && breakpoint->length != 4) {
+               LOG_ERROR("Breakpoint unsupported length\n");
+               return ERROR_FAIL;
+       }
+
+       if (breakpoint->length == 2) {
+               /* Read and save the instruction */
+               retval = du_core->rl_jtag_read_memory(&rv12->jtag,
+                                               breakpoint->address,
+                                               2,
+                                               1,
+                                               (uint8_t *)&data);
+       } else {
+               /* Read and save the instruction */
+               retval = du_core->rl_jtag_read_memory(&rv12->jtag,
+                                               breakpoint->address,
+                                               4,
+                                               1,
+                                               (uint8_t *)&data);
+       }
+
+       if (retval != ERROR_OK) {
+               LOG_ERROR("Error while reading the instruction at 0x%08" 
TARGET_PRIxADDR,
+                          breakpoint->address);
+               return retval;
+       }
+
+       free(breakpoint->orig_instr);
+
+       breakpoint->orig_instr = malloc(breakpoint->length);
+       memcpy(breakpoint->orig_instr, &data, breakpoint->length);
+
+       if (breakpoint->length == 2) {
+               uint16_t rv12_trap_insn16 = RV_EBREAK16_INSTR;
+               /*target_buffer_set_u32(target, rv12_trap_insn, 
RV_EBREAK16_INSTR); */
+               retval = du_core->rl_jtag_write_memory(&rv12->jtag,
+                                               breakpoint->address,
+                                               2,
+                                               1,
+                                               (uint8_t *)&rv12_trap_insn16);
+       } else {
+               uint32_t rv12_trap_insn = RV_EBREAK_INSTR;
+               /*target_buffer_set_u32(target, rv12_trap_insn, 
RV_EBREAK_INSTR); */
+               retval = du_core->rl_jtag_write_memory(&rv12->jtag,
+                                               breakpoint->address,
+                                               4,
+                                               1,
+                                               (uint8_t *)&rv12_trap_insn);
+       }
+
+       return ERROR_OK;
+}
+
+static int rv12_remove_breakpoint(struct target *target,
+                                 struct breakpoint *breakpoint)
+{
+       struct rv12_common *rv12 = target_to_rv12(target);
+       struct rl_du *du_core = rl_to_du(rv12);
+       int retval;
+
+       LOG_DEBUG("Removing breakpoint: addr 0x%08" TARGET_PRIxADDR ", len %d, 
type %d, set: %d, id: %" PRIu32,
+                 breakpoint->address, breakpoint->length, breakpoint->type,
+                 breakpoint->is_set, breakpoint->unique_id);
+
+       /* Only support SW breakpoints for now. */
+       if (breakpoint->type != BKPT_SOFT) {
+               LOG_ERROR("HW breakpoints not supported for now\n");
+               return ERROR_FAIL;
+       }
+
+       if (breakpoint->length != 2 && breakpoint->length != 4) {
+               LOG_ERROR("Breakpoint unsupported length\n");
+               return ERROR_FAIL;
+       }
+
+       if (breakpoint->length == 2) {
+               /* Replace the removed instruction */
+               retval = du_core->rl_jtag_write_memory(&rv12->jtag,
+                                               breakpoint->address,
+                                               2,
+                                               1,
+                                               breakpoint->orig_instr);
+       } else {
+               /* Replace the removed instruction */
+               retval = du_core->rl_jtag_write_memory(&rv12->jtag,
+                                               breakpoint->address,
+                                               4,
+                                               1,
+                                               breakpoint->orig_instr);
+       }
+
+
+       if (retval != ERROR_OK) {
+               LOG_ERROR("Error while writing back the instruction at 0x%08" 
TARGET_PRIxADDR,
+                          breakpoint->address);
+               return retval;
+       }
+
+       return ERROR_OK;
+}
+
+static int rv12_add_watchpoint(struct target *target,
+                              struct watchpoint *watchpoint)
+{
+       LOG_ERROR("%s: implement me", __func__);
+       return ERROR_OK;
+}
+
+static int rv12_remove_watchpoint(struct target *target,
+                                 struct watchpoint *watchpoint)
+{
+       LOG_ERROR("%s: implement me", __func__);
+       return ERROR_OK;
+}
+
+static int rv12_read_memory(struct target *target, target_addr_t address,
+               uint32_t size, uint32_t count, uint8_t *buffer)
+{
+       struct rv12_common *rv12 = target_to_rv12(target);
+       struct rl_du *du_core = rl_to_du(rv12);
+
+       LOG_DEBUG("Read memory at 0x%08" TARGET_PRIxADDR ", size: %" PRIu32 ", 
count: 0x%08" PRIx32, address, size, count);
+
+       if (target->state != TARGET_HALTED) {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+
+       /*TODO: 64bit accesses (for 64bit CPU) */
+       /* Sanitize arguments */
+       if (((size != 4) && (size != 2) && (size != 1)) || (count == 0) || 
!buffer) {
+               LOG_ERROR("Bad arguments");
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+
+       if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 
0x1u))) {
+               LOG_ERROR("Unaligned memory access not supported");
+               return ERROR_TARGET_UNALIGNED_ACCESS;
+       }
+
+       return du_core->rl_jtag_read_memory(&rv12->jtag, address, size, count, 
buffer);
+}
+
+static int rv12_write_memory(struct target *target, target_addr_t address,
+               uint32_t size, uint32_t count, const uint8_t *buffer)
+{
+       struct rv12_common *rv12 = target_to_rv12(target);
+       struct rl_du *du_core = rl_to_du(rv12);
+
+       LOG_DEBUG("Write memory at 0x%08" TARGET_PRIxADDR ", size: %" PRIu32 ", 
count: 0x%08" PRIx32, address, size, count);
+
+       if (target->state != TARGET_HALTED) {
+               LOG_WARNING("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+
+       /*TODO: 64bit accesses for 64bit CPU */
+       /* Sanitize arguments */
+       if (((size != 4) && (size != 2) && (size != 1)) || (count == 0) || 
!buffer) {
+               LOG_ERROR("Bad arguments");
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+
+       if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 
0x1u))) {
+               LOG_ERROR("Unaligned memory access not supported");
+               return ERROR_TARGET_UNALIGNED_ACCESS;
+       }
+
+       return du_core->rl_jtag_write_memory(&rv12->jtag, address, size, count, 
buffer);
+}
+
+static int rv12_init_target(struct command_context *cmd_ctx,
+               struct target *target)
+{
+       struct rv12_common *rv12 = target_to_rv12(target);
+       struct rl_du *du_core = rl_to_du(rv12);
+       struct rl_jtag *jtag = &rv12->jtag;
+
+       if (!du_core) {
+               LOG_ERROR("No debug unit selected");
+               return ERROR_FAIL;
+       }
+
+       if (!jtag->tap_ip) {
+               LOG_ERROR("No tap selected");
+               return ERROR_FAIL;
+       }
+
+       rv12->jtag.tap = target->tap;
+       rv12->jtag.rl_jtag_inited = 0;
+       rv12->jtag.rl_jtag_module_selected = -1;
+       rv12->jtag.target = target;
+
+       rv12_build_reg_cache(target);
+
+       return ERROR_OK;
+}
+
+static int rv12_target_create(struct target *target, Jim_Interp *interp)
+{
+       if (!target->tap)
+               return ERROR_FAIL;
+
+       struct rv12_common *rv12 = calloc(1, sizeof(struct rv12_common));
+
+       target->arch_info = rv12;
+
+       rv12_create_reg_list(target);
+
+       rl_universal_tap_register();
+
+       rl_dbg_adv_register();
+
+       return ERROR_OK;
+}
+
+static int rv12_examine(struct target *target)
+{
+       struct rv12_common *rv12 = target_to_rv12(target);
+       struct rl_du *du_core = rl_to_du(rv12);
+
+       if (!target_was_examined(target)) {
+
+               target_set_examined(target);
+
+               int running;
+
+               int retval = du_core->rl_is_cpu_running(&rv12->jtag, &running);
+               if (retval != ERROR_OK) {
+                       LOG_ERROR("Couldn't read the CPU state");
+                       return retval;
+               } else {
+                       if (running)
+                               target->state = TARGET_RUNNING;
+                       else {
+                               LOG_DEBUG("Target is halted");
+
+                               /* This is the first time we examine the target,
+                                * it is stalled and we don't know why. Let's
+                                * assume this is because of a debug reason.
+                                */
+                               if (target->state == TARGET_UNKNOWN)
+                                       target->debug_reason = DBG_REASON_DBGRQ;
+
+                               target->state = TARGET_HALTED;
+                       }
+               }
+       }
+
+       return ERROR_OK;
+}
+
+static int rv12_arch_state(struct target *target)
+{
+       return ERROR_OK;
+}
+
+static int rv12_get_gdb_reg_list(struct target *target, struct reg 
**reg_list[],
+                         int *reg_list_size, enum target_register_class 
reg_class)
+{
+       struct rv12_common *rv12 = target_to_rv12(target);
+
+       if (reg_class == REG_CLASS_GENERAL) {
+               /* We will have this called whenever GDB connects. */
+               int retval = rv12_save_context(target);
+               if (retval != ERROR_OK) {
+                       LOG_ERROR("Error while calling rv12_save_context");
+                       return retval;
+               }
+
+               /*TODO Load FPR when the CPU has a FPU */
+               *reg_list_size = GDB_REGNO_FPR0;
+               /* this is free()'d back in gdb_server.c's 
gdb_get_register_packet() */
+               *reg_list = malloc((*reg_list_size) * sizeof(struct reg *));
+
+               for (int i = 0; i < GDB_REGNO_FPR0; i++)
+                       (*reg_list)[i] = &rv12->core_cache->reg_list[i];
+       } else {
+               *reg_list_size = rv12->nb_regs;
+               *reg_list = malloc((*reg_list_size) * sizeof(struct reg *));
+
+               for (int i = 0; i < rv12->nb_regs; i++)
+                       (*reg_list)[i] = &rv12->core_cache->reg_list[i];
+       }
+
+       return ERROR_OK;
+
+}
+
+static int rv12_get_gdb_fileio_info(struct target *target, struct 
gdb_fileio_info *fileio_info)
+{
+       return ERROR_FAIL;
+}
+
+static int rv12_checksum_memory(struct target *target, target_addr_t address,
+               uint32_t count, uint32_t *checksum)
+{
+       return ERROR_FAIL;
+}
+
+static int rv12_profiling(struct target *target, uint32_t *samples,
+               uint32_t max_num_samples, uint32_t *num_samples, uint32_t 
seconds)
+{
+       struct timeval timeout, now;
+       struct rv12_common *rv12 = target_to_rv12(target);
+       struct rl_du *du_core = rl_to_du(rv12);
+       int retval = ERROR_OK;
+
+       gettimeofday(&timeout, NULL);
+       timeval_add_time(&timeout, seconds, 0);
+
+       LOG_INFO("Starting rv12 profiling. Sampling npc as fast as we can...");
+
+       /* Make sure the target is running */
+       target_poll(target);
+       if (target->state == TARGET_HALTED)
+               retval = target_resume(target, 1, 0, 0, 0);
+
+       if (retval != ERROR_OK) {
+               LOG_ERROR("Error while resuming target");
+               return retval;
+       }
+
+       uint32_t sample_count = 0;
+
+       for (;;) {
+               uint32_t reg_value;
+               retval = du_core->rl_jtag_read_cpu(&rv12->jtag, (GROUP_GPRS + 
0x201) /* PPC */, 1, &reg_value);
+               if (retval != ERROR_OK) {
+                       LOG_ERROR("Error while reading NPC");
+                       return retval;
+               }
+
+               samples[sample_count++] = reg_value;
+
+               gettimeofday(&now, NULL);
+               if ((sample_count >= max_num_samples) || timeval_compare(&now, 
&timeout) > 0) {
+                       LOG_INFO("Profiling completed. %" PRIu32 " samples.", 
sample_count);
+                       break;
+               }
+       }
+
+       *num_samples = sample_count;
+       return retval;
+}
+
+static int rv12_soc_test_sram(struct target *target)
+{
+       uint32_t baseAddress = 0x00010000;
+       uint32_t ins;
+       uint32_t insn[9];
+       uint32_t address;
+
+       insn[0] = 0x11112222;
+       insn[1] = 0x33334444;
+       insn[2] = 0x55556666;
+       insn[3] = 0x77778888;
+       insn[4] = 0x9999aaaa;
+       insn[5] = 0xbbbbcccc;
+       insn[6] = 0xddddeeee;
+       insn[7] = 0xffff0000;
+       insn[8] = 0xdedababa;
+
+       if (rv12_poll(target) != ERROR_OK) {
+               printf("Error while polling target\n");
+               return ERROR_FAIL;
+       }
+
+       for (int i = 0; i < 9; i++) {
+               address = baseAddress + (i * 4);
+
+               printf("Write address: %08x, with: %08x\n", address, insn[i]);
+               if (rv12_write_memory(target, address, 4, 1, (uint8_t 
*)&insn[i]) != ERROR_OK) {
+                       printf("Error: Cannot write memory\n");
+                       return ERROR_FAIL;
+               }
+       }
+
+       for (int i = 0; i < 9; i++) {
+               address = baseAddress + (i * 4);
+
+               printf("Read address: %08x\n", address);
+               if (rv12_read_memory(target, address, 4, 1, (uint8_t *)&ins) == 
ERROR_OK) {
+                       if (ins != insn[i]) {
+                               printf("Error: Expected: %08x, received: 
%08x\n", insn[i], ins);
+                               return ERROR_FAIL;
+                       }
+               } else {
+                       printf("Error: Reading memory\n");
+                       return ERROR_FAIL;
+               }
+       }
+
+       return ERROR_OK;
+}
+
+static int rv12_soc_test_cpu(struct target *target)
+{
+       uint32_t baseAddress = 0x00010000;
+       uint32_t insn[11];
+       uint32_t illIns = 0x00000000;
+       uint32_t address;
+       uint32_t r1, npc, ppc;
+       int state;
+
+       struct rv12_common *rv12 = target_to_rv12(target);
+       struct rl_du *du_core = rl_jtag_to_du(&rv12->jtag);
+
+       printf("\n-- Testing rv12-SoC CPU\n");
+       printf("writing instructions\n");
+
+       insn[0]  = 0x00004033; /* xor   x0,x0,x0               */
+       insn[1]  = 0x00000093; /* addi  x1,x0,0x0              */
+       insn[2]  = 0x00010137; /* lui   x2,0x00010  (RAM_BASE) */
+       insn[3]  = 0x03016113; /* ori   x2,x2,0x30             */
+       insn[4]  = 0x00108093; /* addi  x1,x1,1                */
+       insn[5]  = 0x00108093; /* addi  x1,x1,1                */
+       insn[6]  = 0x00112023; /* sw    0(x2),x1               */
+       insn[7]  = 0x00108093; /* addi  x1,x1,1                */
+       insn[8]  = 0x00012183; /* lw    x3,0(x2)               */
+       insn[9]  = 0x003080b3; /* add   x1,x1,x3               */
+       insn[10] = 0xfe9ff06f; /* j     (base+0x10)            */
+
+       if (rv12_poll(target) != ERROR_OK)
+               printf("Error while polling target\n");
+
+       for (int i = 0; i < 11; i++) {
+               address = baseAddress + (i * 4);
+               if (rv12_write_memory(target, address, 4, 1, (uint8_t 
*)&insn[i]) != ERROR_OK) {
+                       printf("Error: Cannot write memory\n");
+                       return ERROR_FAIL;
+               }
+       }
+
+       /* Fill rest of memory with 0x00 (C.ILLEGAL). Avoid CPU going nuts on 
0xxxxxx */
+       for (uint32_t i = baseAddress+0x2c; i < baseAddress + 0x4c; i = i + 4) {
+               if (rv12_write_memory(target, i, 4, 1, (uint8_t *)&illIns) != 
ERROR_OK) {
+                       printf("Error: Cannot write memory\n");
+                       return ERROR_FAIL;
+               }
+       }
+
+       printf("Setting up CPU\n");
+
+       /*
+       * Test 1
+       */
+       printf("- Test 1, save context\n");
+
+       if (rv12_save_context(target) == ERROR_OK) {
+               printf("Success: Saved context\n");
+               for (int i = 0; i < GDB_REGNO_FPR0; i++)
+                       printf("reg: %s, value: %08x\n", 
rv12_init_reg_list[i].name, rv12->core_regs[i]);
+       } else {
+               printf("Error: cannot save context\n");
+               return ERROR_FAIL;
+       }
+
+       /*
+       * Test 2
+       */
+       printf("- Test 2, Single stepping\n");
+       printf("Write NPC: %08x\n", baseAddress);
+       if (du_core->rl_jtag_write_cpu(&rv12->jtag, (GROUP_GPRS + 0x200), 1, 
&baseAddress) != ERROR_OK) {
+               printf("Error: cannot set NPC\n");
+               return ERROR_FAIL;
+       }
+
+       for (int i = 0; i < 11; i++) {
+               if (rv12_poll(target) != ERROR_OK) {
+                       printf("Error while polling target\n");
+                       return ERROR_FAIL;
+               }
+
+               printf("Starting CPU, waiting for breakpoint...\n");
+               if (rv12_step(target, 1, 0x00, 0) != ERROR_OK) {
+                       printf("Error: stepping\n");
+                       return ERROR_FAIL;
+               }
+
+               do {
+                       if (rl_is_cpu_running(target, &state) != ERROR_OK) {
+                               LOG_ERROR("Error while calling 
rl_is_cpu_running");
+                               return ERROR_FAIL;
+                       }
+               } while (!state);
+
+               printf("Got breakpoint\n");
+       }
+
+       if (du_core->rl_jtag_read_cpu(&rv12->jtag, (GROUP_GPRS + 0x200), 1, 
&npc) != ERROR_OK) {
+               printf("Error: cannot read NPC\n");
+               return ERROR_FAIL;
+       }
+
+       if (du_core->rl_jtag_read_cpu(&rv12->jtag, (GROUP_GPRS + 0x201), 1, 
&ppc) != ERROR_OK) {
+               printf("Error: cannot read PPC\n");
+               return ERROR_FAIL;
+       }
+
+       if (du_core->rl_jtag_read_cpu(&rv12->jtag, (GROUP_RF   +  1), 1, &r1) 
!= ERROR_OK) {
+               printf("Error: cannot read PPC\n");
+               return ERROR_FAIL;
+       }
+
+       printf("Read:     npc: %08x, ppc: %08x, r1: %08x\n", npc, ppc, r1);
+       printf("Expected: npc: %08x, ppc: %08x, r1: %08x\n", 0x00010010, 
0x00010028, 5);
+
+       if (npc != 0x00010010 || ppc !=  0x00010028 || r1 != 5)
+               return ERROR_FAIL;
+       printf("Passed test 2\n");
+
+       /*
+       * Test 3
+       */
+       printf("- Test 3, Breakpoint hit\n");
+
+       struct breakpoint testBreakPoint = {0};
+
+       testBreakPoint.type = BKPT_SOFT;
+       testBreakPoint.address = (baseAddress + 0x24);
+       testBreakPoint.length = 4;
+
+       printf("Add breakpoint\n");
+       rv12_add_breakpoint(target, &testBreakPoint);
+
+       if (rv12_poll(target) != ERROR_OK) {
+               printf("Error while polling target\n");
+               return ERROR_FAIL;
+       }
+
+       if (rv12_read_memory(target, (baseAddress + 0x24), 4, 1, (uint8_t 
*)&r1) != ERROR_OK) {
+               printf("Cannot read back memory!\n");
+               return ERROR_FAIL;
+       }
+
+       if (r1 != RV_EBREAK_INSTR) {
+               printf("SW breakpoint not set!\n");
+               return ERROR_FAIL;
+       }
+
+       printf("Resuming target\n");
+       rv12_resume(target, 1, 0, 0, 0);
+
+       do {
+               if (rl_is_cpu_running(target, &state) != ERROR_OK) {
+                       LOG_ERROR("Error while calling rl_is_cpu_running");
+                       return ERROR_FAIL;
+               }
+       } while (!state);
+
+       printf("Remove breakpoint\n");
+       rv12_remove_breakpoint(target, &testBreakPoint);
+
+       if (rv12_poll(target) != ERROR_OK) {
+               printf("Error while polling target\n");
+               return ERROR_FAIL;
+       }
+
+       if (rv12_read_memory(target, (baseAddress + 0x24), 4, 1, (uint8_t 
*)&r1) != ERROR_OK) {
+               printf("Cannot read back memory!\n");
+               return ERROR_FAIL;
+       }
+
+       if (r1 != insn[9]) {
+               printf("Breakpoing not removed: Expected: %08x, Received: 
%08x\n", insn[9], r1);
+               return ERROR_FAIL;
+       }
+
+       if (du_core->rl_jtag_read_cpu(&rv12->jtag, (GROUP_GPRS + 0x200), 1, 
&npc) != ERROR_OK) {
+               printf("Error: cannot read NPC\n");
+               return ERROR_FAIL;
+       }
+
+       if (du_core->rl_jtag_read_cpu(&rv12->jtag, (GROUP_GPRS + 0x201), 1, 
&ppc) != ERROR_OK) {
+               printf("Error: cannot read PPC\n");
+               return ERROR_FAIL;
+       }
+
+       if (du_core->rl_jtag_read_cpu(&rv12->jtag, (GROUP_RF   +  1), 1, &r1) 
!= ERROR_OK) {
+               printf("Error: cannot read PPC\n");
+               return ERROR_FAIL;
+       }
+
+       printf("Read:     npc: %08x, ppc: %08x, r1: %08x\n", npc, ppc, r1);
+       printf("Expected: npc: %08x, ppc: %08x, r1: %08x\n", 0x00010028, 
0x00010024, 8);
+
+       if (ppc !=  0x00010024 || r1 != 8)
+               return ERROR_FAIL;
+       printf("Passed test 3\n");
+       printf("- Test 4, Breakpoint hit2\n");
+
+       testBreakPoint.type = BKPT_SOFT;
+       testBreakPoint.address = (baseAddress + 0x28);
+       testBreakPoint.length = 4;
+       printf("Add breakpoint\n");
+
+       rv12_add_breakpoint(target, &testBreakPoint);
+
+       if (rv12_poll(target) != ERROR_OK) {
+               printf("Error while polling target\n");
+               return ERROR_FAIL;
+       }
+
+       ppc = (baseAddress + 0x10);
+       printf("Write NPC: %08x\n", ppc);
+       if (du_core->rl_jtag_write_cpu(&rv12->jtag, (GROUP_GPRS + 0x200), 1, 
&ppc) != ERROR_OK) {
+               printf("Error: cannot set NPC\n");
+               return ERROR_FAIL;
+       }
+
+       printf("Resuming target\n");
+       rv12_resume(target, 1, 0, 0, 0);
+
+       do {
+               if (rl_is_cpu_running(target, &state) != ERROR_OK) {
+                       LOG_ERROR("Error while calling rl_is_cpu_running");
+                       return ERROR_FAIL;
+               }
+       } while (!state);
+
+       printf("Remove breakpoint\n");
+       rv12_remove_breakpoint(target, &testBreakPoint);
+
+       if (du_core->rl_jtag_read_cpu(&rv12->jtag, (GROUP_GPRS + 0x200), 1, 
&npc) != ERROR_OK) {
+               printf("Error: cannot read NPC\n");
+               return ERROR_FAIL;
+       }
+
+       if (du_core->rl_jtag_read_cpu(&rv12->jtag, (GROUP_GPRS + 0x201), 1, 
&ppc) != ERROR_OK) {
+               printf("Error: cannot read PPC\n");
+               return ERROR_FAIL;
+       }
+
+       if (du_core->rl_jtag_read_cpu(&rv12->jtag, (GROUP_RF   +  1), 1, &r1) 
!= ERROR_OK) {
+               printf("Error: cannot read PPC\n");
+               return ERROR_FAIL;
+       }
+
+       printf("Read:     npc: %08x, ppc: %08x, r1: %08x\n", npc, ppc, r1);
+       printf("Expected: npc: %08x, ppc: %08x, r1: %08x\n", 0x0001002C, 
0x00010028, 21);
+
+       if (ppc !=  0x00010028 || r1 != 21)
+               return ERROR_FAIL;
+
+       printf("Passed test 4\n");
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(rl_tap_select_command_handler)
+{
+       struct target *target = get_current_target(CMD_CTX);
+       struct rv12_common *rv12 = target_to_rv12(target);
+       struct rl_jtag *jtag = &rv12->jtag;
+       struct rl_tap_ip *rl_tap;
+
+       if (CMD_ARGC != 1)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       list_for_each_entry(rl_tap, &rl_tap_list, list) {
+               if (rl_tap->name) {
+                       if (!strcmp(CMD_ARGV[0], rl_tap->name)) {
+                               jtag->tap_ip = rl_tap;
+                               LOG_INFO("%s tap selected", rl_tap->name);
+                               return ERROR_OK;
+                       }
+               }
+       }
+
+       LOG_ERROR("%s unknown, no tap selected", CMD_ARGV[0]);
+       return ERROR_COMMAND_SYNTAX_ERROR;
+}
+
+COMMAND_HANDLER(rl_tap_list_command_handler)
+{
+       struct rl_tap_ip *rl_tap;
+
+       if (CMD_ARGC != 0)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       list_for_each_entry(rl_tap, &rl_tap_list, list) {
+               if (rl_tap->name)
+                       command_print(CMD, "%s", rl_tap->name);
+       }
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(rl_du_select_command_handler)
+{
+       struct target *target = get_current_target(CMD_CTX);
+       struct rv12_common *rv12 = target_to_rv12(target);
+       struct rl_jtag *jtag = &rv12->jtag;
+       struct rl_du *rl_du;
+
+       if (CMD_ARGC > 2)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       list_for_each_entry(rl_du, &rl_du_list, list) {
+               if (rl_du->name) {
+                       if (!strcmp(CMD_ARGV[0], rl_du->name)) {
+                               jtag->du_core = rl_du;
+                               LOG_INFO("%s debug unit selected", rl_du->name);
+
+                               if (CMD_ARGC == 2) {
+                                       int options;
+                                       COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], 
options);
+                                       rl_du->options = options;
+                                       LOG_INFO("Option %x is passed to %s 
debug unit"
+                                                , options, rl_du->name);
+                               }
+
+                               return ERROR_OK;
+                       }
+               }
+       }
+
+       LOG_ERROR("%s unknown, no debug unit selected", CMD_ARGV[0]);
+       return ERROR_COMMAND_SYNTAX_ERROR;
+}
+
+COMMAND_HANDLER(rl_du_list_command_handler)
+{
+       struct rl_du *rl_du;
+
+       if (CMD_ARGC != 0)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       list_for_each_entry(rl_du, &rl_du_list, list) {
+               if (rl_du->name)
+                       command_print(CMD, "%s", rl_du->name);
+       }
+
+       return ERROR_OK;
+}
+
+/*
+COMMAND_HANDLER(rv12_addreg_command_handler)
+{
+       struct target *target = get_current_target(CMD_CTX);
+       struct rv12_core_reg new_reg;
+
+       if (CMD_ARGC != 4)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       new_reg.target = NULL;
+       new_reg.rv12_common = NULL;
+
+       uint32_t addr;
+       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], addr);
+
+       new_reg.name = strdup(CMD_ARGV[0]);
+       new_reg.spr_num = addr;
+       new_reg.feature = strdup(CMD_ARGV[2]);
+       new_reg.group = strdup(CMD_ARGV[3]);
+
+       rv12_add_reg(target, &new_reg);
+
+       LOG_DEBUG("Add reg \"%s\" @ 0x%08" PRIx32 ", group \"%s\", feature 
\"%s\"",
+                 new_reg.name, addr, new_reg.group, new_reg.feature);
+
+       return ERROR_OK;
+} */
+
+COMMAND_HANDLER(rv12_test_handler)
+{
+       struct target *target = get_current_target(CMD_CTX);
+
+       if (CMD_ARGC == 0 || CMD_ARGC > 1)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       int options;
+       COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], options);
+
+       printf("rv12 Test\n");
+       printf("Testing options: %u\n", options);
+       printf("\n rv12-SoC Stalling CPU\n");
+
+       if (rv12_halt(target) == ERROR_OK) {
+               printf("Success: CPU(s) stalled\n");
+       } else {
+               printf("Error: CPU(s) not stalled!\n");
+               return ERROR_FAIL;
+       }
+
+       if ((options & 0x00000001) >  0) {
+               printf("\n rv12 SoC on-chip SRAM test:\n");
+               if (rv12_soc_test_sram(target) == ERROR_OK) {
+                       printf("Success: sram test success\n");
+               } else {
+                       printf("Error: sram test failed!\n");
+                       return ERROR_FAIL;
+               }
+       } else
+               printf("\n rv12 SoC SRAM test disabled\n");
+
+       if ((options & 0x00000002) > 0) {
+               if (rv12_soc_test_cpu(target) == ERROR_OK)
+                       printf("Success: CPU test Passed\n");
+               else {
+                       printf("Error: CPU test failed!\n");
+                       return ERROR_FAIL;
+               }
+       }
+
+       printf("Succesfully passed given tests\n");
+
+       return ERROR_OK;
+}
+
+static const struct command_registration rv12_hw_ip_command_handlers[] = {
+       {
+               .name = "rl_tap_select",
+               .handler = rl_tap_select_command_handler,
+               .mode = COMMAND_ANY,
+               .usage = "name",
+               .help = "Select the TAP core to use",
+       },
+       {
+               .name = "rl_tap_list",
+               .handler = rl_tap_list_command_handler,
+               .mode = COMMAND_ANY,
+               .usage = "",
+               .help = "Display available TAP core",
+       },
+       {
+               .name = "rl_du_select",
+               .handler = rl_du_select_command_handler,
+               .mode = COMMAND_ANY,
+               .usage = "name",
+               .help = "Select the Debug Unit core to use",
+       },
+       {
+               .name = "rl_du_list",
+               .handler = rl_du_list_command_handler,
+               .mode = COMMAND_ANY,
+               .usage = "select_tap name",
+               .help = "Display available Debug Unit core",
+       },
+       {
+               .name = "rv12_test",
+               .handler = rv12_test_handler,
+               .mode = COMMAND_ANY,
+               .usage = "Test the rv12 SoC",
+               .help = "Test the rv12 SoC implementation",
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
+/*
+static const struct command_registration rv12_reg_command_handlers[] = {
+       {
+               .name = "addreg",
+               .handler = rv12_addreg_command_handler,
+               .mode = COMMAND_ANY,
+               .usage = "name addr feature group",
+               .help = "Add a register to the register list",
+       },
+       COMMAND_REGISTRATION_DONE
+};*/
+
+static const struct command_registration rv12_command_handlers[] = {
+       {
+               .chain = rv12_hw_ip_command_handlers,
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
+struct target_type rv12_target = {
+       .name = "rv12",
+
+       .poll = rv12_poll,
+       .arch_state = rv12_arch_state,
+
+       .target_request_data = NULL,
+
+       .halt = rv12_halt,
+       .resume = rv12_resume,
+       .step = rv12_step,
+
+       .assert_reset = rv12_assert_reset,
+       .deassert_reset = rv12_deassert_reset,
+       .soft_reset_halt = rv12_soft_reset_halt,
+
+       .get_gdb_reg_list = rv12_get_gdb_reg_list,
+
+       .read_memory = rv12_read_memory,
+       .write_memory = rv12_write_memory,
+       .checksum_memory = rv12_checksum_memory,
+
+       .commands = rv12_command_handlers,
+       .add_breakpoint = rv12_add_breakpoint,
+       .remove_breakpoint = rv12_remove_breakpoint,
+       .add_watchpoint = rv12_add_watchpoint,
+       .remove_watchpoint = rv12_remove_watchpoint,
+
+       .target_create = rv12_target_create,
+       .init_target = rv12_init_target,
+       .examine = rv12_examine,
+
+       .get_gdb_fileio_info = rv12_get_gdb_fileio_info,
+
+       .profiling = rv12_profiling,
+};
diff --git a/src/target/roalogic/rv12.h b/src/target/roalogic/rv12.h
new file mode 100644
index 0000000000..af1dd13a59
--- /dev/null
+++ b/src/target/roalogic/rv12.h
@@ -0,0 +1,255 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/***************************************************************************
+ *   Copyright (C) 2022 by Richard Herveille                               *
+ *   richard.hervei...@roalogic.com                                        *
+ *                                                                         *
+ *   Copyright (C) 2022 by Bjorn Schouteten                                *
+ *   bjorn.schoute...@roalogic.com                                         *
+ *                                                                         *
+ *   Based on the OR1K version                                             *
+ *                                                                         *
+ ***************************************************************************/
+
+#ifndef OPENOCD_TARGET_ROALOGIC_rv12_H
+#define OPENOCD_TARGET_ROALOGIC_rv12_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <target/target.h>
+#include <target/riscv/encoding.h>
+
+/* Debug Register Access Groups Start Addresses
+ * INTERNAL = Debug Unit internal registers
+ * GPRS = INR_RF, FP_RF, NPC, PPC
+ * CSRS = RISC-V State CSRs
+ * */
+#define GROUP_DBG      (0 << 12)
+#define GROUP_GPRS     (1 << 12)
+#define GROUP_CSR      (2 << 12)
+
+#define CSR_USTATUS 0x0
+#define CSR_UIE 0x4
+#define CSR_UTVEC 0x5
+#define CSR_USCRATCH 0x40
+#define CSR_UEPC 0x41
+#define CSR_UCAUSE 0x42
+#define CSR_UTVAL 0x43
+#define CSR_UIP 0x44
+#define CSR_MNMIVEC 0x70C
+
+/* Integer Register File
+ * Floating Point Register File
+ * NPC
+ * PPC
+ */
+#define GROUP_RF       (GROUP_GPRS +        0)
+#define GROUP_FPRF     (GROUP_GPRS + (1 << 8))
+
+
+/* rv12 registers */
+/* gdb's register list is defined in riscv_gdb_reg_names gdb/riscv-tdep.c in
+ * its source tree. We must interpret the numbers the same here. */
+enum gdb_regno {
+       GDB_REGNO_ZERO = 0,        /* Read-only register, always 0.  */
+       GDB_REGNO_RA = 1,          /* Return Address.  */
+       GDB_REGNO_SP = 2,          /* Stack Pointer.  */
+       GDB_REGNO_GP = 3,          /* Global Pointer.  */
+       GDB_REGNO_TP = 4,          /* Thread Pointer.  */
+       GDB_REGNO_T0,
+       GDB_REGNO_T1,
+       GDB_REGNO_T2,
+       GDB_REGNO_S0 = 8,
+       GDB_REGNO_FP = 8,          /* Frame Pointer.  */
+       GDB_REGNO_S1,
+       GDB_REGNO_A0 = 10,         /* First argument.  */
+       GDB_REGNO_A1 = 11,         /* Second argument.  */
+       GDB_REGNO_A2,
+       GDB_REGNO_A3,
+       GDB_REGNO_A4,
+       GDB_REGNO_A5,
+       GDB_REGNO_XPR15 = 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_XPR31 = GDB_REGNO_T6,
+
+       GDB_REGNO_PC = 32,
+       GDB_REGNO_FPR0 = 33,
+       GDB_REGNO_FT0 = GDB_REGNO_FPR0,
+       GDB_REGNO_FT1,
+       GDB_REGNO_FT2,
+       GDB_REGNO_FT3,
+       GDB_REGNO_FT4,
+       GDB_REGNO_FT5,
+       GDB_REGNO_FT6,
+       GDB_REGNO_FT7,
+       GDB_REGNO_FS0,
+       GDB_REGNO_FS1,
+       GDB_REGNO_FA0,
+       GDB_REGNO_FA1,
+       GDB_REGNO_FA2,
+       GDB_REGNO_FA3,
+       GDB_REGNO_FA4,
+       GDB_REGNO_FA5,
+       GDB_REGNO_FA6,
+       GDB_REGNO_FA7,
+       GDB_REGNO_FS2,
+       GDB_REGNO_FS3,
+       GDB_REGNO_FS4,
+       GDB_REGNO_FS5,
+       GDB_REGNO_FS6,
+       GDB_REGNO_FS7,
+       GDB_REGNO_FS8,
+       GDB_REGNO_FS9,
+       GDB_REGNO_FS10,
+       GDB_REGNO_FS11,
+       GDB_REGNO_FT8,
+       GDB_REGNO_FT9,
+       GDB_REGNO_FT10,
+       GDB_REGNO_FT11,
+       GDB_REGNO_FPR31 = GDB_REGNO_FT11,
+       GDB_REGNO_CSR0 = 65,
+       GDB_REGNO_VSTART = CSR_VSTART + GDB_REGNO_CSR0,
+       GDB_REGNO_VXSAT = CSR_VXSAT + GDB_REGNO_CSR0,
+       GDB_REGNO_VXRM = CSR_VXRM + GDB_REGNO_CSR0,
+       GDB_REGNO_VLENB = CSR_VLENB + GDB_REGNO_CSR0,
+       GDB_REGNO_VL = CSR_VL + GDB_REGNO_CSR0,
+       GDB_REGNO_VTYPE = CSR_VTYPE + GDB_REGNO_CSR0,
+       GDB_REGNO_TSELECT = CSR_TSELECT + GDB_REGNO_CSR0,
+       GDB_REGNO_TDATA1 = CSR_TDATA1 + GDB_REGNO_CSR0,
+       GDB_REGNO_TDATA2 = CSR_TDATA2 + GDB_REGNO_CSR0,
+       GDB_REGNO_MISA = CSR_MISA + GDB_REGNO_CSR0,
+       GDB_REGNO_DPC = CSR_DPC + GDB_REGNO_CSR0,
+       GDB_REGNO_DCSR = CSR_DCSR + GDB_REGNO_CSR0,
+       GDB_REGNO_DSCRATCH0 = CSR_DSCRATCH0 + GDB_REGNO_CSR0,
+       GDB_REGNO_MSTATUS = CSR_MSTATUS + GDB_REGNO_CSR0,
+       GDB_REGNO_MEPC = CSR_MEPC + GDB_REGNO_CSR0,
+       GDB_REGNO_MCAUSE = CSR_MCAUSE + GDB_REGNO_CSR0,
+       GDB_REGNO_SATP = CSR_SATP + GDB_REGNO_CSR0,
+       GDB_REGNO_CSR4095 = GDB_REGNO_CSR0 + 4095,
+       GDB_REGNO_PRIV = 4161,
+       /* It's still undecided what register numbers GDB will actually use for
+        * these. See
+        * 
https://groups.google.com/a/groups.riscv.org/d/msg/sw-dev/7lQYiTUN9Ms/gTxGhzaYBQAJ
+        */
+       GDB_REGNO_V0, GDB_REGNO_V1, GDB_REGNO_V2, GDB_REGNO_V3,
+       GDB_REGNO_V4, GDB_REGNO_V5, GDB_REGNO_V6, GDB_REGNO_V7,
+       GDB_REGNO_V8, GDB_REGNO_V9, GDB_REGNO_V10, GDB_REGNO_V11,
+       GDB_REGNO_V12, GDB_REGNO_V13, GDB_REGNO_V14, GDB_REGNO_V15,
+       GDB_REGNO_V16, GDB_REGNO_V17, GDB_REGNO_V18, GDB_REGNO_V19,
+       GDB_REGNO_V20, GDB_REGNO_V21, GDB_REGNO_V22, GDB_REGNO_V23,
+       GDB_REGNO_V24, GDB_REGNO_V25, GDB_REGNO_V26, GDB_REGNO_V27,
+       GDB_REGNO_V28, GDB_REGNO_V29, GDB_REGNO_V30, GDB_REGNO_V31,
+       GDB_REGNO_COUNT
+};
+
+const char *gdb_regno_name(enum gdb_regno regno);
+
+
+struct rl_jtag {
+       struct jtag_tap *tap;
+       int rl_jtag_inited;
+       int rl_jtag_module_selected;
+       int rl_jtag_cpu_selected;
+       int rl_jtag_address_size;
+       uint8_t *current_reg_idx;
+       struct rl_tap_ip *tap_ip;
+       struct rl_du *du_core;
+       struct target *target;
+};
+
+
+struct rv12_common {
+       struct rl_jtag jtag;
+       struct reg_cache *core_cache;
+       uint32_t core_regs[GDB_REGNO_COUNT];
+       int nb_regs;
+       struct rv12_core_reg *arch_info;
+};
+
+static inline struct rv12_common *
+target_to_rv12(struct target *target)
+{
+       return (struct rv12_common *)target->arch_info;
+}
+
+struct rv12_core_reg {
+       const char *name;
+       uint32_t list_num;   /* Index in register cache */
+       uint32_t spr_num;    /* Number in architecture's SPR space */
+       struct target *target;
+       struct rv12_common *rv12_common;
+       const char *feature; /* feature name in XML tdesc file */
+       const char *group;   /* register group in XML tdesc file */
+};
+
+struct rv12_core_reg_init {
+       const char *name;
+       uint32_t spr_num;    /* Number in architecture's SPR space */
+       const char *feature; /* feature name in XML tdesc file */
+       const char *group;   /* register group in XML tdesc file */
+};
+
+/* RISC-V EBREAK instruction */
+#define RV_EBREAK_INSTR  0x00100073
+#define RV_EBREAK16_INSTR 0x9002
+
+enum rv12_debug_reg_nums {
+       rv12_DEBUG_REG_CTRL = 0,
+       rv12_DEBUG_REG_HIT,
+       rv12_DEBUG_REG_IE,
+       rv12_DEBUG_REG_CAUSE,
+       rv12_DEBUG_REG_BPCTRL0 = 0x10,
+       rv12_DEBUG_REG_BPDATA0,
+       rv12_DEBUG_REG_BPCTRL1,
+       rv12_DEBUG_REG_BPDATA1,
+       rv12_DEBUG_REG_BPCTRL2,
+       rv12_DEBUG_REG_BPDATA2
+};
+
+#define rv12_JTAG_DBG_REGS 10
+
+#define NO_SINGLE_STEP         0
+#define SINGLE_STEP            1
+
+
+/* DBG CTRL */
+/* Bit definitions */
+#define DBG_CTRL_SINGLE_STEP_TRACE     0x01       /* Enable single-step trace  
                      */
+#define DBG_CTRL_BRANCH_TRACE          0x02       /* Enable branch-trace       
                      */
+
+#define DBG_CSR_MSTASUS_MIE         0x08
+
+#define DBG_IE_INST_MISALIGNED         0x00001
+#define DBG_IE_INST_ACCESS_FAULT       0x00002
+#define DBG_IE_ILLEGAL                 0x00004
+#define DBG_IE_BREAKPOINT              0x00008
+#define DBG_IE_LOAD_MISALIGNED         0x00010
+#define DBG_IE_LOAD_ACCESS_FAULT       0x00020
+#define DBG_IE_AMO_MISALIGNED          0x00040
+#define DBG_IE_STORE_ACCESS_FAULT      0x00080
+#define DBG_IE_UMODE_ECALL             0x00100
+#define DBG_IE_SMODE_ECALL             0x00200
+#define DBG_IE_HMODE_ECALL             0x00400
+#define DBG_IE_MMODE_ECALL             0x00800
+#define DBG_IE_SOFTWARE_INT            0x10000
+#define DBG_IE_TIMER_INT               0x20000
+#define DBG_IE_UART                    0x40000
+
+#endif /* OPENOCD_TARGET_ROALOGIC_rv12_H */
diff --git a/src/target/target.c b/src/target/target.c
index 9b07dbf618..e9ed5b17fc 100644
--- a/src/target/target.c
+++ b/src/target/target.c
@@ -105,6 +105,7 @@ extern struct target_type stm8_target;
 extern struct target_type riscv_target;
 extern struct target_type mem_ap_target;
 extern struct target_type esirisc_target;
+extern struct target_type rv12_target;
 extern struct target_type arcv2_target;
 
 static struct target_type *target_types[] = {
@@ -147,6 +148,7 @@ static struct target_type *target_types[] = {
        &esirisc_target,
        &arcv2_target,
        &aarch64_target,
+       &rv12_target,
        &mips_mips64_target,
        NULL,
 };
diff --git a/tcl/target/roalogic_rv12.cfg b/tcl/target/roalogic_rv12.cfg
new file mode 100644
index 0000000000..7a63bca6bf
--- /dev/null
+++ b/tcl/target/roalogic_rv12.cfg
@@ -0,0 +1,26 @@
+#setup device
+# Roa logic Tap ID
+set _CPUTAPID 0x000009DD
+
+# Roa logic chipname
+set _CHIPNAME rv12
+
+jtag newtap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUTAPID
+
+set _TARGETNAME $_CHIPNAME.cpu
+target create $_TARGETNAME rv12 -chain-position $_TARGETNAME
+
+# Select the debug unit core we are using. This debug unit as an option.
+
+set ADBG_USE_HISPEED           1
+#set ENABLE_JSP_SERVER         2
+#set ENABLE_JSP_MULTI          4
+
+# If ADBG_USE_HISPEED is set (options bit 1), status bits will be skipped
+# on burst reads and writes to improve download speeds.
+# This option must match the RTL configured option.
+
+rl_du_select rl_dbg_adv [expr {$ADBG_USE_HISPEED | $ENABLE_JSP_SERVER | 
$ENABLE_JSP_MULTI}]
+rl_tap_select rl_universal_tap
+
+echo "Ready for Remote Connections"

-- 

Reply via email to