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
> 
> 

Reply via email to