qemu/target/sparc/int32_helper.c
<<
>>
Prefs
   1/*
   2 * Sparc32 interrupt helpers
   3 *
   4 *  Copyright (c) 2003-2005 Fabrice Bellard
   5 *
   6 * This library is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU Lesser General Public
   8 * License as published by the Free Software Foundation; either
   9 * version 2.1 of the License, or (at your option) any later version.
  10 *
  11 * This library is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14 * Lesser General Public License for more details.
  15 *
  16 * You should have received a copy of the GNU Lesser General Public
  17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  18 */
  19
  20#include "qemu/osdep.h"
  21#include "qemu/main-loop.h"
  22#include "cpu.h"
  23#include "trace.h"
  24#include "exec/log.h"
  25#include "sysemu/runstate.h"
  26
  27
  28static const char * const excp_names[0x80] = {
  29    [TT_TFAULT] = "Instruction Access Fault",
  30    [TT_ILL_INSN] = "Illegal Instruction",
  31    [TT_PRIV_INSN] = "Privileged Instruction",
  32    [TT_NFPU_INSN] = "FPU Disabled",
  33    [TT_WIN_OVF] = "Window Overflow",
  34    [TT_WIN_UNF] = "Window Underflow",
  35    [TT_UNALIGNED] = "Unaligned Memory Access",
  36    [TT_FP_EXCP] = "FPU Exception",
  37    [TT_DFAULT] = "Data Access Fault",
  38    [TT_TOVF] = "Tag Overflow",
  39    [TT_EXTINT | 0x1] = "External Interrupt 1",
  40    [TT_EXTINT | 0x2] = "External Interrupt 2",
  41    [TT_EXTINT | 0x3] = "External Interrupt 3",
  42    [TT_EXTINT | 0x4] = "External Interrupt 4",
  43    [TT_EXTINT | 0x5] = "External Interrupt 5",
  44    [TT_EXTINT | 0x6] = "External Interrupt 6",
  45    [TT_EXTINT | 0x7] = "External Interrupt 7",
  46    [TT_EXTINT | 0x8] = "External Interrupt 8",
  47    [TT_EXTINT | 0x9] = "External Interrupt 9",
  48    [TT_EXTINT | 0xa] = "External Interrupt 10",
  49    [TT_EXTINT | 0xb] = "External Interrupt 11",
  50    [TT_EXTINT | 0xc] = "External Interrupt 12",
  51    [TT_EXTINT | 0xd] = "External Interrupt 13",
  52    [TT_EXTINT | 0xe] = "External Interrupt 14",
  53    [TT_EXTINT | 0xf] = "External Interrupt 15",
  54    [TT_CODE_ACCESS] = "Instruction Access Error",
  55    [TT_DATA_ACCESS] = "Data Access Error",
  56    [TT_DIV_ZERO] = "Division By Zero",
  57    [TT_NCP_INSN] = "Coprocessor Disabled",
  58};
  59
  60static const char *excp_name_str(int32_t exception_index)
  61{
  62    if (exception_index < 0 || exception_index >= ARRAY_SIZE(excp_names)) {
  63        return "Unknown";
  64    }
  65    return excp_names[exception_index];
  66}
  67
  68void cpu_check_irqs(CPUSPARCState *env)
  69{
  70    CPUState *cs;
  71
  72    /* We should be holding the BQL before we mess with IRQs */
  73    g_assert(qemu_mutex_iothread_locked());
  74
  75    if (env->pil_in && (env->interrupt_index == 0 ||
  76                        (env->interrupt_index & ~15) == TT_EXTINT)) {
  77        unsigned int i;
  78
  79        for (i = 15; i > 0; i--) {
  80            if (env->pil_in & (1 << i)) {
  81                int old_interrupt = env->interrupt_index;
  82
  83                env->interrupt_index = TT_EXTINT | i;
  84                if (old_interrupt != env->interrupt_index) {
  85                    cs = env_cpu(env);
  86                    trace_sun4m_cpu_interrupt(i);
  87                    cpu_interrupt(cs, CPU_INTERRUPT_HARD);
  88                }
  89                break;
  90            }
  91        }
  92    } else if (!env->pil_in && (env->interrupt_index & ~15) == TT_EXTINT) {
  93        cs = env_cpu(env);
  94        trace_sun4m_cpu_reset_interrupt(env->interrupt_index & 15);
  95        env->interrupt_index = 0;
  96        cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
  97    }
  98}
  99
 100void sparc_cpu_do_interrupt(CPUState *cs)
 101{
 102    SPARCCPU *cpu = SPARC_CPU(cs);
 103    CPUSPARCState *env = &cpu->env;
 104    int cwp, intno = cs->exception_index;
 105
 106    /* Compute PSR before exposing state.  */
 107    if (env->cc_op != CC_OP_FLAGS) {
 108        cpu_get_psr(env);
 109    }
 110
 111    if (qemu_loglevel_mask(CPU_LOG_INT)) {
 112        static int count;
 113        const char *name;
 114
 115        if (intno < 0 || intno >= 0x100) {
 116            name = "Unknown";
 117        } else if (intno >= 0x80) {
 118            name = "Trap Instruction";
 119        } else {
 120            name = excp_name_str(intno);
 121        }
 122
 123        qemu_log("%6d: %s (v=%02x)\n", count, name, intno);
 124        log_cpu_state(cs, 0);
 125#if 0
 126        {
 127            int i;
 128            uint8_t *ptr;
 129
 130            qemu_log("       code=");
 131            ptr = (uint8_t *)env->pc;
 132            for (i = 0; i < 16; i++) {
 133                qemu_log(" %02x", ldub(ptr + i));
 134            }
 135            qemu_log("\n");
 136        }
 137#endif
 138        count++;
 139    }
 140#if !defined(CONFIG_USER_ONLY)
 141    if (env->psret == 0) {
 142        if (cs->exception_index == 0x80 &&
 143            env->def.features & CPU_FEATURE_TA0_SHUTDOWN) {
 144            qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
 145        } else {
 146            cpu_abort(cs, "Trap 0x%02x (%s) while interrupts disabled, "
 147                          "Error state",
 148                      cs->exception_index, excp_name_str(cs->exception_index));
 149        }
 150        return;
 151    }
 152#endif
 153    env->psret = 0;
 154    cwp = cpu_cwp_dec(env, env->cwp - 1);
 155    cpu_set_cwp(env, cwp);
 156    env->regwptr[9] = env->pc;
 157    env->regwptr[10] = env->npc;
 158    env->psrps = env->psrs;
 159    env->psrs = 1;
 160    env->tbr = (env->tbr & TBR_BASE_MASK) | (intno << 4);
 161    env->pc = env->tbr;
 162    env->npc = env->pc + 4;
 163    cs->exception_index = -1;
 164
 165#if !defined(CONFIG_USER_ONLY)
 166    /* IRQ acknowledgment */
 167    if ((intno & ~15) == TT_EXTINT && env->qemu_irq_ack != NULL) {
 168        env->qemu_irq_ack(env, env->irq_manager, intno);
 169    }
 170#endif
 171}
 172