Skip to content

Commit

Permalink
target/riscv: new ebreak controls
Browse files Browse the repository at this point in the history
* Deprecate `riscv set_ebreak*` commands.
* Introduce RISC-V-sepecific `configure` parameter `-ebreak` instead.
* Separate controls for VS and VU modes.

Change-Id: I0ff88318dcb52af6923eb9f20f9d0c056ad09cf0
Signed-off-by: Evgeniy Naydanov <[email protected]>
  • Loading branch information
en-sc committed Dec 11, 2024
1 parent 1bf7efb commit cbc0bb6
Show file tree
Hide file tree
Showing 6 changed files with 294 additions and 80 deletions.
34 changes: 19 additions & 15 deletions doc/openocd.texi
Original file line number Diff line number Diff line change
Expand Up @@ -11225,6 +11225,25 @@ follows:
</feature>
@end example

@subsection RISC-V @code{$target_name configure} options
@itemize
@item @code{-ebreak} [@option{m}|@option{s}|@option{u}|@option{vs}|@option{vu}]
@option{exception}|@option{halt} -- sets the desired behavior of @code{ebreak}
instruction on the target. Defaults to @option{halt} in all execution modes.

@itemize
@item The last argument specifies which action should be taken when a hart
executes a @code{ebreak}.

@item The first argument specifies in which execution mode the @code{ebreak}
behavior should change. If this option is omitted the configuration affects
all execution modes.

@item @code{cget} returns a TCL @code{dict} of execution mode - @code{ebreak}
action pairs.
@end itemize
@end itemize

@subsection RISC-V Debug Configuration Commands

@deffn {Command} {riscv dump_sample_buf} [base64]
Expand Down Expand Up @@ -11434,21 +11453,6 @@ Keep in mind, disabling the option does not guarantee that single stepping will
To make that happen, dcsr.stepie would have to be written to 1 as well.
@end deffn

@deffn {Command} {riscv set_ebreakm} [on|off]
Control dcsr.ebreakm. When on (default), M-mode ebreak instructions trap to
OpenOCD. When off, they generate a breakpoint exception handled internally.
@end deffn

@deffn {Command} {riscv set_ebreaks} [on|off]
Control dcsr.ebreaks. When on (default), S-mode ebreak instructions trap to
OpenOCD. When off, they generate a breakpoint exception handled internally.
@end deffn

@deffn {Command} {riscv set_ebreaku} [on|off]
Control dcsr.ebreaku. When on (default), U-mode ebreak instructions trap to
OpenOCD. When off, they generate a breakpoint exception handled internally.
@end deffn

The commands below can be used to prevent OpenOCD from using certain RISC-V trigger features.
For example in cases when there are known issues in the target hardware.

Expand Down
22 changes: 12 additions & 10 deletions src/target/riscv/riscv-011.c
Original file line number Diff line number Diff line change
Expand Up @@ -1074,9 +1074,18 @@ 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)
{
RISCV_INFO(r);
riscv011_info_t *info = get_info(target);

LOG_DEBUG("step=%d", step);
Expand Down Expand Up @@ -1108,10 +1117,7 @@ static int execute_resume(struct target *target, bool step)
}
}

info->dcsr = set_field(info->dcsr, DCSR_EBREAKM, r->riscv_ebreakm);
info->dcsr = set_field(info->dcsr, DCSR_EBREAKS, r->riscv_ebreaks);
info->dcsr = set_field(info->dcsr, DCSR_EBREAKU, r->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)
Expand Down Expand Up @@ -1928,7 +1934,6 @@ static int riscv011_resume(struct target *target, int current,

static int assert_reset(struct target *target)
{
RISCV_INFO(r);
riscv011_info_t *info = get_info(target);
/* TODO: Maybe what I implemented here is more like soft_reset_halt()? */

Expand All @@ -1942,10 +1947,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, r->riscv_ebreakm);
info->dcsr = set_field(info->dcsr, DCSR_EBREAKS, r->riscv_ebreaks);
info->dcsr = set_field(info->dcsr, DCSR_EBREAKU, r->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;
Expand Down
19 changes: 11 additions & 8 deletions src/target/riscv/riscv-013.c
Original file line number Diff line number Diff line change
Expand Up @@ -1604,19 +1604,19 @@ static int set_dcsr_ebreak(struct target *target, bool step)
if (dm013_select_target(target) != ERROR_OK)
return ERROR_FAIL;

RISCV_INFO(r);
RISCV013_INFO(info);
riscv_reg_t original_dcsr, dcsr;
/* We want to twiddle some bits in the debug CSR so debugging works. */
if (riscv_reg_get(target, &dcsr, GDB_REGNO_DCSR) != ERROR_OK)
return ERROR_FAIL;
original_dcsr = dcsr;
dcsr = set_field(dcsr, CSR_DCSR_STEP, step);
dcsr = set_field(dcsr, CSR_DCSR_EBREAKM, r->riscv_ebreakm);
dcsr = set_field(dcsr, CSR_DCSR_EBREAKS, r->riscv_ebreaks && riscv_supports_extension(target, 'S'));
dcsr = set_field(dcsr, CSR_DCSR_EBREAKU, r->riscv_ebreaku && riscv_supports_extension(target, 'U'));
dcsr = set_field(dcsr, CSR_DCSR_EBREAKVS, r->riscv_ebreaku && riscv_supports_extension(target, 'H'));
dcsr = set_field(dcsr, CSR_DCSR_EBREAKVU, r->riscv_ebreaku && riscv_supports_extension(target, 'H'));
const struct riscv_private_config * const config = riscv_private_config(target);
dcsr = set_field(dcsr, CSR_DCSR_EBREAKM, config->dcsr_ebreak_fields[RISCV_MODE_M]);
dcsr = set_field(dcsr, CSR_DCSR_EBREAKS, config->dcsr_ebreak_fields[RISCV_MODE_S]);
dcsr = set_field(dcsr, CSR_DCSR_EBREAKU, config->dcsr_ebreak_fields[RISCV_MODE_U]);
dcsr = set_field(dcsr, CSR_DCSR_EBREAKVS, config->dcsr_ebreak_fields[RISCV_MODE_VS]);
dcsr = set_field(dcsr, CSR_DCSR_EBREAKVU, config->dcsr_ebreak_fields[RISCV_MODE_VU]);
if (dcsr != original_dcsr &&
riscv_reg_set(target, GDB_REGNO_DCSR, dcsr) != ERROR_OK)
return ERROR_FAIL;
Expand Down Expand Up @@ -2842,8 +2842,11 @@ static int assert_reset(struct target *target)

static bool dcsr_ebreak_config_equals_reset_value(const struct target *target)
{
RISCV_INFO(r);
return !(r->riscv_ebreakm || r->riscv_ebreaks || r->riscv_ebreaku);
const struct riscv_private_config * const config = riscv_private_config(target);
for (int i = 0; i < N_RISCV_MODE; ++i)
if (config->dcsr_ebreak_fields[i])
return false;
return true;
}

static int deassert_reset(struct target *target)
Expand Down
Loading

0 comments on commit cbc0bb6

Please sign in to comment.