qemu/target/cris/helper.c
<<
>>
Prefs
   1/*
   2 *  CRIS helper routines.
   3 *
   4 *  Copyright (c) 2007 AXIS Communications AB
   5 *  Written by Edgar E. Iglesias.
   6 *
   7 * This library is free software; you can redistribute it and/or
   8 * modify it under the terms of the GNU Lesser General Public
   9 * License as published by the Free Software Foundation; either
  10 * version 2.1 of the License, or (at your option) any later version.
  11 *
  12 * This library is distributed in the hope that it will be useful,
  13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15 * Lesser General Public License for more details.
  16 *
  17 * You should have received a copy of the GNU Lesser General Public
  18 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  19 */
  20
  21#include "qemu/osdep.h"
  22#include "qemu/log.h"
  23#include "cpu.h"
  24#include "hw/core/tcg-cpu-ops.h"
  25#include "mmu.h"
  26#include "qemu/host-utils.h"
  27#include "exec/exec-all.h"
  28#include "exec/cpu_ldst.h"
  29#include "exec/helper-proto.h"
  30
  31
  32//#define CRIS_HELPER_DEBUG
  33
  34
  35#ifdef CRIS_HELPER_DEBUG
  36#define D(x) x
  37#define D_LOG(...) qemu_log(__VA_ARGS__)
  38#else
  39#define D(x)
  40#define D_LOG(...) do { } while (0)
  41#endif
  42
  43static void cris_shift_ccs(CPUCRISState *env)
  44{
  45    uint32_t ccs;
  46    /* Apply the ccs shift.  */
  47    ccs = env->pregs[PR_CCS];
  48    ccs = ((ccs & 0xc0000000) | ((ccs << 12) >> 2)) & ~0x3ff;
  49    env->pregs[PR_CCS] = ccs;
  50}
  51
  52bool cris_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
  53                       MMUAccessType access_type, int mmu_idx,
  54                       bool probe, uintptr_t retaddr)
  55{
  56    CRISCPU *cpu = CRIS_CPU(cs);
  57    CPUCRISState *env = &cpu->env;
  58    struct cris_mmu_result res;
  59    int prot, miss;
  60    target_ulong phy;
  61
  62    miss = cris_mmu_translate(&res, env, address & TARGET_PAGE_MASK,
  63                              access_type, mmu_idx, 0);
  64    if (likely(!miss)) {
  65        /*
  66         * Mask off the cache selection bit. The ETRAX busses do not
  67         * see the top bit.
  68         */
  69        phy = res.phy & ~0x80000000;
  70        prot = res.prot;
  71        tlb_set_page(cs, address & TARGET_PAGE_MASK, phy,
  72                     prot, mmu_idx, TARGET_PAGE_SIZE);
  73        return true;
  74    }
  75
  76    if (probe) {
  77        return false;
  78    }
  79
  80    if (cs->exception_index == EXCP_BUSFAULT) {
  81        cpu_abort(cs, "CRIS: Illegal recursive bus fault."
  82                      "addr=%" VADDR_PRIx " access_type=%d\n",
  83                      address, access_type);
  84    }
  85
  86    env->pregs[PR_EDA] = address;
  87    cs->exception_index = EXCP_BUSFAULT;
  88    env->fault_vector = res.bf_vec;
  89    if (retaddr) {
  90        if (cpu_restore_state(cs, retaddr, true)) {
  91            /* Evaluate flags after retranslation. */
  92            helper_top_evaluate_flags(env);
  93        }
  94    }
  95    cpu_loop_exit(cs);
  96}
  97
  98void crisv10_cpu_do_interrupt(CPUState *cs)
  99{
 100    CRISCPU *cpu = CRIS_CPU(cs);
 101    CPUCRISState *env = &cpu->env;
 102    int ex_vec = -1;
 103
 104    D_LOG("exception index=%d interrupt_req=%d\n",
 105          cs->exception_index,
 106          cs->interrupt_request);
 107
 108    if (env->dslot) {
 109        /* CRISv10 never takes interrupts while in a delay-slot.  */
 110        cpu_abort(cs, "CRIS: Interrupt on delay-slot\n");
 111    }
 112
 113    assert(!(env->pregs[PR_CCS] & PFIX_FLAG));
 114    switch (cs->exception_index) {
 115    case EXCP_BREAK:
 116        /* These exceptions are genereated by the core itself.
 117           ERP should point to the insn following the brk.  */
 118        ex_vec = env->trap_vector;
 119        env->pregs[PRV10_BRP] = env->pc;
 120        break;
 121
 122    case EXCP_NMI:
 123        /* NMI is hardwired to vector zero.  */
 124        ex_vec = 0;
 125        env->pregs[PR_CCS] &= ~M_FLAG_V10;
 126        env->pregs[PRV10_BRP] = env->pc;
 127        break;
 128
 129    case EXCP_BUSFAULT:
 130        cpu_abort(cs, "Unhandled busfault");
 131        break;
 132
 133    default:
 134        /* The interrupt controller gives us the vector.  */
 135        ex_vec = env->interrupt_vector;
 136        /* Normal interrupts are taken between
 137           TB's.  env->pc is valid here.  */
 138        env->pregs[PR_ERP] = env->pc;
 139        break;
 140    }
 141
 142    if (env->pregs[PR_CCS] & U_FLAG) {
 143        /* Swap stack pointers.  */
 144        env->pregs[PR_USP] = env->regs[R_SP];
 145        env->regs[R_SP] = env->ksp;
 146    }
 147
 148    /* Now that we are in kernel mode, load the handlers address.  */
 149    env->pc = cpu_ldl_code(env, env->pregs[PR_EBP] + ex_vec * 4);
 150    env->locked_irq = 1;
 151    env->pregs[PR_CCS] |= F_FLAG_V10; /* set F.  */
 152
 153    qemu_log_mask(CPU_LOG_INT, "%s isr=%x vec=%x ccs=%x pid=%d erp=%x\n",
 154                  __func__, env->pc, ex_vec,
 155                  env->pregs[PR_CCS],
 156                  env->pregs[PR_PID],
 157                  env->pregs[PR_ERP]);
 158}
 159
 160void cris_cpu_do_interrupt(CPUState *cs)
 161{
 162    CRISCPU *cpu = CRIS_CPU(cs);
 163    CPUCRISState *env = &cpu->env;
 164    int ex_vec = -1;
 165
 166    D_LOG("exception index=%d interrupt_req=%d\n",
 167          cs->exception_index,
 168          cs->interrupt_request);
 169
 170    switch (cs->exception_index) {
 171    case EXCP_BREAK:
 172        /* These exceptions are genereated by the core itself.
 173           ERP should point to the insn following the brk.  */
 174        ex_vec = env->trap_vector;
 175        env->pregs[PR_ERP] = env->pc;
 176        break;
 177
 178    case EXCP_NMI:
 179        /* NMI is hardwired to vector zero.  */
 180        ex_vec = 0;
 181        env->pregs[PR_CCS] &= ~M_FLAG_V32;
 182        env->pregs[PR_NRP] = env->pc;
 183        break;
 184
 185    case EXCP_BUSFAULT:
 186        ex_vec = env->fault_vector;
 187        env->pregs[PR_ERP] = env->pc;
 188        break;
 189
 190    default:
 191        /* The interrupt controller gives us the vector.  */
 192        ex_vec = env->interrupt_vector;
 193        /* Normal interrupts are taken between
 194           TB's.  env->pc is valid here.  */
 195        env->pregs[PR_ERP] = env->pc;
 196        break;
 197    }
 198
 199    /* Fill in the IDX field.  */
 200    env->pregs[PR_EXS] = (ex_vec & 0xff) << 8;
 201
 202    if (env->dslot) {
 203        D_LOG("excp isr=%x PC=%x ds=%d SP=%x"
 204              " ERP=%x pid=%x ccs=%x cc=%d %x\n",
 205              ex_vec, env->pc, env->dslot,
 206              env->regs[R_SP],
 207              env->pregs[PR_ERP], env->pregs[PR_PID],
 208              env->pregs[PR_CCS],
 209              env->cc_op, env->cc_mask);
 210        /* We loose the btarget, btaken state here so rexec the
 211           branch.  */
 212        env->pregs[PR_ERP] -= env->dslot;
 213        /* Exception starts with dslot cleared.  */
 214        env->dslot = 0;
 215    }
 216
 217    if (env->pregs[PR_CCS] & U_FLAG) {
 218        /* Swap stack pointers.  */
 219        env->pregs[PR_USP] = env->regs[R_SP];
 220        env->regs[R_SP] = env->ksp;
 221    }
 222
 223    /* Apply the CRIS CCS shift. Clears U if set.  */
 224    cris_shift_ccs(env);
 225
 226    /* Now that we are in kernel mode, load the handlers address.
 227       This load may not fault, real hw leaves that behaviour as
 228       undefined.  */
 229    env->pc = cpu_ldl_code(env, env->pregs[PR_EBP] + ex_vec * 4);
 230
 231    /* Clear the excption_index to avoid spurios hw_aborts for recursive
 232       bus faults.  */
 233    cs->exception_index = -1;
 234
 235    D_LOG("%s isr=%x vec=%x ccs=%x pid=%d erp=%x\n",
 236          __func__, env->pc, ex_vec,
 237          env->pregs[PR_CCS],
 238          env->pregs[PR_PID],
 239          env->pregs[PR_ERP]);
 240}
 241
 242hwaddr cris_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
 243{
 244    CRISCPU *cpu = CRIS_CPU(cs);
 245    uint32_t phy = addr;
 246    struct cris_mmu_result res;
 247    int miss;
 248
 249    miss = cris_mmu_translate(&res, &cpu->env, addr, MMU_DATA_LOAD, 0, 1);
 250    /* If D TLB misses, try I TLB.  */
 251    if (miss) {
 252        miss = cris_mmu_translate(&res, &cpu->env, addr, MMU_INST_FETCH, 0, 1);
 253    }
 254
 255    if (!miss) {
 256        phy = res.phy;
 257    }
 258    D(fprintf(stderr, "%s %x -> %x\n", __func__, addr, phy));
 259    return phy;
 260}
 261
 262bool cris_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
 263{
 264    CPUClass *cc = CPU_GET_CLASS(cs);
 265    CRISCPU *cpu = CRIS_CPU(cs);
 266    CPUCRISState *env = &cpu->env;
 267    bool ret = false;
 268
 269    if (interrupt_request & CPU_INTERRUPT_HARD
 270        && (env->pregs[PR_CCS] & I_FLAG)
 271        && !env->locked_irq) {
 272        cs->exception_index = EXCP_IRQ;
 273        cc->tcg_ops->do_interrupt(cs);
 274        ret = true;
 275    }
 276    if (interrupt_request & CPU_INTERRUPT_NMI) {
 277        unsigned int m_flag_archval;
 278        if (env->pregs[PR_VR] < 32) {
 279            m_flag_archval = M_FLAG_V10;
 280        } else {
 281            m_flag_archval = M_FLAG_V32;
 282        }
 283        if ((env->pregs[PR_CCS] & m_flag_archval)) {
 284            cs->exception_index = EXCP_NMI;
 285            cc->tcg_ops->do_interrupt(cs);
 286            ret = true;
 287        }
 288    }
 289
 290    return ret;
 291}
 292