Merge pull request #1181 from en-sc/en-sc/reg-invalidate
target/riscv: clean-up register invalidation
This commit is contained in:
commit
cf9963ad81
|
@ -1136,7 +1136,7 @@ static int execute_resume(struct target *target, bool step)
|
||||||
}
|
}
|
||||||
|
|
||||||
target->state = TARGET_RUNNING;
|
target->state = TARGET_RUNNING;
|
||||||
register_cache_invalidate(target->reg_cache);
|
riscv_reg_cache_invalidate_all(target);
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2728,6 +2728,13 @@ static int handle_became_unavailable(struct target *target,
|
||||||
enum riscv_hart_state previous_riscv_state)
|
enum riscv_hart_state previous_riscv_state)
|
||||||
{
|
{
|
||||||
RISCV013_INFO(info);
|
RISCV013_INFO(info);
|
||||||
|
|
||||||
|
if (riscv_reg_cache_any_dirty(target, LOG_LVL_WARNING))
|
||||||
|
LOG_TARGET_WARNING(target, "Discarding values of dirty registers "
|
||||||
|
"(due to target becoming unavailable).");
|
||||||
|
|
||||||
|
riscv_reg_cache_invalidate_all(target);
|
||||||
|
|
||||||
info->dcsr_ebreak_is_set = false;
|
info->dcsr_ebreak_is_set = false;
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
@ -5442,6 +5449,8 @@ static int riscv013_step_or_resume_current_hart(struct target *target,
|
||||||
if (riscv_reg_flush_all(target) != ERROR_OK)
|
if (riscv_reg_flush_all(target) != ERROR_OK)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
|
|
||||||
|
riscv_reg_cache_invalidate_all(target);
|
||||||
|
|
||||||
dm013_info_t *dm = get_dm(target);
|
dm013_info_t *dm = get_dm(target);
|
||||||
/* Issue the resume command, and then wait for the current hart to resume. */
|
/* Issue the resume command, and then wait for the current hart to resume. */
|
||||||
uint32_t dmcontrol = DM_DMCONTROL_DMACTIVE | DM_DMCONTROL_RESUMEREQ;
|
uint32_t dmcontrol = DM_DMCONTROL_DMACTIVE | DM_DMCONTROL_RESUMEREQ;
|
||||||
|
|
|
@ -290,7 +290,6 @@ static const virt2phys_info_t sv57x4 = {
|
||||||
|
|
||||||
static enum riscv_halt_reason riscv_halt_reason(struct target *target);
|
static enum riscv_halt_reason riscv_halt_reason(struct target *target);
|
||||||
static void riscv_info_init(struct target *target, struct riscv_info *r);
|
static void riscv_info_init(struct target *target, struct riscv_info *r);
|
||||||
static void riscv_invalidate_register_cache(struct target *target);
|
|
||||||
static int riscv_step_rtos_hart(struct target *target);
|
static int riscv_step_rtos_hart(struct target *target);
|
||||||
|
|
||||||
static void riscv_sample_buf_maybe_add_timestamp(struct target *target, bool before)
|
static void riscv_sample_buf_maybe_add_timestamp(struct target *target, bool before)
|
||||||
|
@ -2485,10 +2484,15 @@ static int riscv_halt_go_all_harts(struct target *target)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// Safety check:
|
||||||
|
if (riscv_reg_cache_any_dirty(target, LOG_LVL_ERROR))
|
||||||
|
LOG_TARGET_INFO(target, "BUG: Registers should not be dirty while "
|
||||||
|
"the target is not halted!");
|
||||||
|
|
||||||
|
riscv_reg_cache_invalidate_all(target);
|
||||||
|
|
||||||
if (r->halt_go(target) != ERROR_OK)
|
if (r->halt_go(target) != ERROR_OK)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
|
|
||||||
riscv_invalidate_register_cache(target);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
|
@ -2572,7 +2576,11 @@ static int riscv_assert_reset(struct target *target)
|
||||||
struct target_type *tt = get_target_type(target);
|
struct target_type *tt = get_target_type(target);
|
||||||
if (!tt)
|
if (!tt)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
riscv_invalidate_register_cache(target);
|
|
||||||
|
if (riscv_reg_cache_any_dirty(target, LOG_LVL_INFO))
|
||||||
|
LOG_TARGET_INFO(target, "Discarding values of dirty registers.");
|
||||||
|
|
||||||
|
riscv_reg_cache_invalidate_all(target);
|
||||||
return tt->assert_reset(target);
|
return tt->assert_reset(target);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2699,7 +2707,15 @@ static int resume_go(struct target *target, int current,
|
||||||
static int resume_finish(struct target *target, int debug_execution)
|
static int resume_finish(struct target *target, int debug_execution)
|
||||||
{
|
{
|
||||||
assert(target->state == TARGET_HALTED);
|
assert(target->state == TARGET_HALTED);
|
||||||
register_cache_invalidate(target->reg_cache);
|
if (riscv_reg_cache_any_dirty(target, LOG_LVL_ERROR)) {
|
||||||
|
/* If this happens, it means there is a bug in the previous
|
||||||
|
* register-flushing algorithm: not all registers were flushed
|
||||||
|
* back to the target in preparation for the resume.*/
|
||||||
|
LOG_TARGET_ERROR(target,
|
||||||
|
"BUG: registers should have been flushed by this point.");
|
||||||
|
}
|
||||||
|
|
||||||
|
riscv_reg_cache_invalidate_all(target);
|
||||||
|
|
||||||
target->state = debug_execution ? TARGET_DEBUG_RUNNING : TARGET_RUNNING;
|
target->state = debug_execution ? TARGET_DEBUG_RUNNING : TARGET_RUNNING;
|
||||||
target->debug_reason = DBG_REASON_NOTHALTED;
|
target->debug_reason = DBG_REASON_NOTHALTED;
|
||||||
|
@ -4001,7 +4017,15 @@ static int riscv_openocd_step_impl(struct target *target, int current,
|
||||||
LOG_TARGET_ERROR(target, "Unable to step rtos hart.");
|
LOG_TARGET_ERROR(target, "Unable to step rtos hart.");
|
||||||
}
|
}
|
||||||
|
|
||||||
register_cache_invalidate(target->reg_cache);
|
if (riscv_reg_cache_any_dirty(target, LOG_LVL_ERROR)) {
|
||||||
|
/* If this happens, it means there is a bug in the previous
|
||||||
|
* register-flushing algorithm: not all registers were flushed
|
||||||
|
* back to the target prior to single-step. */
|
||||||
|
LOG_TARGET_ERROR(target,
|
||||||
|
"BUG: registers should have been flushed by this point.");
|
||||||
|
}
|
||||||
|
|
||||||
|
riscv_reg_cache_invalidate_all(target);
|
||||||
|
|
||||||
if (info->isrmask_mode == RISCV_ISRMASK_STEPONLY)
|
if (info->isrmask_mode == RISCV_ISRMASK_STEPONLY)
|
||||||
if (riscv_interrupts_restore(target, current_mstatus) != ERROR_OK) {
|
if (riscv_interrupts_restore(target, current_mstatus) != ERROR_OK) {
|
||||||
|
@ -5177,7 +5201,7 @@ COMMAND_HANDLER(riscv_exec_progbuf)
|
||||||
if (riscv_reg_flush_all(target) != ERROR_OK)
|
if (riscv_reg_flush_all(target) != ERROR_OK)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
int error = riscv_program_exec(&prog, target);
|
int error = riscv_program_exec(&prog, target);
|
||||||
riscv_invalidate_register_cache(target);
|
riscv_reg_cache_invalidate_all(target);
|
||||||
|
|
||||||
if (error != ERROR_OK) {
|
if (error != ERROR_OK) {
|
||||||
LOG_TARGET_ERROR(target, "exec_progbuf: Program buffer execution failed.");
|
LOG_TARGET_ERROR(target, "exec_progbuf: Program buffer execution failed.");
|
||||||
|
@ -5731,8 +5755,6 @@ static int riscv_resume_go_all_harts(struct target *target)
|
||||||
} else {
|
} else {
|
||||||
LOG_TARGET_DEBUG(target, "Hart requested resume, but was already resumed.");
|
LOG_TARGET_DEBUG(target, "Hart requested resume, but was already resumed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
riscv_invalidate_register_cache(target);
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5826,17 +5848,6 @@ unsigned int riscv_vlenb(const struct target *target)
|
||||||
return r->vlenb;
|
return r->vlenb;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void riscv_invalidate_register_cache(struct target *target)
|
|
||||||
{
|
|
||||||
/* Do not invalidate the register cache if it is not yet set up
|
|
||||||
* (e.g. when the target failed to get examined). */
|
|
||||||
if (!target->reg_cache)
|
|
||||||
return;
|
|
||||||
|
|
||||||
LOG_TARGET_DEBUG(target, "Invalidating register cache.");
|
|
||||||
register_cache_invalidate(target->reg_cache);
|
|
||||||
}
|
|
||||||
|
|
||||||
int riscv_get_hart_state(struct target *target, enum riscv_hart_state *state)
|
int riscv_get_hart_state(struct target *target, enum riscv_hart_state *state)
|
||||||
{
|
{
|
||||||
RISCV_INFO(r);
|
RISCV_INFO(r);
|
||||||
|
|
|
@ -888,6 +888,34 @@ static int riscv_set_or_write_register(struct target *target,
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool riscv_reg_cache_any_dirty(const struct target *target, int log_level)
|
||||||
|
{
|
||||||
|
bool any_dirty = false;
|
||||||
|
|
||||||
|
if (!target->reg_cache)
|
||||||
|
return any_dirty;
|
||||||
|
|
||||||
|
for (unsigned int number = 0; number < target->reg_cache->num_regs; ++number) {
|
||||||
|
const struct reg * const reg = riscv_reg_impl_cache_entry(target, number);
|
||||||
|
assert(riscv_reg_impl_is_initialized(reg));
|
||||||
|
if (reg->dirty) {
|
||||||
|
log_printf_lf(log_level, __FILE__, __LINE__, __func__,
|
||||||
|
"[%s] Register %s is dirty!", target_name(target), reg->name);
|
||||||
|
any_dirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return any_dirty;
|
||||||
|
}
|
||||||
|
|
||||||
|
void riscv_reg_cache_invalidate_all(struct target *target)
|
||||||
|
{
|
||||||
|
if (!target->reg_cache)
|
||||||
|
return;
|
||||||
|
|
||||||
|
LOG_TARGET_DEBUG(target, "Invalidating register cache.");
|
||||||
|
register_cache_invalidate(target->reg_cache);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This function is used to change the value of a register. The new value may
|
* This function is used to change the value of a register. The new value may
|
||||||
* be cached, and may not be written until the hart is resumed.
|
* be cached, and may not be written until the hart is resumed.
|
||||||
|
|
|
@ -21,6 +21,17 @@ void riscv_reg_free_all(struct target *target);
|
||||||
|
|
||||||
/** Write all dirty registers to the target. */
|
/** Write all dirty registers to the target. */
|
||||||
int riscv_reg_flush_all(struct target *target);
|
int riscv_reg_flush_all(struct target *target);
|
||||||
|
/**
|
||||||
|
* Check whether there are any dirty registers in the OpenOCD's register cache.
|
||||||
|
* In addition, all dirty registers will be reported to the log using the
|
||||||
|
* supplied "log_level".
|
||||||
|
*/
|
||||||
|
bool riscv_reg_cache_any_dirty(const struct target *target, int log_level);
|
||||||
|
/**
|
||||||
|
* Invalidate all registers - forget their cached register values.
|
||||||
|
* WARNING: If a register was dirty, its walue will be silently lost!
|
||||||
|
*/
|
||||||
|
void riscv_reg_cache_invalidate_all(struct target *target);
|
||||||
/**
|
/**
|
||||||
* Set the register value. For cacheable registers, only the cache is updated
|
* Set the register value. For cacheable registers, only the cache is updated
|
||||||
* (write-back mode).
|
* (write-back mode).
|
||||||
|
|
Loading…
Reference in New Issue