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:
committed by
Tomas Vanek
parent
ab22b0bf8f
commit
5754aebc49
@@ -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,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user