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, + ®s[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, ®_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, ®_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" --