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: new ebreak controls #1168

Open
wants to merge 1 commit 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
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 pc = riscv_private_config(target);
dcsr = set_field(dcsr, DCSR_EBREAKM, pc->dcsr_ebreak_ctls[RISCV_DCSR_EBREAK_M_CTL]);
dcsr = set_field(dcsr, DCSR_EBREAKS, pc->dcsr_ebreak_ctls[RISCV_DCSR_EBREAK_S_CTL]);
dcsr = set_field(dcsr, DCSR_EBREAKU, pc->dcsr_ebreak_ctls[RISCV_DCSR_EBREAK_U_CTL]);
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 pc = riscv_private_config(target);
dcsr = set_field(dcsr, CSR_DCSR_EBREAKM, pc->dcsr_ebreak_ctls[RISCV_DCSR_EBREAK_M_CTL]);
dcsr = set_field(dcsr, CSR_DCSR_EBREAKS, pc->dcsr_ebreak_ctls[RISCV_DCSR_EBREAK_S_CTL]);
dcsr = set_field(dcsr, CSR_DCSR_EBREAKU, pc->dcsr_ebreak_ctls[RISCV_DCSR_EBREAK_U_CTL]);
dcsr = set_field(dcsr, CSR_DCSR_EBREAKVS, pc->dcsr_ebreak_ctls[RISCV_DCSR_EBREAK_VS_CTL]);
dcsr = set_field(dcsr, CSR_DCSR_EBREAKVU, pc->dcsr_ebreak_ctls[RISCV_DCSR_EBREAK_VU_CTL]);
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 pc = riscv_private_config(target);
for (int i = 0; i < N_RISCV_DCSR_EBREAK_CTL; ++i)
if (pc->dcsr_ebreak_ctls[i])
return false;
return true;
}

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