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 { 36259186a7SAndreas Färber CPUState *cs = CPU(xtensa_env_get_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) { 7153018216SPaolo Bonzini env->sregs[INTSET] |= irq_bit; 7253018216SPaolo Bonzini } else if (env->config->interrupt[irq].inttype == INTTYPE_LEVEL) { 7353018216SPaolo Bonzini env->sregs[INTSET] &= ~irq_bit; 7453018216SPaolo Bonzini } 7553018216SPaolo Bonzini 7653018216SPaolo Bonzini check_interrupts(env); 7753018216SPaolo Bonzini } 7853018216SPaolo Bonzini } 7953018216SPaolo Bonzini 8053018216SPaolo Bonzini void xtensa_timer_irq(CPUXtensaState *env, uint32_t id, uint32_t active) 8153018216SPaolo Bonzini { 8253018216SPaolo Bonzini qemu_set_irq(env->irq_inputs[env->config->timerint[id]], active); 8353018216SPaolo Bonzini } 8453018216SPaolo Bonzini 8553018216SPaolo Bonzini static void xtensa_ccompare_cb(void *opaque) 8653018216SPaolo Bonzini { 87*59a71f75SMax Filippov XtensaCcompareTimer *ccompare = opaque; 88*59a71f75SMax Filippov CPUXtensaState *env = ccompare->env; 89*59a71f75SMax Filippov unsigned i = ccompare - env->ccompare; 9053018216SPaolo Bonzini 91*59a71f75SMax Filippov xtensa_timer_irq(env, i, 1); 9253018216SPaolo Bonzini } 9353018216SPaolo Bonzini 9453018216SPaolo Bonzini void xtensa_irq_init(CPUXtensaState *env) 9553018216SPaolo Bonzini { 9653018216SPaolo Bonzini env->irq_inputs = (void **)qemu_allocate_irqs( 9753018216SPaolo Bonzini xtensa_set_irq, env, env->config->ninterrupt); 98*59a71f75SMax Filippov if (xtensa_option_enabled(env->config, XTENSA_OPTION_TIMER_INTERRUPT)) { 99*59a71f75SMax Filippov unsigned i; 100*59a71f75SMax Filippov 101*59a71f75SMax Filippov env->time_base = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 102*59a71f75SMax Filippov env->ccount_base = env->sregs[CCOUNT]; 103*59a71f75SMax Filippov for (i = 0; i < env->config->nccompare; ++i) { 104*59a71f75SMax Filippov env->ccompare[i].env = env; 105*59a71f75SMax Filippov env->ccompare[i].timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, 106*59a71f75SMax Filippov xtensa_ccompare_cb, env->ccompare + i); 107*59a71f75SMax Filippov } 10853018216SPaolo Bonzini } 10953018216SPaolo Bonzini } 11053018216SPaolo Bonzini 11153018216SPaolo Bonzini void *xtensa_get_extint(CPUXtensaState *env, unsigned extint) 11253018216SPaolo Bonzini { 11353018216SPaolo Bonzini if (extint < env->config->nextint) { 11453018216SPaolo Bonzini unsigned irq = env->config->extint[extint]; 11553018216SPaolo Bonzini return env->irq_inputs[irq]; 11653018216SPaolo Bonzini } else { 11753018216SPaolo Bonzini qemu_log("%s: trying to acquire invalid external interrupt %d\n", 11853018216SPaolo Bonzini __func__, extint); 11953018216SPaolo Bonzini return NULL; 12053018216SPaolo Bonzini } 12153018216SPaolo Bonzini } 122