Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

target/riscv: access registers via reg->type #1187

Open
wants to merge 2 commits into
base: riscv
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 19 additions & 7 deletions doc/openocd.texi
Original file line number Diff line number Diff line change
Expand Up @@ -9271,7 +9271,7 @@ various operations. The current target may be changed
by using @command{targets} command with the name of the
target which should become current.

@deffn {Command} {reg} [(number|name) [(value|'force')]]
@deffn {Command} {reg} [(number|name)] [value] ['force']
Access a single register by @var{number} or by its @var{name}.
The target must generally be halted before access to CPU core
registers is allowed. Depending on the hardware, some other
Expand All @@ -9285,15 +9285,17 @@ which are also dirty (and will be written back later)
are flagged as such.

@emph{With number/name}: display that register's value.
Use @var{force} argument to read directly from the target,
bypassing any internal cache.
Use @var{force} argument to read directly from the target
(as opposed to OpenOCD's internal register cache).

@emph{With both number/name and value}: set register's value.
Writes may be held in a writeback cache internal to OpenOCD,
so that setting the value marks the register as dirty instead
of immediately flushing that value. Resuming CPU execution
(including by single stepping) or otherwise activating the
relevant module will flush such values.
relevant module will flush such values. The use of @var{force}
causes the register value to be written to the target
immediately.

Cores may have surprisingly many registers in their
Debug and trace infrastructure:
Expand All @@ -9310,10 +9312,13 @@ Debug and trace infrastructure:
@end example
@end deffn

@deffn {Command} {set_reg} dict
Set register values of the target.
@deffn {Command} {set_reg} ['-force'] dict
Set register values of the target. The new register values may be
kept in OpenOCD's cache and not written to the target immediately
(unless @var{-force} is used).

@itemize
@item @option{-force} ... Force immediate write of the new register values.
@item @var{dict} ... Tcl dictionary with pairs of register names and values.
@end itemize

Expand All @@ -9329,7 +9334,7 @@ set_reg @{pc 0 sp 0x1000@}
Get register values from the target and return them as Tcl dictionary with pairs
of register names and values.
If option "-force" is set, the register values are read directly from the
target, bypassing any caching.
target, not from OpenOCD's internal cache.

@itemize
@item @var{list} ... List of register names
Expand All @@ -9343,6 +9348,13 @@ get_reg @{pc sp@}
@end example
@end deffn

@deffn {Command} {flush_reg_cache} [-invalidate]
Flush the internal OpenOCD's register cache - write back the dirty register values to the target.
If @option{-invalidate} is set, also invalidate (forget) the OpenOCD's cached register values;
therefore the next call to get_reg is guaranteed to read the fresh register value directly
from the target.
@end deffn

@deffn {Command} {write_memory} address width data ['phys']
This function provides an efficient way to write to the target memory from a Tcl
script.
Expand Down
1 change: 1 addition & 0 deletions src/target/arc.c
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,7 @@ static int arc_set_register(struct reg *reg, uint8_t *buf)
static const struct reg_arch_type arc_reg_type = {
.get = arc_get_register,
.set = arc_set_register,
.flush = NULL,
};

/* GDB register groups. For now we support only general and "empty" */
Expand Down
1 change: 1 addition & 0 deletions src/target/armv4_5.c
Original file line number Diff line number Diff line change
Expand Up @@ -655,6 +655,7 @@ static int armv4_5_set_core_reg(struct reg *reg, uint8_t *buf)
static const struct reg_arch_type arm_reg_type = {
.get = armv4_5_get_core_reg,
.set = armv4_5_set_core_reg,
.flush = NULL,
};

struct reg_cache *arm_build_reg_cache(struct target *target, struct arm *arm)
Expand Down
1 change: 1 addition & 0 deletions src/target/armv7m.c
Original file line number Diff line number Diff line change
Expand Up @@ -786,6 +786,7 @@ int armv7m_arch_state(struct target *target)
static const struct reg_arch_type armv7m_reg_type = {
.get = armv7m_get_core_reg,
.set = armv7m_set_core_reg,
.flush = NULL,
};

/** Builds cache of architecturally defined registers. */
Expand Down
2 changes: 2 additions & 0 deletions src/target/armv8.c
Original file line number Diff line number Diff line change
Expand Up @@ -1714,6 +1714,7 @@ static int armv8_set_core_reg(struct reg *reg, uint8_t *buf)
static const struct reg_arch_type armv8_reg_type = {
.get = armv8_get_core_reg,
.set = armv8_set_core_reg,
.flush = NULL,
};

static int armv8_get_core_reg32(struct reg *reg)
Expand Down Expand Up @@ -1775,6 +1776,7 @@ static int armv8_set_core_reg32(struct reg *reg, uint8_t *buf)
static const struct reg_arch_type armv8_reg32_type = {
.get = armv8_get_core_reg32,
.set = armv8_set_core_reg32,
.flush = NULL,
};

/** Builds cache of architecturally defined registers. */
Expand Down
1 change: 1 addition & 0 deletions src/target/avr32_ap7k.c
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ static int avr32_set_core_reg(struct reg *reg, uint8_t *buf)
static const struct reg_arch_type avr32_reg_type = {
.get = avr32_get_core_reg,
.set = avr32_set_core_reg,
.flush = NULL,
};

static struct reg_cache *avr32_build_reg_cache(struct target *target)
Expand Down
1 change: 1 addition & 0 deletions src/target/cortex_m.c
Original file line number Diff line number Diff line change
Expand Up @@ -2431,6 +2431,7 @@ static const struct dwt_reg dwt_comp[] = {
static const struct reg_arch_type dwt_reg_type = {
.get = cortex_m_dwt_get_reg,
.set = cortex_m_dwt_set_reg,
.flush = NULL,
};

static void cortex_m_dwt_addreg(struct target *t, struct reg *r, const struct dwt_reg *d)
Expand Down
1 change: 1 addition & 0 deletions src/target/dsp563xx.c
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,7 @@ static int dsp563xx_set_core_reg(struct reg *reg, uint8_t *buf)
static const struct reg_arch_type dsp563xx_reg_type = {
.get = dsp563xx_get_core_reg,
.set = dsp563xx_set_core_reg,
.flush = NULL,
};

static void dsp563xx_build_reg_cache(struct target *target)
Expand Down
1 change: 1 addition & 0 deletions src/target/embeddedice.c
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ static int embeddedice_get_reg(struct reg *reg)
static const struct reg_arch_type eice_reg_type = {
.get = embeddedice_get_reg,
.set = embeddedice_set_reg_w_exec,
.flush = NULL,
};

/**
Expand Down
1 change: 1 addition & 0 deletions src/target/esirisc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1419,6 +1419,7 @@ static int esirisc_set_reg(struct reg *reg, uint8_t *buf)
static const struct reg_arch_type esirisc_reg_type = {
.get = esirisc_get_reg,
.set = esirisc_set_reg,
.flush = NULL,
};

static struct reg_cache *esirisc_build_reg_cache(struct target *target)
Expand Down
1 change: 1 addition & 0 deletions src/target/etb.c
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ static int etb_get_reg(struct reg *reg)
static const struct reg_arch_type etb_reg_type = {
.get = etb_get_reg,
.set = etb_set_reg_w_exec,
.flush = NULL,
};

struct reg_cache *etb_build_reg_cache(struct etb *etb)
Expand Down
1 change: 1 addition & 0 deletions src/target/etm.c
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ static int etm_write_reg(struct reg *reg, uint32_t value);
static const struct reg_arch_type etm_scan6_type = {
.get = etm_get_reg,
.set = etm_set_reg_w_exec,
.flush = NULL,
};

/* Look up register by ID ... most ETM instances only
Expand Down
1 change: 1 addition & 0 deletions src/target/lakemont.c
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,7 @@ static const struct reg_arch_type lakemont_reg_type = {
*/
.get = lakemont_get_core_reg,
.set = lakemont_set_core_reg,
.flush = NULL,
};

struct reg_cache *lakemont_build_reg_cache(struct target *t)
Expand Down
1 change: 1 addition & 0 deletions src/target/mem_ap.c
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ static int mem_ap_reg_set(struct reg *reg, uint8_t *buf)
static struct reg_arch_type mem_ap_reg_arch_type = {
.get = mem_ap_reg_get,
.set = mem_ap_reg_set,
.flush = NULL,
};

static const char *mem_ap_get_gdb_arch(const struct target *target)
Expand Down
1 change: 1 addition & 0 deletions src/target/mips32.c
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,7 @@ int mips32_arch_state(struct target *target)
static const struct reg_arch_type mips32_reg_type = {
.get = mips32_get_core_reg,
.set = mips32_set_core_reg,
.flush = NULL,
};

struct reg_cache *mips32_build_reg_cache(struct target *target)
Expand Down
1 change: 1 addition & 0 deletions src/target/mips64.c
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,7 @@ int mips64_arch_state(struct target *target)
static const struct reg_arch_type mips64_reg_type = {
.get = mips64_get_core_reg,
.set = mips64_set_core_reg,
.flush = NULL,
};

int mips64_build_reg_cache(struct target *target)
Expand Down
1 change: 1 addition & 0 deletions src/target/openrisc/or1k.c
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,7 @@ static int or1k_set_core_reg(struct reg *reg, uint8_t *buf)
static const struct reg_arch_type or1k_reg_type = {
.get = or1k_get_core_reg,
.set = or1k_set_core_reg,
.flush = NULL,
};

static struct reg_cache *or1k_build_reg_cache(struct target *target)
Expand Down
62 changes: 62 additions & 0 deletions src/target/register.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

#include "register.h"
#include <helper/log.h>
#include <target/target.h>
#include <target/target_type.h>

/**
* @file
Expand Down Expand Up @@ -115,12 +117,72 @@ static int register_set_dummy_core_reg(struct reg *reg, uint8_t *buf)
return ERROR_OK;
}

static int register_flush_dummy(struct reg *reg)
{
reg->dirty = false;

return ERROR_OK;
}

static const struct reg_arch_type dummy_type = {
.get = register_get_dummy_core_reg,
.set = register_set_dummy_core_reg,
.flush = register_flush_dummy,
};

void register_init_dummy(struct reg *reg)
{
reg->type = &dummy_type;
}

int register_flush(const struct target *target, struct reg *reg, bool invalidate)
{
if (!reg) {
LOG_ERROR("BUG: %s called with NULL", __func__);
return ERROR_FAIL;
}

if (!reg->exist) {
LOG_ERROR("BUG: %s called with non-existent register", __func__);
return ERROR_FAIL;
}

if (!reg->dirty) {
LOG_TARGET_DEBUG(target, "Register '%s' is not dirty, nothing to flush", reg->name);
if (reg->valid && invalidate) {
LOG_TARGET_DEBUG(target, "Invalidating register '%s'", reg->name);
reg->valid = false;
}
return ERROR_OK;
}

if (!reg->type->flush) {
LOG_TARGET_ERROR(target, "Unable to flush dirty register '%s' - operation not yet supported "
"by %s implementation in OpenOCD", reg->name, target->type->name);
return ERROR_NOT_IMPLEMENTED;
}

if (!reg->valid) {
LOG_ERROR("BUG: Register '%s' is not valid, but flush attempted", reg->name);
return ERROR_FAIL;
}

LOG_TARGET_DEBUG(target, "Flushing register '%s'", reg->name);

int result = reg->type->flush(reg);
if (result != ERROR_OK) {
LOG_TARGET_ERROR(target, "Failed to flush register '%s'", reg->name);
return result;
}

if (reg->dirty) {
LOG_ERROR("BUG: Register '%s' remained dirty after flushing", reg->name);
return ERROR_FAIL;
}
if (reg->valid && invalidate) {
LOG_TARGET_DEBUG(target, "Invalidating register '%s' after flush", reg->name);
reg->valid = false;
}

return ERROR_OK;
}
4 changes: 4 additions & 0 deletions src/target/register.h
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ struct reg_cache {
struct reg_arch_type {
int (*get)(struct reg *reg);
int (*set)(struct reg *reg, uint8_t *buf);
int (*flush)(struct reg *reg);
};

struct reg *register_get_by_number(struct reg_cache *first,
Expand All @@ -163,4 +164,7 @@ void register_cache_invalidate(struct reg_cache *cache);

void register_init_dummy(struct reg *reg);

/* Flushes the register. Also invalidates the cached register value if invalidate == true */
int register_flush(const struct target *target, struct reg *reg, bool invalidate);

#endif /* OPENOCD_TARGET_REGISTER_H */
9 changes: 4 additions & 5 deletions src/target/riscv/program.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,10 @@ int riscv_program_init(struct riscv_program *p, struct target *t);
/* Write the program to the program buffer. */
int riscv_program_write(struct riscv_program *program);

/* Executes a program, returning 0 if the program successfully executed. Note
* that this may cause registers to be saved or restored, which could result to
* calls to things like riscv013_reg_save which itself could require a
* program to execute. That's OK, just make sure this eventually terminates.
* */
/* Executes the RISC-V Program Buffer and returns ERROR_OK if the program
* buffer got successfully executed. In case of failure, more detailed error reason
* can be found in p->execution_result.
*/
int riscv_program_exec(struct riscv_program *p, struct target *t);

/* A lower level interface, you shouldn't use this unless you have a reason. */
Expand Down
Loading
Loading