target/riscv: Fix the trigger writing sequence
According to section 5.6 in the RISC-V debug specification, the previous way to set triggers was incorrect, as was discussed as part of https://github.com/riscv/riscv-openocd/issues/870. This commit fixes the sequence to be in line with the specification as well as adds some comments to clarify for any future reader as to what is actually done. Change-Id: Iffc5cc0f866a466a7aaa72a4c53ee95c9080ac9d Signed-off-by: Marek Vrbka <marek.vrbka@codasip.com>
This commit is contained in:
parent
92c0319261
commit
ea115917b9
|
@ -572,33 +572,46 @@ static int set_trigger(struct target *target, unsigned int idx, riscv_reg_t tdat
|
||||||
riscv_reg_t tdata1_ignore_mask)
|
riscv_reg_t tdata1_ignore_mask)
|
||||||
{
|
{
|
||||||
riscv_reg_t tdata1_rb, tdata2_rb;
|
riscv_reg_t tdata1_rb, tdata2_rb;
|
||||||
|
// Select which trigger to use
|
||||||
if (riscv_set_register(target, GDB_REGNO_TSELECT, idx) != ERROR_OK)
|
if (riscv_set_register(target, GDB_REGNO_TSELECT, idx) != ERROR_OK)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
|
|
||||||
|
// Disable the trigger by writing 0 to it
|
||||||
|
if (riscv_set_register(target, GDB_REGNO_TDATA1, 0) != ERROR_OK)
|
||||||
|
return ERROR_FAIL;
|
||||||
|
|
||||||
|
// Set trigger data for tdata2 (and tdata3 if it was supported)
|
||||||
|
if (riscv_set_register(target, GDB_REGNO_TDATA2, tdata2) != ERROR_OK)
|
||||||
|
return ERROR_FAIL;
|
||||||
|
|
||||||
|
// Set trigger data for tdata1
|
||||||
if (riscv_set_register(target, GDB_REGNO_TDATA1, tdata1) != ERROR_OK)
|
if (riscv_set_register(target, GDB_REGNO_TDATA1, tdata1) != ERROR_OK)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
|
|
||||||
|
// Read back tdata1, tdata2, (tdata3), and check if the configuration is supported
|
||||||
if (riscv_get_register(target, &tdata1_rb, GDB_REGNO_TDATA1) != ERROR_OK)
|
if (riscv_get_register(target, &tdata1_rb, GDB_REGNO_TDATA1) != ERROR_OK)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
if ((tdata1 & ~tdata1_ignore_mask) != (tdata1_rb & ~tdata1_ignore_mask)) {
|
|
||||||
LOG_TARGET_DEBUG(target,
|
|
||||||
"Trigger %u doesn't support what we need; After writing 0x%"
|
|
||||||
PRIx64 " to tdata1 it contains 0x%" PRIx64
|
|
||||||
"; tdata1_ignore_mask=0x%" PRIx64,
|
|
||||||
idx, tdata1, tdata1_rb, tdata1_ignore_mask);
|
|
||||||
riscv_set_register(target, GDB_REGNO_TDATA1, 0);
|
|
||||||
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
|
||||||
}
|
|
||||||
if (riscv_set_register(target, GDB_REGNO_TDATA2, tdata2) != ERROR_OK)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
if (riscv_get_register(target, &tdata2_rb, GDB_REGNO_TDATA2) != ERROR_OK)
|
if (riscv_get_register(target, &tdata2_rb, GDB_REGNO_TDATA2) != ERROR_OK)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
if (tdata2 != tdata2_rb) {
|
bool tdata1_config_denied = (tdata1 & ~tdata1_ignore_mask) != (tdata1_rb & ~tdata1_ignore_mask);
|
||||||
LOG_TARGET_DEBUG(target,
|
bool tdata2_config_denied = tdata2 != tdata2_rb;
|
||||||
"Trigger %u doesn't support what we need; wrote 0x%"
|
if (tdata1_config_denied || tdata2_config_denied) {
|
||||||
PRIx64 " to tdata2 but read back 0x%" PRIx64,
|
LOG_TARGET_DEBUG(target, "Trigger %u doesn't support what we need.", idx);
|
||||||
idx, tdata2, tdata2_rb);
|
|
||||||
|
if (tdata1_config_denied)
|
||||||
|
LOG_TARGET_DEBUG(target,
|
||||||
|
"After writing 0x%" PRIx64 " to tdata1 it contains 0x%" PRIx64 "; tdata1_ignore_mask=0x%" PRIx64,
|
||||||
|
tdata1, tdata1_rb, tdata1_ignore_mask);
|
||||||
|
|
||||||
|
if (tdata2_config_denied)
|
||||||
|
LOG_TARGET_DEBUG(target,
|
||||||
|
"wrote 0x%" PRIx64 " to tdata2 but read back 0x%" PRIx64,
|
||||||
|
tdata2, tdata2_rb);
|
||||||
|
|
||||||
riscv_set_register(target, GDB_REGNO_TDATA1, 0);
|
riscv_set_register(target, GDB_REGNO_TDATA1, 0);
|
||||||
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue