153018216SPaolo Bonzini /* 253018216SPaolo Bonzini * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab. 353018216SPaolo Bonzini * All rights reserved. 453018216SPaolo Bonzini * 553018216SPaolo Bonzini * Redistribution and use in source and binary forms, with or without 653018216SPaolo Bonzini * modification, are permitted provided that the following conditions are met: 753018216SPaolo Bonzini * * Redistributions of source code must retain the above copyright 853018216SPaolo Bonzini * notice, this list of conditions and the following disclaimer. 953018216SPaolo Bonzini * * Redistributions in binary form must reproduce the above copyright 1053018216SPaolo Bonzini * notice, this list of conditions and the following disclaimer in the 1153018216SPaolo Bonzini * documentation and/or other materials provided with the distribution. 1253018216SPaolo Bonzini * * Neither the name of the Open Source and Linux Lab nor the 1353018216SPaolo Bonzini * names of its contributors may be used to endorse or promote products 1453018216SPaolo Bonzini * derived from this software without specific prior written permission. 1553018216SPaolo Bonzini * 1653018216SPaolo Bonzini * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 1753018216SPaolo Bonzini * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1853018216SPaolo Bonzini * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1953018216SPaolo Bonzini * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 2053018216SPaolo Bonzini * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 2153018216SPaolo Bonzini * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 2253018216SPaolo Bonzini * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 2353018216SPaolo Bonzini * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2453018216SPaolo Bonzini * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 2553018216SPaolo Bonzini * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2653018216SPaolo Bonzini */ 2753018216SPaolo Bonzini 2809aae23dSPeter Maydell #include "qemu/osdep.h" 2933c11879SPaolo Bonzini #include "cpu.h" 3053018216SPaolo Bonzini #include "hw/hw.h" 3153018216SPaolo Bonzini #include "qemu/log.h" 3253018216SPaolo Bonzini #include "qemu/timer.h" 3353018216SPaolo Bonzini 3453018216SPaolo Bonzini void check_interrupts(CPUXtensaState *env) 3553018216SPaolo Bonzini { 36*92fddfbdSRichard Henderson CPUState *cs = env_cpu(env); 3753018216SPaolo Bonzini int minlevel = xtensa_get_cintlevel(env); 3853018216SPaolo Bonzini uint32_t int_set_enabled = env->sregs[INTSET] & env->sregs[INTENABLE]; 3953018216SPaolo Bonzini int level; 4053018216SPaolo Bonzini 4153018216SPaolo Bonzini for (level = env->config->nlevel; level > minlevel; --level) { 4253018216SPaolo Bonzini if (env->config->level_mask[level] & int_set_enabled) { 4353018216SPaolo Bonzini env->pending_irq_level = level; 44c3affe56SAndreas Färber cpu_interrupt(cs, CPU_INTERRUPT_HARD); 4553018216SPaolo Bonzini qemu_log_mask(CPU_LOG_INT, 4653018216SPaolo Bonzini "%s level = %d, cintlevel = %d, " 4753018216SPaolo Bonzini "pc = %08x, a0 = %08x, ps = %08x, " 4853018216SPaolo Bonzini "intset = %08x, intenable = %08x, " 4953018216SPaolo Bonzini "ccount = %08x\n", 5053018216SPaolo Bonzini __func__, level, xtensa_get_cintlevel(env), 5153018216SPaolo Bonzini env->pc, env->regs[0], env->sregs[PS], 5253018216SPaolo Bonzini env->sregs[INTSET], env->sregs[INTENABLE], 5353018216SPaolo Bonzini env->sregs[CCOUNT]); 5453018216SPaolo Bonzini return; 5553018216SPaolo Bonzini } 5653018216SPaolo Bonzini } 5753018216SPaolo Bonzini env->pending_irq_level = 0; 58d8ed887bSAndreas Färber cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); 5953018216SPaolo Bonzini } 6053018216SPaolo Bonzini 6153018216SPaolo Bonzini static void xtensa_set_irq(void *opaque, int irq, int active) 6253018216SPaolo Bonzini { 6353018216SPaolo Bonzini CPUXtensaState *env = opaque; 6453018216SPaolo Bonzini 6553018216SPaolo Bonzini if (irq >= env->config->ninterrupt) { 6653018216SPaolo Bonzini qemu_log("%s: bad IRQ %d\n", __func__, irq); 6753018216SPaolo Bonzini } else { 6853018216SPaolo Bonzini uint32_t irq_bit = 1 << irq; 6953018216SPaolo Bonzini 7053018216SPaolo Bonzini if (active) { 71fa92bd4aSMax Filippov atomic_or(&env->sregs[INTSET], irq_bit); 7253018216SPaolo Bonzini } else if (env->config->interrupt[irq].inttype == INTTYPE_LEVEL) { 73fa92bd4aSMax Filippov atomic_and(&env->sregs[INTSET], ~irq_bit); 7453018216SPaolo Bonzini } 7553018216SPaolo Bonzini 7653018216SPaolo Bonzini check_interrupts(env); 7753018216SPaolo Bonzini } 7853018216SPaolo Bonzini } 7953018216SPaolo Bonzini 8053018216SPaolo Bonzini static void xtensa_ccompare_cb(void *opaque) 8153018216SPaolo Bonzini { 8259a71f75SMax Filippov XtensaCcompareTimer *ccompare = opaque; 8359a71f75SMax Filippov CPUXtensaState *env = ccompare->env; 8459a71f75SMax Filippov unsigned i = ccompare - env->ccompare; 8553018216SPaolo Bonzini 863f75038aSMax Filippov qemu_set_irq(env->irq_inputs[env->config->timerint[i]], 1); 8753018216SPaolo Bonzini } 8853018216SPaolo Bonzini 8917a86b0eSMax Filippov static void xtensa_set_runstall(void *opaque, int irq, int active) 9017a86b0eSMax Filippov { 9117a86b0eSMax Filippov CPUXtensaState *env = opaque; 9217a86b0eSMax Filippov xtensa_runstall(env, active); 9317a86b0eSMax Filippov } 9417a86b0eSMax Filippov 9553018216SPaolo Bonzini void xtensa_irq_init(CPUXtensaState *env) 9653018216SPaolo Bonzini { 9759a71f75SMax Filippov unsigned i; 9859a71f75SMax Filippov 9966f03d7eSMax Filippov env->irq_inputs = qemu_allocate_irqs(xtensa_set_irq, env, 10066f03d7eSMax Filippov env->config->ninterrupt); 10166f03d7eSMax Filippov if (xtensa_option_enabled(env->config, XTENSA_OPTION_TIMER_INTERRUPT)) { 10259a71f75SMax Filippov env->time_base = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 10359a71f75SMax Filippov env->ccount_base = env->sregs[CCOUNT]; 10459a71f75SMax Filippov for (i = 0; i < env->config->nccompare; ++i) { 10559a71f75SMax Filippov env->ccompare[i].env = env; 10659a71f75SMax Filippov env->ccompare[i].timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, 10759a71f75SMax Filippov xtensa_ccompare_cb, env->ccompare + i); 10859a71f75SMax Filippov } 10953018216SPaolo Bonzini } 11066f03d7eSMax Filippov for (i = 0; i < env->config->nextint; ++i) { 11166f03d7eSMax Filippov unsigned irq = env->config->extint[i]; 11266f03d7eSMax Filippov 11366f03d7eSMax Filippov env->ext_irq_inputs[i] = env->irq_inputs[irq]; 11466f03d7eSMax Filippov } 11517a86b0eSMax Filippov env->runstall_irq = qemu_allocate_irq(xtensa_set_runstall, env, 0); 11653018216SPaolo Bonzini } 11753018216SPaolo Bonzini 11866f03d7eSMax Filippov qemu_irq *xtensa_get_extints(CPUXtensaState *env) 11953018216SPaolo Bonzini { 12066f03d7eSMax Filippov return env->ext_irq_inputs; 12153018216SPaolo Bonzini } 12217a86b0eSMax Filippov 12317a86b0eSMax Filippov qemu_irq xtensa_get_runstall(CPUXtensaState *env) 12417a86b0eSMax Filippov { 12517a86b0eSMax Filippov return env->runstall_irq; 12617a86b0eSMax Filippov } 127