When a trigger type is "disabled", tdata2 and tdata3 must accept values that are valid for some supported trigger type. Additionally, writing 0 to tdata1 must result in the type becoming "disabled". This is important for the prescribed sequences for updating triggers.
Implement write tdata=0 -> disabled behaviour and permissive accepting of tdata2/3 values in disabled state. This implementation could be improved by checking tdata2/3 values against supported trigger types, but it is good enough to be usable by software. >From the RISC-V Debug Specification for tdata1: Writing 0 to this register must result in a trigger that is disabled. If this trigger supports multiple types, then the hardware should disable it by changing type to 15. and, when type=15: This trigger is disabled. In this state, tdata2 and tdata3 can be written with any value that is supported for any of the types this trigger implements. Signed-off-by: Nicholas Piggin <[email protected]> --- target/riscv/debug.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/target/riscv/debug.c b/target/riscv/debug.c index 2190c25f23..c92bd9860e 100644 --- a/target/riscv/debug.c +++ b/target/riscv/debug.c @@ -827,6 +827,28 @@ static void itrigger_reg_write(CPURISCVState *env, target_ulong index, } } +static void anytype_reg_write(CPURISCVState *env, target_ulong index, + int tdata_index, target_ulong val) +{ + /* + * This should check the value is valid for at least one of the supported + * trigger types. + */ + switch (tdata_index) { + case TDATA1: + env->tdata1[env->trigger_cur] = val; + break; + case TDATA2: + env->tdata2[env->trigger_cur] = val; + break; + case TDATA3: + env->tdata3[env->trigger_cur] = val; + break; + default: + g_assert_not_reached(); + } +} + static int itrigger_get_adjust_count(CPURISCVState *env) { int count = itrigger_get_count(env, env->trigger_cur), executed; @@ -883,6 +905,10 @@ void tdata_csr_write(CPURISCVState *env, int tdata_index, target_ulong val) } if (tdata_index == TDATA1) { + if (val == 0) { + /* special case, writing 0 results in disabled trigger */ + val = build_tdata1(env, TRIGGER_TYPE_UNAVAIL, 0, 0); + } trigger_type = extract_trigger_type(env, val); } @@ -897,6 +923,9 @@ void tdata_csr_write(CPURISCVState *env, int tdata_index, target_ulong val) itrigger_reg_write(env, env->trigger_cur, tdata_index, val); check_itrigger = true; break; + case TRIGGER_TYPE_UNAVAIL: + anytype_reg_write(env, env->trigger_cur, tdata_index, val); + break; case TRIGGER_TYPE_INT: case TRIGGER_TYPE_EXCP: case TRIGGER_TYPE_EXT_SRC: @@ -904,7 +933,6 @@ void tdata_csr_write(CPURISCVState *env, int tdata_index, target_ulong val) trigger_type); break; case TRIGGER_TYPE_NO_EXIST: - case TRIGGER_TYPE_UNAVAIL: qemu_log_mask(LOG_GUEST_ERROR, "trigger type: %d does not exit\n", trigger_type); break; -- 2.51.0
