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