On Wed, Jan 14, 2026 at 02:46:36PM +0800, Nicholas Piggin wrote:
> 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]>
Reviewed-by: Chao Liu <[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
>
>