/* * CRIS helper routines. * * Copyright (c) 2007 AXIS Communications AB * Written by Edgar E. Iglesias. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see . */ #include "cpu.h" #include "mmu.h" #include "qemu/host-utils.h" //#define CRIS_HELPER_DEBUG #ifdef CRIS_HELPER_DEBUG #define D(x) x #define D_LOG(...) qemu_log(__VA_ARGS__) #else #define D(x) #define D_LOG(...) do { } while (0) #endif #if defined(CONFIG_USER_ONLY) void do_interrupt (CPUCRISState *env) { env->exception_index = -1; env->pregs[PR_ERP] = env->pc; } int cpu_cris_handle_mmu_fault(CPUCRISState * env, target_ulong address, int rw, int mmu_idx) { env->exception_index = 0xaa; env->pregs[PR_EDA] = address; cpu_dump_state(env, stderr, fprintf, 0); return 1; } #else /* !CONFIG_USER_ONLY */ static void cris_shift_ccs(CPUCRISState *env) { uint32_t ccs; /* Apply the ccs shift. */ ccs = env->pregs[PR_CCS]; ccs = ((ccs & 0xc0000000) | ((ccs << 12) >> 2)) & ~0x3ff; env->pregs[PR_CCS] = ccs; } int cpu_cris_handle_mmu_fault (CPUCRISState *env, target_ulong address, int rw, int mmu_idx) { struct cris_mmu_result res; int prot, miss; int r = -1; target_ulong phy; D(printf ("%s addr=%x pc=%x rw=%x\n", __func__, address, env->pc, rw)); miss = cris_mmu_translate(&res, env, address & TARGET_PAGE_MASK, rw, mmu_idx, 0); if (miss) { if (env->exception_index == EXCP_BUSFAULT) cpu_abort(env, "CRIS: Illegal recursive bus fault." "addr=%x rw=%d\n", address, rw); env->pregs[PR_EDA] = address; env->exception_index = EXCP_BUSFAULT; env->fault_vector = res.bf_vec; r = 1; } else { /* * Mask off the cache selection bit. The ETRAX busses do not * see the top bit. */ phy = res.phy & ~0x80000000; prot = res.prot; tlb_set_page(env, address & TARGET_PAGE_MASK, phy, prot, mmu_idx, TARGET_PAGE_SIZE); r = 0; } if (r > 0) D_LOG("%s returns %d irqreq=%x addr=%x phy=%x vec=%x pc=%x\n", __func__, r, env->interrupt_request, address, res.phy, res.bf_vec, env->pc); return r; } static void do_interruptv10(CPUCRISState *env) { int ex_vec = -1; D_LOG( "exception index=%d interrupt_req=%d\n", env->exception_index, env->interrupt_request); assert(!(env->pregs[PR_CCS] & PFIX_FLAG)); switch (env->exception_index) { case EXCP_BREAK: /* These exceptions are genereated by the core itself. ERP should point to the insn following the brk. */ ex_vec = env->trap_vector; env->pregs[PRV10_BRP] = env->pc; break; case EXCP_NMI: /* NMI is hardwired to vector zero. */ ex_vec = 0; env->pregs[PR_CCS] &= ~M_FLAG_V10; env->pregs[PRV10_BRP] = env->pc; break; case EXCP_BUSFAULT: cpu_abort(env, "Unhandled busfault"); break; default: /* The interrupt controller gives us the vector. */ ex_vec = env->interrupt_vector; /* Normal interrupts are taken between TB's. env->pc is valid here. */ env->pregs[PR_ERP] = env->pc; break; } if (env->pregs[PR_CCS] & U_FLAG) { /* Swap stack pointers. */ env->pregs[PR_USP] = env->regs[R_SP]; env->regs[R_SP] = env->ksp; } /* Now that we are in kernel mode, load the handlers address. */ env->pc = cpu_ldl_code(env, env->pregs[PR_EBP] + ex_vec * 4); env->locked_irq = 1; env->pregs[PR_CCS] |= F_FLAG_V10; /* set F. */ qemu_log_mask(CPU_LOG_INT, "%s isr=%x vec=%x ccs=%x pid=%d erp=%x\n", __func__, env->pc, ex_vec, env->pregs[PR_CCS], env->pregs[PR_PID], env->pregs[PR_ERP]); } void do_interrupt(CPUCRISState *env) { int ex_vec = -1; if (env->pregs[PR_VR] < 32) return do_interruptv10(env); D_LOG( "exception index=%d interrupt_req=%d\n", env->exception_index, env->interrupt_request); switch (env->exception_index) { case EXCP_BREAK: /* These exceptions are genereated by the core itself. ERP should point to the insn following the brk. */ ex_vec = env->trap_vector; env->pregs[PR_ERP] = env->pc; break; case EXCP_NMI: /* NMI is hardwired to vector zero. */ ex_vec = 0; env->pregs[PR_CCS] &= ~M_FLAG_V32; env->pregs[PR_NRP] = env->pc; break; case EXCP_BUSFAULT: ex_vec = env->fault_vector; env->pregs[PR_ERP] = env->pc; break; default: /* The interrupt controller gives us the vector. */ ex_vec = env->interrupt_vector; /* Normal interrupts are taken between TB's. env->pc is valid here. */ env->pregs[PR_ERP] = env->pc; break; } /* Fill in the IDX field. */ env->pregs[PR_EXS] = (ex_vec & 0xff) << 8; if (env->dslot) { D_LOG("excp isr=%x PC=%x ds=%d SP=%x" " ERP=%x pid=%x ccs=%x cc=%d %x\n", ex_vec, env->pc, env->dslot, env->regs[R_SP], env->pregs[PR_ERP], env->pregs[PR_PID], env->pregs[PR_CCS], env->cc_op, env->cc_mask); /* We loose the btarget, btaken state here so rexec the branch. */ env->pregs[PR_ERP] -= env->dslot; /* Exception starts with dslot cleared. */ env->dslot = 0; } if (env->pregs[PR_CCS] & U_FLAG) { /* Swap stack pointers. */ env->pregs[PR_USP] = env->regs[R_SP]; env->regs[R_SP] = env->ksp; } /* Apply the CRIS CCS shift. Clears U if set. */ cris_shift_ccs(env); /* Now that we are in kernel mode, load the handlers address. This load may not fault, real hw leaves that behaviour as undefined. */ env->pc = cpu_ldl_code(env, env->pregs[PR_EBP] + ex_vec * 4); /* Clear the excption_index to avoid spurios hw_aborts for recursive bus faults. */ env->exception_index = -1; D_LOG("%s isr=%x vec=%x ccs=%x pid=%d erp=%x\n", __func__, env->pc, ex_vec, env->pregs[PR_CCS], env->pregs[PR_PID], env->pregs[PR_ERP]); } hwaddr cpu_get_phys_page_debug(CPUCRISState * env, target_ulong addr) { uint32_t phy = addr; struct cris_mmu_result res; int miss; miss = cris_mmu_translate(&res, env, addr, 0, 0, 1); /* If D TLB misses, try I TLB. */ if (miss) { miss = cris_mmu_translate(&res, env, addr, 2, 0, 1); } if (!miss) phy = res.phy; D(fprintf(stderr, "%s %x -> %x\n", __func__, addr, phy)); return phy; } #endif