void debug_exception_env(CPUXtensaState *new_env, uint32_t cause) { if (xtensa_get_cintlevel(new_env) < new_env->config->debug_level) { env = new_env; HELPER(debug_exception)(env->pc, cause); } }
void xtensa_cpu_do_interrupt(CPUState *cs) { XtensaCPU *cpu = XTENSA_CPU(cs); CPUXtensaState *env = &cpu->env; if (env->exception_index == EXC_IRQ) { qemu_log_mask(CPU_LOG_INT, "%s(EXC_IRQ) level = %d, cintlevel = %d, " "pc = %08x, a0 = %08x, ps = %08x, " "intset = %08x, intenable = %08x, " "ccount = %08x\n", __func__, env->pending_irq_level, xtensa_get_cintlevel(env), env->pc, env->regs[0], env->sregs[PS], env->sregs[INTSET], env->sregs[INTENABLE], env->sregs[CCOUNT]); handle_interrupt(env); } switch (env->exception_index) { case EXC_WINDOW_OVERFLOW4: case EXC_WINDOW_UNDERFLOW4: case EXC_WINDOW_OVERFLOW8: case EXC_WINDOW_UNDERFLOW8: case EXC_WINDOW_OVERFLOW12: case EXC_WINDOW_UNDERFLOW12: case EXC_KERNEL: case EXC_USER: case EXC_DOUBLE: case EXC_DEBUG: qemu_log_mask(CPU_LOG_INT, "%s(%d) " "pc = %08x, a0 = %08x, ps = %08x, ccount = %08x\n", __func__, env->exception_index, env->pc, env->regs[0], env->sregs[PS], env->sregs[CCOUNT]); if (env->config->exception_vector[env->exception_index]) { env->pc = relocated_vector(env, env->config->exception_vector[env->exception_index]); env->exception_taken = 1; } else { qemu_log("%s(pc = %08x) bad exception_index: %d\n", __func__, env->pc, env->exception_index); } break; case EXC_IRQ: break; default: qemu_log("%s(pc = %08x) unknown exception_index: %d\n", __func__, env->pc, env->exception_index); break; } check_interrupts(env); }
void check_interrupts(CPUXtensaState *env) { int minlevel = xtensa_get_cintlevel(env); uint32_t int_set_enabled = env->sregs[INTSET] & env->sregs[INTENABLE]; int level; /* If the CPU is halted advance CCOUNT according to the vm_clock time * elapsed since the moment when it was advanced last time. */ if (env->halted) { int64_t now = qemu_get_clock_ns(vm_clock); xtensa_advance_ccount(env, muldiv64(now - env->halt_clock, env->config->clock_freq_khz, 1000000)); env->halt_clock = now; } for (level = env->config->nlevel; level > minlevel; --level) { if (env->config->level_mask[level] & int_set_enabled) { env->pending_irq_level = level; cpu_interrupt(env, CPU_INTERRUPT_HARD); qemu_log_mask(CPU_LOG_INT, "%s level = %d, cintlevel = %d, " "pc = %08x, a0 = %08x, ps = %08x, " "intset = %08x, intenable = %08x, " "ccount = %08x\n", __func__, level, xtensa_get_cintlevel(env), env->pc, env->regs[0], env->sregs[PS], env->sregs[INTSET], env->sregs[INTENABLE], env->sregs[CCOUNT]); return; } } env->pending_irq_level = 0; cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); }
/*! * Handle penging IRQ. * For the high priority interrupt jump to the corresponding interrupt vector. * For the level-1 interrupt convert it to either user, kernel or double * exception with the 'level-1 interrupt' exception cause. */ static void handle_interrupt(CPUXtensaState *env) { int level = env->pending_irq_level; if (level > xtensa_get_cintlevel(env) && level <= env->config->nlevel && (env->config->level_mask[level] & env->sregs[INTSET] & env->sregs[INTENABLE])) { if (level > 1) { env->sregs[EPC1 + level - 1] = env->pc; env->sregs[EPS2 + level - 2] = env->sregs[PS]; env->sregs[PS] = (env->sregs[PS] & ~PS_INTLEVEL) | level | PS_EXCM; env->pc = relocated_vector(env, env->config->interrupt_vector[level]); } else { env->sregs[EXCCAUSE] = LEVEL1_INTERRUPT_CAUSE; if (env->sregs[PS] & PS_EXCM) { if (env->config->ndepc) { env->sregs[DEPC] = env->pc; } else { env->sregs[EPC1] = env->pc; } env->exception_index = EXC_DOUBLE; } else { env->sregs[EPC1] = env->pc; env->exception_index = (env->sregs[PS] & PS_UM) ? EXC_USER : EXC_KERNEL; } env->sregs[PS] |= PS_EXCM; } env->exception_taken = 1; } }