target: riscv: Sync with the RISC-V fork

Regenerate autogenerated debug_defines.{c,h} files from current
riscv-debug-spec, sync remaining RISC-V target files with the
RISC-V fork.

This is based on the work of (in alphabetic order):

Aleksey Lotosh <lotosh@gmail.com>
Alexander Rumyantsev <cetygamer@gmail.com>
Anastasiya Chernikova <anastasiya.chernikova@syntacore.com>
Anatoly Parshintsev <114445139+aap-sc@users.noreply.github.com>
Bernhard Rosenkränzer <bero@baylibre.com>
bluew <bluewww@users.noreply.github.com>
Carsten Gosvig <40368726+cgsfv@users.noreply.github.com>
cgsfv <cgsfv@users.noreply.github.com>
Craig Blackmore <craig.blackmore@embecosm.com>
Dan Robertson <danlrobertson89@gmail.com>
Darius Rad <darius@bluespec.com>
dave-estes-syzexion <53795406+dave-estes-syzexion@users.noreply.github.com>
Dmitry Ryzhov <dmitry.ryzhov@cloudbear.ru>
Dolu1990 <charles.papon.90@gmail.com>
Emmanuel Blot <emmanuel.blot@free.fr>
Ernie Edgar <43148441+ernie-sifive@users.noreply.github.com>
Evgeniy Naydanov <evgeniy.naydanov@syntacore.com>
Farid Khaydari <f.khaydari@syntacore.com>
Gleb Gagarin <gleb@sifive.com>
Greg Savin <43152568+SiFiveGregS@users.noreply.github.com>
Hang Xu <xuhang@eswincomputing.com>
Hsiangkai <Hsiangkai@gmail.com>
Jan Matyas <jan.matyas@codasip.com>
jhjung81 <48940114+jhjung81@users.noreply.github.com>
Jiuyang Liu <liu@jiuyang.me>
Kaspar Schleiser <kaspar@schleiser.de>
Khem Raj <raj.khem@gmail.com>
Kirill Radkin <kirill.radkin@syntacore.com>
liangzhen <zhen.liang@spacemit.com>
Liviu Ionescu <ilg@livius.net>
Marc Schink <openocd-dev@marcschink.de>
Megan Wachs <megan@sifive.com>
Nils Wistoff <git@wistoff.net>
Palmer Dabbelt <palmer@dabbelt.com>
panciyan <panciyan@eswincomputing.com>
Parshintsev Anatoly <anatoly.parshintsev@syntacore.com>
Paul George <command.paul@gmail.com>
Pavel S. Smirnov <Paul.Smirnov.aka.sps@gmail.com>
Philipp Wagner <mail@philipp-wagner.com>
Ryan Macdonald <rmac@sifive.com>
Samuel Obuch <samuel.obuch17@gmail.com>
Tarek BOCHKATI <tarek.bouchkati@gmail.com>
Tim Newsome <tim@casualhacker.net>
Tobias Kaiser <mail@tb-kaiser.de>
Tom Hebb <tommyhebb@gmail.com>
Tommy Murphy <tommy_murphy@hotmail.com>
wxjstz <wxjstz@126.com>
wzgpeter <wzgpeter@outlook.com>
Xiang W <wxjstz@126.com>
zhusonghe <zhusonghe@eswincomputing.com>

Checkpatch-ignore MULTISTATEMENT_MACRO_USE_DO_WHILE is added to allow a
macro in riscv-013.c that can't use do/while because it expands to a
"case ...:" statement.

Checkpatch-ignore TRAILING_SEMICOLON is added to allow a construct in
riscv-013.c where a macro expands to either code (where it needs the
semicolon) or a member of an enum (where it needs a comma).

Checkpatch-ignore LONG_LINE_COMMENT and NEW_TYPEDEFS lines are added for
the sake of the autogenerated files from riscv-debug-spec.
All non-autogenerated files have been updated for checkpatch compliance.

Checkpatch-ignore: LONG_LINE_COMMENT
Checkpatch-ignore: NEW_TYPEDEFS
Checkpatch-ignore: MULTISTATEMENT_MACRO_USE_DO_WHILE
Checkpatch-ignore: TRAILING_SEMICOLON
Change-Id: Ie594915a4d6e6f9d9dad6016b176ab76409a099a
Signed-off-by: Bernhard Rosenkränzer <bero@baylibre.com>
Reviewed-on: https://review.openocd.org/c/openocd/+/8893
Tested-by: jenkins
Reviewed-by: Evgeniy Naydanov <evgeniy.naydanov@syntacore.com>
Reviewed-by: Tomas Vanek <vanekt@fbl.cz>
This commit is contained in:
Bernhard Rosenkränzer
2025-05-06 01:20:22 +02:00
committed by Tomas Vanek
parent ab22b0bf8f
commit 5754aebc49
29 changed files with 16775 additions and 6857 deletions

View File

@@ -13,6 +13,8 @@
#include "config.h"
#endif
#include "riscv-011.h"
#include "target/target.h"
#include "target/algorithm.h"
#include "target/target_type.h"
@@ -22,8 +24,10 @@
#include "target/breakpoints.h"
#include "helper/time_support.h"
#include "riscv.h"
#include "asm.h"
#include "riscv_reg.h"
#include "riscv-011_reg.h"
#include "gdb_regs.h"
#include "field_helpers.h"
/**
* Since almost everything can be accomplish by scanning the dbus register, all
@@ -67,8 +71,7 @@
* to the target. Afterwards use cache_get... to read results.
*/
#define get_field(reg, mask) (((reg) & (mask)) / ((mask) & ~((mask) << 1)))
#define set_field(reg, mask, val) (((reg) & ~(mask)) | (((val) * ((mask) & ~((mask) << 1))) & (mask)))
static int handle_halt(struct target *target, bool announce);
/* Constants for legacy SiFive hardware breakpoints. */
#define CSR_BPCONTROL_X (1<<0)
@@ -161,15 +164,6 @@ typedef enum slot {
#define DRAM_CACHE_SIZE 16
struct trigger {
uint64_t address;
uint32_t length;
uint64_t mask;
uint64_t value;
bool read, write, execute;
int unique_id;
};
struct memory_cache_line {
uint32_t data;
bool valid;
@@ -219,7 +213,6 @@ typedef struct {
static int poll_target(struct target *target, bool announce);
static int riscv011_poll(struct target *target);
static int get_register(struct target *target, riscv_reg_t *value, int regid);
/*** Utility functions. ***/
@@ -257,18 +250,46 @@ static unsigned int slot_offset(const struct target *target, slot_t slot)
return 0; /* Silence -Werror=return-type */
}
static uint32_t load(const struct target *target, unsigned int rd,
unsigned int base, int16_t offset)
{
switch (riscv_xlen(target)) {
case 32:
return lw(rd, base, offset);
case 64:
return ld(rd, base, offset);
}
assert(0);
return 0; /* Silence -Werror=return-type */
}
static uint32_t store(const struct target *target, unsigned int src,
unsigned int base, int16_t offset)
{
switch (riscv_xlen(target)) {
case 32:
return sw(src, base, offset);
case 64:
return sd(src, base, offset);
}
assert(0);
return 0; /* Silence -Werror=return-type */
}
static uint32_t load_slot(const struct target *target, unsigned int dest,
slot_t slot)
{
unsigned int offset = DEBUG_RAM_START + 4 * slot_offset(target, slot);
return load(target, dest, ZERO, offset);
assert(offset <= MAX_INT12);
return load(target, dest, ZERO, (int16_t)offset);
}
static uint32_t store_slot(const struct target *target, unsigned int src,
slot_t slot)
{
unsigned int offset = DEBUG_RAM_START + 4 * slot_offset(target, slot);
return store(target, src, ZERO, offset);
assert(offset <= MAX_INT12);
return store(target, src, ZERO, (int16_t)offset);
}
static uint16_t dram_address(unsigned int index)
@@ -279,36 +300,6 @@ static uint16_t dram_address(unsigned int index)
return 0x40 + index - 0x10;
}
static uint32_t dtmcontrol_scan(struct target *target, uint32_t out)
{
struct scan_field field;
uint8_t in_value[4];
uint8_t out_value[4] = { 0 };
buf_set_u32(out_value, 0, 32, out);
jtag_add_ir_scan(target->tap, &select_dtmcontrol, TAP_IDLE);
field.num_bits = 32;
field.out_value = out_value;
field.in_value = in_value;
jtag_add_dr_scan(target->tap, 1, &field, TAP_IDLE);
/* Always return to dbus. */
jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE);
int retval = jtag_execute_queue();
if (retval != ERROR_OK) {
LOG_ERROR("failed jtag scan: %d", retval);
return retval;
}
uint32_t in = buf_get_u32(field.in_value, 0, 32);
LOG_DEBUG("DTMCONTROL: 0x%x -> 0x%x", out, in);
return in;
}
static uint32_t idcode_scan(struct target *target)
{
struct scan_field field;
@@ -344,7 +335,7 @@ static void increase_dbus_busy_delay(struct target *target)
info->dtmcontrol_idle, info->dbus_busy_delay,
info->interrupt_high_delay);
dtmcontrol_scan(target, DTMCONTROL_DBUS_RESET);
dtmcs_scan(target->tap, DTMCONTROL_DBUS_RESET, NULL /* discard value */);
}
static void increase_interrupt_high_delay(struct target *target)
@@ -431,8 +422,13 @@ static dbus_status_t dbus_scan(struct target *target, uint16_t *address_in,
.out_value = out,
.in_value = in
};
if (address_in)
*address_in = 0;
assert(info->addrbits != 0);
if (info->addrbits == 0) {
LOG_TARGET_ERROR(target, "Can't access DMI because addrbits=0.");
return DBUS_STATUS_FAILED;
}
buf_set_u64(out, DBUS_OP_START, DBUS_OP_SIZE, op);
buf_set_u64(out, DBUS_DATA_START, DBUS_DATA_SIZE, data_out);
@@ -605,9 +601,9 @@ static void scans_add_write32(scans_t *scans, uint16_t address, uint32_t data,
static void scans_add_write_jump(scans_t *scans, uint16_t address,
bool set_interrupt)
{
scans_add_write32(scans, address,
jal(0, (uint32_t) (DEBUG_ROM_RESUME - (DEBUG_RAM_START + 4*address))),
set_interrupt);
unsigned int jump_offset = DEBUG_ROM_RESUME - (DEBUG_RAM_START + 4 * address);
assert(jump_offset <= MAX_INT21);
scans_add_write32(scans, address, jal(0, (int32_t)jump_offset), set_interrupt);
}
/** Add a 32-bit dbus write for an instruction that loads from the indicated
@@ -686,18 +682,13 @@ static void dram_write32(struct target *target, unsigned int index, uint32_t val
}
/** Read the haltnot and interrupt bits. */
static bits_t read_bits(struct target *target)
static int read_bits(struct target *target, bits_t *result)
{
uint64_t value;
dbus_status_t status;
uint16_t address_in;
riscv011_info_t *info = get_info(target);
bits_t err_result = {
.haltnot = 0,
.interrupt = 0
};
do {
unsigned int i = 0;
do {
@@ -706,26 +697,23 @@ static bits_t read_bits(struct target *target)
if (address_in == (1<<info->addrbits) - 1 &&
value == (1ULL<<DBUS_DATA_SIZE) - 1) {
LOG_ERROR("TDO seems to be stuck high.");
return err_result;
return ERROR_FAIL;
}
increase_dbus_busy_delay(target);
} else if (status == DBUS_STATUS_FAILED) {
/* TODO: return an actual error */
return err_result;
}
} while (status == DBUS_STATUS_BUSY && i++ < 256);
if (i >= 256) {
if (status != DBUS_STATUS_SUCCESS) {
LOG_ERROR("Failed to read from 0x%x; status=%d", address_in, status);
return err_result;
return ERROR_FAIL;
}
} while (address_in > 0x10 && address_in != DMCONTROL);
bits_t result = {
.haltnot = get_field(value, DMCONTROL_HALTNOT),
.interrupt = get_field(value, DMCONTROL_INTERRUPT)
};
return result;
if (result) {
result->haltnot = get_field(value, DMCONTROL_HALTNOT);
result->interrupt = get_field(value, DMCONTROL_INTERRUPT);
}
return ERROR_OK;
}
static int wait_for_debugint_clear(struct target *target, bool ignore_first)
@@ -736,13 +724,19 @@ static int wait_for_debugint_clear(struct target *target, bool ignore_first)
* result of the read that happened just before debugint was set.
* (Assuming the last scan before calling this function was one that
* sets debugint.) */
read_bits(target);
read_bits(target, NULL);
}
while (1) {
bits_t bits = read_bits(target);
bits_t bits = {
.haltnot = 0,
.interrupt = 0
};
if (read_bits(target, &bits) != ERROR_OK)
return ERROR_FAIL;
if (!bits.interrupt)
return ERROR_OK;
if (time(NULL) - start > riscv_command_timeout_sec) {
if (time(NULL) - start > riscv_get_command_timeout_sec()) {
LOG_ERROR("Timed out waiting for debug int to clear."
"Increase timeout with riscv set_command_timeout_sec.");
return ERROR_FAIL;
@@ -788,22 +782,25 @@ static void cache_set(struct target *target, slot_t slot, uint64_t data)
static void cache_set_jump(struct target *target, unsigned int index)
{
cache_set32(target, index,
jal(0, (uint32_t) (DEBUG_ROM_RESUME - (DEBUG_RAM_START + 4*index))));
unsigned int jump_offset = DEBUG_ROM_RESUME - (DEBUG_RAM_START + 4 * index);
assert(jump_offset <= MAX_INT21);
cache_set32(target, index, jal(0, (int32_t)jump_offset));
}
static void cache_set_load(struct target *target, unsigned int index,
unsigned int reg, slot_t slot)
{
uint16_t offset = DEBUG_RAM_START + 4 * slot_offset(target, slot);
cache_set32(target, index, load(target, reg, ZERO, offset));
unsigned int offset = DEBUG_RAM_START + 4 * slot_offset(target, slot);
assert(offset <= MAX_INT12);
cache_set32(target, index, load(target, reg, ZERO, (int16_t)offset));
}
static void cache_set_store(struct target *target, unsigned int index,
unsigned int reg, slot_t slot)
{
uint16_t offset = DEBUG_RAM_START + 4 * slot_offset(target, slot);
cache_set32(target, index, store(target, reg, ZERO, offset));
unsigned int offset = DEBUG_RAM_START + 4 * slot_offset(target, slot);
assert(offset <= MAX_INT12);
cache_set32(target, index, store(target, reg, ZERO, (int16_t)offset));
}
static void dump_debug_ram(struct target *target)
@@ -1012,9 +1009,9 @@ static uint64_t cache_get(struct target *target, slot_t slot)
static void dram_write_jump(struct target *target, unsigned int index,
bool set_interrupt)
{
dram_write32(target, index,
jal(0, (uint32_t) (DEBUG_ROM_RESUME - (DEBUG_RAM_START + 4*index))),
set_interrupt);
unsigned int jump_offset = DEBUG_ROM_RESUME - (DEBUG_RAM_START + 4 * index);
assert(jump_offset <= MAX_INT21);
dram_write32(target, index, jal(0, (int32_t)jump_offset), set_interrupt);
}
static int wait_for_state(struct target *target, enum target_state state)
@@ -1026,7 +1023,7 @@ static int wait_for_state(struct target *target, enum target_state state)
return result;
if (target->state == state)
return ERROR_OK;
if (time(NULL) - start > riscv_command_timeout_sec) {
if (time(NULL) - start > riscv_get_command_timeout_sec()) {
LOG_ERROR("Timed out waiting for state %d. "
"Increase timeout with riscv set_command_timeout_sec.", state);
return ERROR_FAIL;
@@ -1048,7 +1045,7 @@ static int read_remote_csr(struct target *target, uint64_t *value, uint32_t csr)
uint32_t exception = cache_get32(target, info->dramsize-1);
if (exception) {
LOG_WARNING("Got exception 0x%x when reading %s", exception,
gdb_regno_name(GDB_REGNO_CSR0 + csr));
riscv_reg_gdb_regno_name(target, GDB_REGNO_CSR0 + csr));
*value = ~0;
return ERROR_FAIL;
}
@@ -1107,12 +1104,25 @@ static int maybe_write_tselect(struct target *target)
return ERROR_OK;
}
static uint64_t set_ebreakx_fields(uint64_t dcsr, const struct target *target)
{
const struct riscv_private_config * const config = riscv_private_config(target);
dcsr = set_field(dcsr, DCSR_EBREAKM, config->dcsr_ebreak_fields[RISCV_MODE_M]);
dcsr = set_field(dcsr, DCSR_EBREAKS, config->dcsr_ebreak_fields[RISCV_MODE_S]);
dcsr = set_field(dcsr, DCSR_EBREAKU, config->dcsr_ebreak_fields[RISCV_MODE_U]);
dcsr = set_field(dcsr, DCSR_EBREAKH, 1);
return dcsr;
}
static int execute_resume(struct target *target, bool step)
{
riscv011_info_t *info = get_info(target);
LOG_DEBUG("step=%d", step);
if (riscv_reg_flush_all(target) != ERROR_OK)
return ERROR_FAIL;
maybe_write_tselect(target);
/* TODO: check if dpc is dirty (which also is true if an exception was hit
@@ -1137,10 +1147,7 @@ static int execute_resume(struct target *target, bool step)
}
}
info->dcsr = set_field(info->dcsr, DCSR_EBREAKM, riscv_ebreakm);
info->dcsr = set_field(info->dcsr, DCSR_EBREAKS, riscv_ebreaks);
info->dcsr = set_field(info->dcsr, DCSR_EBREAKU, riscv_ebreaku);
info->dcsr = set_field(info->dcsr, DCSR_EBREAKH, 1);
info->dcsr = set_ebreakx_fields(info->dcsr, target);
info->dcsr &= ~DCSR_HALT;
if (step)
@@ -1165,7 +1172,7 @@ static int execute_resume(struct target *target, bool step)
}
target->state = TARGET_RUNNING;
register_cache_invalidate(target->reg_cache);
riscv_reg_cache_invalidate_all(target);
return ERROR_OK;
}
@@ -1183,23 +1190,13 @@ static int full_step(struct target *target, bool announce)
return result;
if (target->state != TARGET_DEBUG_RUNNING)
break;
if (time(NULL) - start > riscv_command_timeout_sec) {
if (time(NULL) - start > riscv_get_command_timeout_sec()) {
LOG_ERROR("Timed out waiting for step to complete."
"Increase timeout with riscv set_command_timeout_sec");
return ERROR_FAIL;
}
}
return ERROR_OK;
}
static int resume(struct target *target, bool debug_execution, bool step)
{
if (debug_execution) {
LOG_ERROR("TODO: debug_execution is true");
return ERROR_FAIL;
}
return execute_resume(target, step);
return handle_halt(target, announce);
}
static uint64_t reg_cache_get(struct target *target, unsigned int number)
@@ -1234,7 +1231,7 @@ static int update_mstatus_actual(struct target *target)
/* Force reading the register. In that process mstatus_actual will be
* updated. */
riscv_reg_t mstatus;
return get_register(target, &mstatus, GDB_REGNO_MSTATUS);
return riscv011_get_register(target, &mstatus, GDB_REGNO_MSTATUS);
}
/*** OpenOCD target functions. ***/
@@ -1256,7 +1253,7 @@ static int register_read(struct target *target, riscv_reg_t *value, int regnum)
uint32_t exception = cache_get32(target, info->dramsize-1);
if (exception) {
LOG_WARNING("Got exception 0x%x when reading %s", exception, gdb_regno_name(regnum));
LOG_WARNING("Got exception 0x%x when reading %s", exception, riscv_reg_gdb_regno_name(target, regnum));
*value = ~0;
return ERROR_FAIL;
}
@@ -1270,7 +1267,7 @@ static int register_read(struct target *target, riscv_reg_t *value, int regnum)
return ERROR_OK;
}
/* Write the register. No caching or games. */
/* Write the register. */
static int register_write(struct target *target, unsigned int number,
uint64_t value)
{
@@ -1289,7 +1286,7 @@ static int register_write(struct target *target, unsigned int number,
} else if (number <= GDB_REGNO_XPR31) {
cache_set_load(target, 0, number - GDB_REGNO_ZERO, SLOT0);
cache_set_jump(target, 1);
} else if (number == GDB_REGNO_PC) {
} else if (number == GDB_REGNO_PC || number == GDB_REGNO_DPC) {
info->dpc = value;
return ERROR_OK;
} else if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) {
@@ -1331,22 +1328,27 @@ static int register_write(struct target *target, unsigned int number,
uint32_t exception = cache_get32(target, info->dramsize-1);
if (exception) {
LOG_WARNING("Got exception 0x%x when writing %s", exception,
gdb_regno_name(number));
riscv_reg_gdb_regno_name(target, number));
return ERROR_FAIL;
}
return ERROR_OK;
}
static int get_register(struct target *target, riscv_reg_t *value, int regid)
int riscv011_get_register(struct target *target, riscv_reg_t *value,
enum gdb_regno regid)
{
riscv011_info_t *info = get_info(target);
maybe_write_tselect(target);
if (regid <= GDB_REGNO_XPR31) {
/* FIXME: Here the implementation assumes that the value
* written to GPR will be the same as the value read back. This
* is not true for a write of a non-zero value to x0.
*/
*value = reg_cache_get(target, regid);
} else if (regid == GDB_REGNO_PC) {
} else if (regid == GDB_REGNO_PC || regid == GDB_REGNO_DPC) {
*value = info->dpc;
} else if (regid >= GDB_REGNO_FPR0 && regid <= GDB_REGNO_FPR31) {
int result = update_mstatus_actual(target);
@@ -1376,15 +1378,32 @@ static int get_register(struct target *target, riscv_reg_t *value, int regid)
return result;
}
if (regid == GDB_REGNO_MSTATUS)
target->reg_cache->reg_list[regid].valid = true;
return ERROR_OK;
}
static int set_register(struct target *target, int regid, uint64_t value)
/* This function is intended to handle accesses to registers through register
* cache. */
int riscv011_set_register(struct target *target, enum gdb_regno regid,
riscv_reg_t value)
{
return register_write(target, regid, value);
assert(target->reg_cache);
assert(target->reg_cache->reg_list);
struct reg * const reg = &target->reg_cache->reg_list[regid];
assert(reg);
/* On RISC-V 0.11 targets valid value of some registers (e.g. `dcsr`)
* is stored in `riscv011_info_t` itself, not in register cache. This
* complicates register cache implementation.
* Therefore, for now, caching registers in register cache is disabled
* for all registers, except for reads of GPRs.
*/
assert(!reg->dirty);
int result = register_write(target, regid, value);
if (result != ERROR_OK)
return result;
reg_cache_set(target, regid, value);
/* FIXME: x0 (zero) should not be cached on writes. */
reg->valid = regid <= GDB_REGNO_XPR31;
return ERROR_OK;
}
static int halt(struct target *target)
@@ -1468,19 +1487,20 @@ static int step(struct target *target, bool current, target_addr_t address,
static int examine(struct target *target)
{
/* Don't need to select dbus, since the first thing we do is read dtmcontrol. */
uint32_t dtmcontrol = dtmcontrol_scan(target, 0);
LOG_DEBUG("dtmcontrol=0x%x", dtmcontrol);
LOG_DEBUG(" addrbits=%d", get_field(dtmcontrol, DTMCONTROL_ADDRBITS));
LOG_DEBUG(" version=%d", get_field(dtmcontrol, DTMCONTROL_VERSION));
LOG_DEBUG(" idle=%d", get_field(dtmcontrol, DTMCONTROL_IDLE));
if (dtmcontrol == 0) {
LOG_ERROR("dtmcontrol is 0. Check JTAG connectivity/board power.");
uint32_t dtmcontrol;
if (dtmcs_scan(target->tap, 0, &dtmcontrol) != ERROR_OK || dtmcontrol == 0) {
LOG_ERROR("Could not scan dtmcontrol. Check JTAG connectivity/board power.");
return ERROR_FAIL;
}
LOG_DEBUG("dtmcontrol=0x%x", dtmcontrol);
LOG_DEBUG(" addrbits=%d", get_field32(dtmcontrol, DTMCONTROL_ADDRBITS));
LOG_DEBUG(" version=%d", get_field32(dtmcontrol, DTMCONTROL_VERSION));
LOG_DEBUG(" idle=%d", get_field32(dtmcontrol, DTMCONTROL_IDLE));
if (get_field(dtmcontrol, DTMCONTROL_VERSION) != 0) {
LOG_ERROR("Unsupported DTM version %d. (dtmcontrol=0x%x)",
get_field(dtmcontrol, DTMCONTROL_VERSION), dtmcontrol);
get_field32(dtmcontrol, DTMCONTROL_VERSION), dtmcontrol);
return ERROR_FAIL;
}
@@ -1498,22 +1518,22 @@ static int examine(struct target *target)
uint32_t dminfo = dbus_read(target, DMINFO);
LOG_DEBUG("dminfo: 0x%08x", dminfo);
LOG_DEBUG(" abussize=0x%x", get_field(dminfo, DMINFO_ABUSSIZE));
LOG_DEBUG(" serialcount=0x%x", get_field(dminfo, DMINFO_SERIALCOUNT));
LOG_DEBUG(" access128=%d", get_field(dminfo, DMINFO_ACCESS128));
LOG_DEBUG(" access64=%d", get_field(dminfo, DMINFO_ACCESS64));
LOG_DEBUG(" access32=%d", get_field(dminfo, DMINFO_ACCESS32));
LOG_DEBUG(" access16=%d", get_field(dminfo, DMINFO_ACCESS16));
LOG_DEBUG(" access8=%d", get_field(dminfo, DMINFO_ACCESS8));
LOG_DEBUG(" dramsize=0x%x", get_field(dminfo, DMINFO_DRAMSIZE));
LOG_DEBUG(" authenticated=0x%x", get_field(dminfo, DMINFO_AUTHENTICATED));
LOG_DEBUG(" authbusy=0x%x", get_field(dminfo, DMINFO_AUTHBUSY));
LOG_DEBUG(" authtype=0x%x", get_field(dminfo, DMINFO_AUTHTYPE));
LOG_DEBUG(" version=0x%x", get_field(dminfo, DMINFO_VERSION));
LOG_DEBUG(" abussize=0x%x", get_field32(dminfo, DMINFO_ABUSSIZE));
LOG_DEBUG(" serialcount=0x%x", get_field32(dminfo, DMINFO_SERIALCOUNT));
LOG_DEBUG(" access128=%d", get_field32(dminfo, DMINFO_ACCESS128));
LOG_DEBUG(" access64=%d", get_field32(dminfo, DMINFO_ACCESS64));
LOG_DEBUG(" access32=%d", get_field32(dminfo, DMINFO_ACCESS32));
LOG_DEBUG(" access16=%d", get_field32(dminfo, DMINFO_ACCESS16));
LOG_DEBUG(" access8=%d", get_field32(dminfo, DMINFO_ACCESS8));
LOG_DEBUG(" dramsize=0x%x", get_field32(dminfo, DMINFO_DRAMSIZE));
LOG_DEBUG(" authenticated=0x%x", get_field32(dminfo, DMINFO_AUTHENTICATED));
LOG_DEBUG(" authbusy=0x%x", get_field32(dminfo, DMINFO_AUTHBUSY));
LOG_DEBUG(" authtype=0x%x", get_field32(dminfo, DMINFO_AUTHTYPE));
LOG_DEBUG(" version=0x%x", get_field32(dminfo, DMINFO_VERSION));
if (get_field(dminfo, DMINFO_VERSION) != 1) {
LOG_ERROR("OpenOCD only supports Debug Module version 1, not %d "
"(dminfo=0x%x)", get_field(dminfo, DMINFO_VERSION), dminfo);
"(dminfo=0x%x)", get_field32(dminfo, DMINFO_VERSION), dminfo);
return ERROR_FAIL;
}
@@ -1581,7 +1601,7 @@ static int examine(struct target *target)
}
/* Update register list to match discovered XLEN/supported extensions. */
riscv_init_registers(target);
riscv011_reg_init_all(target);
info->never_halted = true;
@@ -1590,9 +1610,6 @@ static int examine(struct target *target)
return result;
target_set_examined(target);
riscv_set_current_hartid(target, 0);
for (size_t i = 0; i < 32; ++i)
reg_cache_set(target, i, -1);
LOG_INFO("Examined RISCV core; XLEN=%d, misa=0x%" PRIx64,
riscv_xlen(target), r->misa);
@@ -1778,10 +1795,10 @@ static riscv_error_t handle_halt_routine(struct target *target)
reg = S0;
break;
case 31:
reg = CSR_DPC;
reg = GDB_REGNO_DPC;
break;
case 32:
reg = CSR_DCSR;
reg = GDB_REGNO_DCSR;
break;
default:
assert(0);
@@ -1815,8 +1832,8 @@ static riscv_error_t handle_halt_routine(struct target *target)
}
/* TODO: get rid of those 2 variables and talk to the cache directly. */
info->dpc = reg_cache_get(target, CSR_DPC);
info->dcsr = reg_cache_get(target, CSR_DCSR);
info->dpc = reg_cache_get(target, GDB_REGNO_DPC);
info->dcsr = reg_cache_get(target, GDB_REGNO_DCSR);
cache_invalidate(target);
@@ -1872,8 +1889,16 @@ static int handle_halt(struct target *target, bool announce)
if (target->debug_reason == DBG_REASON_BREAKPOINT) {
int retval;
if (riscv_semihosting(target, &retval) != 0)
return retval;
/* Hotfix: Don't try to handle semihosting before the target is marked as examined. */
/* TODO: The code should be rearranged so that:
* - Semihosting is not attempted before the target is examined.
* - When the target is already halted on a semihosting magic sequence
* at the time when OpenOCD connects to it, this semihosting attempt
* gets handled right after the examination.
*/
if (target_was_examined(target))
if (riscv_semihosting(target, &retval) != SEMIHOSTING_NONE)
return retval;
}
if (announce)
@@ -1905,7 +1930,13 @@ static int poll_target(struct target *target, bool announce)
int old_debug_level = debug_level;
if (debug_level >= LOG_LVL_DEBUG)
debug_level = LOG_LVL_INFO;
bits_t bits = read_bits(target);
bits_t bits = {
.haltnot = 0,
.interrupt = 0
};
if (read_bits(target, &bits) != ERROR_OK)
return ERROR_FAIL;
debug_level = old_debug_level;
if (bits.haltnot && bits.interrupt) {
@@ -1937,7 +1968,7 @@ static int riscv011_resume(struct target *target, bool current,
jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE);
r->prepped = false;
return resume(target, debug_execution, false);
return execute_resume(target, false);
}
static int assert_reset(struct target *target)
@@ -1955,10 +1986,7 @@ static int assert_reset(struct target *target)
/* Not sure what we should do when there are multiple cores.
* Here just reset the single hart we're talking to. */
info->dcsr = set_field(info->dcsr, DCSR_EBREAKM, riscv_ebreakm);
info->dcsr = set_field(info->dcsr, DCSR_EBREAKS, riscv_ebreaks);
info->dcsr = set_field(info->dcsr, DCSR_EBREAKU, riscv_ebreaku);
info->dcsr = set_field(info->dcsr, DCSR_EBREAKH, 1);
info->dcsr = set_ebreakx_fields(info->dcsr, target);
info->dcsr |= DCSR_HALT;
if (target->reset_halt)
info->dcsr |= DCSR_NDRESET;
@@ -1985,9 +2013,16 @@ static int deassert_reset(struct target *target)
return wait_for_state(target, TARGET_RUNNING);
}
static int read_memory(struct target *target, target_addr_t address,
uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment)
static int read_memory(struct target *target, const struct riscv_mem_access_args args)
{
assert(riscv_mem_access_is_read(args));
const target_addr_t address = args.address;
const uint32_t size = args.size;
const uint32_t count = args.count;
const uint32_t increment = args.increment;
uint8_t * const buffer = args.read_buffer;
if (increment != size) {
LOG_ERROR("read_memory with custom increment not implemented");
return ERROR_NOT_IMPLEMENTED;
@@ -2155,9 +2190,20 @@ static int setup_write_memory(struct target *target, uint32_t size)
return ERROR_OK;
}
static int write_memory(struct target *target, target_addr_t address,
uint32_t size, uint32_t count, const uint8_t *buffer)
static int write_memory(struct target *target, const struct riscv_mem_access_args args)
{
assert(riscv_mem_access_is_write(args));
if (args.increment != args.size) {
LOG_TARGET_ERROR(target, "Write increment size has to be equal to element size");
return ERROR_NOT_IMPLEMENTED;
}
const target_addr_t address = args.address;
const uint32_t size = args.size;
const uint32_t count = args.count;
const uint8_t * const buffer = args.write_buffer;
riscv011_info_t *info = get_info(target);
jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE);
@@ -2293,6 +2339,15 @@ error:
return ERROR_FAIL;
}
static int access_memory(struct target *target, const struct riscv_mem_access_args args)
{
assert(riscv_mem_access_is_valid(args));
const bool is_write = riscv_mem_access_is_write(args);
if (is_write)
return write_memory(target, args);
return read_memory(target, args);
}
static int arch_state(struct target *target)
{
return ERROR_OK;
@@ -2325,10 +2380,10 @@ static int wait_for_authbusy(struct target *target)
uint32_t dminfo = dbus_read(target, DMINFO);
if (!get_field(dminfo, DMINFO_AUTHBUSY))
break;
if (time(NULL) - start > riscv_command_timeout_sec) {
if (time(NULL) - start > riscv_get_command_timeout_sec()) {
LOG_ERROR("Timed out after %ds waiting for authbusy to go low (dminfo=0x%x). "
"Increase the timeout with riscv set_command_timeout_sec.",
riscv_command_timeout_sec,
riscv_get_command_timeout_sec(),
dminfo);
return ERROR_FAIL;
}
@@ -2369,17 +2424,27 @@ static int riscv011_authdata_write(struct target *target, uint32_t value, unsign
return ERROR_OK;
}
static bool riscv011_get_impebreak(const struct target *target)
{
return false;
}
static unsigned int riscv011_get_progbufsize(const struct target *target)
{
return 0;
}
static int init_target(struct command_context *cmd_ctx,
struct target *target)
{
LOG_DEBUG("init");
RISCV_INFO(generic_info);
generic_info->get_register = get_register;
generic_info->set_register = set_register;
generic_info->read_memory = read_memory;
generic_info->access_memory = access_memory;
generic_info->authdata_read = &riscv011_authdata_read;
generic_info->authdata_write = &riscv011_authdata_write;
generic_info->print_info = &riscv011_print_info;
generic_info->get_impebreak = &riscv011_get_impebreak;
generic_info->get_progbufsize = &riscv011_get_progbufsize;
generic_info->version_specific = calloc(1, sizeof(riscv011_info_t));
if (!generic_info->version_specific)
@@ -2387,7 +2452,7 @@ static int init_target(struct command_context *cmd_ctx,
/* Assume 32-bit until we discover the real value in examine(). */
generic_info->xlen = 32;
riscv_init_registers(target);
riscv011_reg_init_all(target);
return ERROR_OK;
}
@@ -2409,7 +2474,5 @@ struct target_type riscv011_target = {
.assert_reset = assert_reset,
.deassert_reset = deassert_reset,
.write_memory = write_memory,
.arch_state = arch_state,
};