On 8/18/2026 6:31 PM, Brian Cain wrote:
> Interrupts 3 through 5 are routed to guest mode when CCR:GIE and the
> matching CCR:VV bit are set.  Enter through GEVB rather than EVB,
> record the pre-entry state in GSR and the return address in GELR, and
> read the vector ID from the l2vic.
> 
> Signed-off-by: Brian Cain <[email protected]>
> ---
>  target/hexagon/reg_fields_def.h.inc |  7 +++
>  target/hexagon/cpu.c                |  5 ++
>  target/hexagon/hex_interrupts.c     | 87 ++++++++++++++++++++++++++---
>  3 files changed, 92 insertions(+), 7 deletions(-)
> 
> diff --git a/target/hexagon/reg_fields_def.h.inc 
> b/target/hexagon/reg_fields_def.h.inc
> index d2c706d56b5..29497fbcc4d 100644
> --- a/target/hexagon/reg_fields_def.h.inc
> +++ b/target/hexagon/reg_fields_def.h.inc
> @@ -136,6 +136,13 @@ DEF_REG_FIELD(CCR_VV1, 29, 1)
>  DEF_REG_FIELD(CCR_VV2, 30, 1)
>  DEF_REG_FIELD(CCR_VV3, 31, 1)
>  
> +/* GSR fields */
> +DEF_REG_FIELD(GSR_CAUSE, 0, 16)
> +DEF_REG_FIELD(GSR_CFI, 28, 1)
> +DEF_REG_FIELD(GSR_SS, 29, 1)
> +DEF_REG_FIELD(GSR_IE, 30, 1)
> +DEF_REG_FIELD(GSR_UM, 31, 1)
> +
>  /* ISDB ST fields */
>  DEF_REG_FIELD(ISDBST_WAITRUN, 24, 8)
>  DEF_REG_FIELD(ISDBST_ONOFF, 16, 8)
> diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c
> index 0a677840bcb..efaf569c6f8 100644
> --- a/target/hexagon/cpu.c
> +++ b/target/hexagon/cpu.c
> @@ -475,6 +475,11 @@ static void hexagon_cpu_realize(DeviceState *dev, Error 
> **errp)
>          error_setg(errp, "hexagon cpu requires 'tlb' link property to be 
> set");
>          return;
>      }
> +    if (!HEXAGON_CPU(dev)->l2vic) {
> +        error_setg(errp,
> +                   "hexagon cpu requires 'l2vic' link property to be set");
> +        return;
> +    }
>  #endif
>  
>      qemu_init_vcpu(cs);
> diff --git a/target/hexagon/hex_interrupts.c b/target/hexagon/hex_interrupts.c
> index 3534481da24..ea1ba0903dd 100644
> --- a/target/hexagon/hex_interrupts.c
> +++ b/target/hexagon/hex_interrupts.c
> @@ -11,6 +11,7 @@
>  #include "cpu_helper.h"
>  #include "exec/cpu-interrupt.h"
>  #include "hex_interrupts.h"
> +#include "hw/intc/hex-l2vic.h"
>  #include "macros.h"
>  #include "sys_macros.h"
>  #include "system/cpus.h"
> @@ -215,19 +216,75 @@ static void restore_state(CPUHexagonState *env, bool 
> int_accepted)
>      }
>  }
>  
> +static bool int_should_dtg(CPUHexagonState *env, int int_num)
> +{

What does dtg means?

> +    uint32_t ccr = env->t_sreg[HEX_SREG_CCR];
> +
> +    switch (int_num) {
> +    case 3:
> +        if (!GET_FIELD(CCR_VV1, ccr)) {
> +            return false;
> +        }
> +        break;
> +    case 4:
> +        if (!GET_FIELD(CCR_VV2, ccr)) {
> +            return false;
> +        }
> +        break;
> +    case 5:
> +        if (!GET_FIELD(CCR_VV3, ccr)) {
> +            return false;
> +        }
> +        break;
> +    default:
> +        return false;
> +    }
> +
> +    return GET_FIELD(CCR_GIE, ccr);
> +}
> +
> +static void guest_interrupt_entry(CPUHexagonState *env, uint32_t cause,
> +                                  uint32_t event_pc)
> +{
> +    uint32_t old_ssr = env->t_sreg[HEX_SREG_SSR];
> +    uint32_t new_ssr = old_ssr;
> +    uint32_t ccr = env->t_sreg[HEX_SREG_CCR];
> +    uint32_t gsr = 0;
> +
> +    gsr = deposit32(gsr, reg_field_info[GSR_CAUSE].offset,
> +                    reg_field_info[GSR_CAUSE].width, cause);
> +    gsr = deposit32(gsr, reg_field_info[GSR_SS].offset,
> +                    reg_field_info[GSR_SS].width,
> +                    GET_SSR_FIELD(SSR_SS, old_ssr));
> +    gsr = deposit32(gsr, reg_field_info[GSR_UM].offset,
> +                    reg_field_info[GSR_UM].width,
> +                    !GET_SSR_FIELD(SSR_GM, old_ssr));
> +    gsr = deposit32(gsr, reg_field_info[GSR_IE].offset,
> +                    reg_field_info[GSR_IE].width,
> +                    GET_FIELD(CCR_GIE, ccr));
> +    env->greg[HEX_GREG_GSR] = gsr;
> +
> +    fSET_FIELD(new_ssr, SSR_SS, 0);
> +    fSET_FIELD(new_ssr, SSR_GM, 1);
> +    env->t_sreg[HEX_SREG_SSR] = new_ssr;
> +    hexagon_modify_ssr(env, new_ssr, old_ssr);
> +
> +    SET_SYSTEM_FIELD(env, HEX_SREG_CCR, CCR_GIE, 0);
> +    env->greg[HEX_GREG_GELR] = event_pc;
> +    env->gpr[HEX_REG_PC] = env->t_sreg[HEX_SREG_GEVB] |
> +                           (HEX_EVENT_INT0 << 2);
> +}
> +
>  static void hex_accept_int(CPUHexagonState *env, int int_num)
>  {
>      CPUState *cs = env_cpu(env);
>      HexagonCPU *cpu = env_archcpu(env);
> -    uint32_t evb =
> -        hexagon_globalreg_read(cpu->globalregs, HEX_SREG_EVB,
> -                               env->threadId);
>      const int exe_mode = get_exe_mode(env);
>      const bool in_wait_mode = exe_mode == HEX_EXE_MODE_WAIT;
> +    uint32_t elr;
>  
>      set_ipend_bit(env, int_num, 0);
>      set_iad_bit(env, int_num, 1);
> -    set_ssr_ex_cause(env, 1, HEX_CAUSE_INT0 | int_num);
>      cs->exception_index = HEX_EVENT_INT0 + int_num;
>      env->cause_code = HEX_EVENT_INT0 + int_num;
>      clear_pending_locks(env);
> @@ -235,15 +292,31 @@ static void hex_accept_int(CPUHexagonState *env, int 
> int_num)
>          qemu_log_mask(CPU_LOG_INT,
>              "%s: thread " TARGET_FMT_ld " resuming, exiting WAIT mode\n",
>              __func__, env->threadId);
> -        set_elr(env, env->wait_next_pc);
> +        elr = env->wait_next_pc;
>          clear_wait_mode(env);
>          cs->halted = false;
>      } else if (env->k0_lock_state == HEX_LOCK_WAITING) {
>          g_assert_not_reached();
>      } else {
> -        set_elr(env, env->gpr[HEX_REG_PC]);
> +        elr = env->gpr[HEX_REG_PC];
> +    }
> +
> +    if (int_should_dtg(env, int_num)) {
> +        int vic_group = int_num - 2;
> +        uint32_t vid_packed = l2vic_read_vid(cpu->l2vic, vic_group / 2);
> +        uint32_t vid = extract32(vid_packed,
> +                                 (vic_group & 1) ? 16 : 0, 16);
> +
> +        guest_interrupt_entry(env, vid, elr);
> +    } else {
> +        uint32_t evb =
> +            hexagon_globalreg_read(cpu->globalregs, HEX_SREG_EVB,
> +                                   env->threadId);
> +
> +        set_ssr_ex_cause(env, 1, HEX_CAUSE_INT0 | int_num);
> +        set_elr(env, elr);
> +        env->gpr[HEX_REG_PC] = evb | (cs->exception_index << 2);
>      }
> -    env->gpr[HEX_REG_PC] = evb | (cs->exception_index << 2);
>      if (get_ipend(env) == 0) {
>          restore_state(env, true);
>      }


Reply via email to