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);
> }