| /* |
| * 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, write to the Free Software |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| */ |
| |
| #include <stdio.h> |
| #include <string.h> |
| |
| #include "config.h" |
| #include "cpu.h" |
| #include "mmu.h" |
| #include "exec-all.h" |
| #include "host-utils.h" |
| |
| #define D(x) |
| |
| #if defined(CONFIG_USER_ONLY) |
| |
| void do_interrupt (CPUState *env) |
| { |
| env->exception_index = -1; |
| env->pregs[PR_ERP] = env->pc; |
| } |
| |
| int cpu_cris_handle_mmu_fault(CPUState * env, target_ulong address, int rw, |
| int mmu_idx, int is_softmmu) |
| { |
| env->exception_index = 0xaa; |
| env->debug1 = address; |
| cpu_dump_state(env, stderr, fprintf, 0); |
| env->pregs[PR_ERP] = env->pc; |
| return 1; |
| } |
| |
| target_phys_addr_t cpu_get_phys_page_debug(CPUState * env, target_ulong addr) |
| { |
| return addr; |
| } |
| |
| #else /* !CONFIG_USER_ONLY */ |
| |
| |
| static void cris_shift_ccs(CPUState *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 (CPUState *env, target_ulong address, int rw, |
| int mmu_idx, int is_softmmu) |
| { |
| struct cris_mmu_result_t 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)); |
| address &= TARGET_PAGE_MASK; |
| prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; |
| miss = cris_mmu_translate(&res, env, address, rw, mmu_idx); |
| if (miss) |
| { |
| if (env->exception_index == EXCP_MMU_FAULT) |
| cpu_abort(env, |
| "CRIS: Illegal recursive bus fault." |
| "addr=%x rw=%d\n", |
| address, rw); |
| |
| env->exception_index = EXCP_MMU_FAULT; |
| env->fault_vector = res.bf_vec; |
| r = 1; |
| } |
| else |
| { |
| phy = res.phy; |
| prot = res.prot; |
| address &= TARGET_PAGE_MASK; |
| r = tlb_set_page(env, address, phy, prot, mmu_idx, is_softmmu); |
| } |
| if (r > 0) |
| D(fprintf(logfile, "%s returns %d irqreq=%x addr=%x ismmu=%d vec=%x\n", |
| __func__, r, env->interrupt_request, |
| address, is_softmmu, res.bf_vec)); |
| return r; |
| } |
| |
| void do_interrupt(CPUState *env) |
| { |
| int ex_vec = -1; |
| |
| D(fprintf (logfile, "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 + 2; |
| break; |
| |
| case EXCP_MMU_FAULT: |
| ex_vec = env->fault_vector; |
| env->pregs[PR_ERP] = env->pc; |
| break; |
| |
| default: |
| /* Is the core accepting interrupts? */ |
| if (!(env->pregs[PR_CCS] & I_FLAG)) |
| return; |
| /* 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)) { |
| D(fprintf(logfile, "excp isr=%x PC=%x SP=%x ERP=%x pid=%x ccs=%x cc=%d %x\n", |
| ex_vec, env->pc, |
| env->regs[R_SP], |
| env->pregs[PR_ERP], env->pregs[PR_PID], |
| env->pregs[PR_CCS], |
| env->cc_op, env->cc_mask)); |
| } |
| |
| env->pc = ldl_code(env->pregs[PR_EBP] + ex_vec * 4); |
| |
| 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); |
| D(fprintf (logfile, "%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])); |
| } |
| |
| target_phys_addr_t cpu_get_phys_page_debug(CPUState * env, target_ulong addr) |
| { |
| uint32_t phy = addr; |
| struct cris_mmu_result_t res; |
| int miss; |
| miss = cris_mmu_translate(&res, env, addr, 0, 0); |
| if (!miss) |
| phy = res.phy; |
| D(fprintf(stderr, "%s %x -> %x\n", __func__, addr, phy)); |
| return phy; |
| } |
| #endif |