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 43 static 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 52 bool 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 CPUCRISState *env = cpu_env(cs); 57 struct cris_mmu_result res; 58 int prot, miss; 59 target_ulong phy; 60 61 miss = cris_mmu_translate(&res, env, address & TARGET_PAGE_MASK, 62 access_type, mmu_idx, 0); 63 if (likely(!miss)) { 64 /* 65 * Mask off the cache selection bit. The ETRAX busses do not 66 * see the top bit. 67 */ 68 phy = res.phy & ~0x80000000; 69 prot = res.prot; 70 tlb_set_page(cs, address & TARGET_PAGE_MASK, phy, 71 prot, mmu_idx, TARGET_PAGE_SIZE); 72 return true; 73 } 74 75 if (probe) { 76 return false; 77 } 78 79 if (cs->exception_index == EXCP_BUSFAULT) { 80 cpu_abort(cs, "CRIS: Illegal recursive bus fault." 81 "addr=%" VADDR_PRIx " access_type=%d\n", 82 address, access_type); 83 } 84 85 env->pregs[PR_EDA] = address; 86 cs->exception_index = EXCP_BUSFAULT; 87 env->fault_vector = res.bf_vec; 88 if (retaddr) { 89 if (cpu_restore_state(cs, retaddr)) { 90 /* Evaluate flags after retranslation. */ 91 helper_top_evaluate_flags(env); 92 } 93 } 94 cpu_loop_exit(cs); 95 } 96 97 void crisv10_cpu_do_interrupt(CPUState *cs) 98 { 99 CPUCRISState *env = cpu_env(cs); 100 int ex_vec = -1; 101 102 D_LOG("exception index=%d interrupt_req=%d\n", 103 cs->exception_index, 104 cs->interrupt_request); 105 106 if (env->dslot) { 107 /* CRISv10 never takes interrupts while in a delay-slot. */ 108 cpu_abort(cs, "CRIS: Interrupt on delay-slot\n"); 109 } 110 111 assert(!(env->pregs[PR_CCS] & PFIX_FLAG)); 112 switch (cs->exception_index) { 113 case EXCP_BREAK: 114 /* These exceptions are generated by the core itself. 115 ERP should point to the insn following the brk. */ 116 ex_vec = env->trap_vector; 117 env->pregs[PRV10_BRP] = env->pc; 118 break; 119 120 case EXCP_NMI: 121 /* NMI is hardwired to vector zero. */ 122 ex_vec = 0; 123 env->pregs[PR_CCS] &= ~M_FLAG_V10; 124 env->pregs[PRV10_BRP] = env->pc; 125 break; 126 127 case EXCP_BUSFAULT: 128 cpu_abort(cs, "Unhandled busfault"); 129 break; 130 131 default: 132 /* The interrupt controller gives us the vector. */ 133 ex_vec = env->interrupt_vector; 134 /* Normal interrupts are taken between 135 TB's. env->pc is valid here. */ 136 env->pregs[PR_ERP] = env->pc; 137 break; 138 } 139 140 if (env->pregs[PR_CCS] & U_FLAG) { 141 /* Swap stack pointers. */ 142 env->pregs[PR_USP] = env->regs[R_SP]; 143 env->regs[R_SP] = env->ksp; 144 } 145 146 /* Now that we are in kernel mode, load the handlers address. */ 147 env->pc = cpu_ldl_code(env, env->pregs[PR_EBP] + ex_vec * 4); 148 env->locked_irq = 1; 149 env->pregs[PR_CCS] |= F_FLAG_V10; /* set F. */ 150 151 qemu_log_mask(CPU_LOG_INT, "%s isr=%x vec=%x ccs=%x pid=%d erp=%x\n", 152 __func__, env->pc, ex_vec, 153 env->pregs[PR_CCS], 154 env->pregs[PR_PID], 155 env->pregs[PR_ERP]); 156 } 157 158 void cris_cpu_do_interrupt(CPUState *cs) 159 { 160 CPUCRISState *env = cpu_env(cs); 161 int ex_vec = -1; 162 163 D_LOG("exception index=%d interrupt_req=%d\n", 164 cs->exception_index, 165 cs->interrupt_request); 166 167 switch (cs->exception_index) { 168 case EXCP_BREAK: 169 /* These exceptions are generated by the core itself. 170 ERP should point to the insn following the brk. */ 171 ex_vec = env->trap_vector; 172 env->pregs[PR_ERP] = env->pc; 173 break; 174 175 case EXCP_NMI: 176 /* NMI is hardwired to vector zero. */ 177 ex_vec = 0; 178 env->pregs[PR_CCS] &= ~M_FLAG_V32; 179 env->pregs[PR_NRP] = env->pc; 180 break; 181 182 case EXCP_BUSFAULT: 183 ex_vec = env->fault_vector; 184 env->pregs[PR_ERP] = env->pc; 185 break; 186 187 default: 188 /* The interrupt controller gives us the vector. */ 189 ex_vec = env->interrupt_vector; 190 /* Normal interrupts are taken between 191 TB's. env->pc is valid here. */ 192 env->pregs[PR_ERP] = env->pc; 193 break; 194 } 195 196 /* Fill in the IDX field. */ 197 env->pregs[PR_EXS] = (ex_vec & 0xff) << 8; 198 199 if (env->dslot) { 200 D_LOG("excp isr=%x PC=%x ds=%d SP=%x" 201 " ERP=%x pid=%x ccs=%x cc=%d %x\n", 202 ex_vec, env->pc, env->dslot, 203 env->regs[R_SP], 204 env->pregs[PR_ERP], env->pregs[PR_PID], 205 env->pregs[PR_CCS], 206 env->cc_op, env->cc_mask); 207 /* We loose the btarget, btaken state here so rexec the 208 branch. */ 209 env->pregs[PR_ERP] -= env->dslot; 210 /* Exception starts with dslot cleared. */ 211 env->dslot = 0; 212 } 213 214 if (env->pregs[PR_CCS] & U_FLAG) { 215 /* Swap stack pointers. */ 216 env->pregs[PR_USP] = env->regs[R_SP]; 217 env->regs[R_SP] = env->ksp; 218 } 219 220 /* Apply the CRIS CCS shift. Clears U if set. */ 221 cris_shift_ccs(env); 222 223 /* Now that we are in kernel mode, load the handlers address. 224 This load may not fault, real hw leaves that behaviour as 225 undefined. */ 226 env->pc = cpu_ldl_code(env, env->pregs[PR_EBP] + ex_vec * 4); 227 228 /* Clear the excption_index to avoid spurious hw_aborts for recursive 229 bus faults. */ 230 cs->exception_index = -1; 231 232 D_LOG("%s isr=%x vec=%x ccs=%x pid=%d erp=%x\n", 233 __func__, env->pc, ex_vec, 234 env->pregs[PR_CCS], 235 env->pregs[PR_PID], 236 env->pregs[PR_ERP]); 237 } 238 239 hwaddr cris_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) 240 { 241 CRISCPU *cpu = CRIS_CPU(cs); 242 uint32_t phy = addr; 243 struct cris_mmu_result res; 244 int miss; 245 246 miss = cris_mmu_translate(&res, &cpu->env, addr, MMU_DATA_LOAD, 0, 1); 247 /* If D TLB misses, try I TLB. */ 248 if (miss) { 249 miss = cris_mmu_translate(&res, &cpu->env, addr, MMU_INST_FETCH, 0, 1); 250 } 251 252 if (!miss) { 253 phy = res.phy; 254 } 255 D(fprintf(stderr, "%s %x -> %x\n", __func__, addr, phy)); 256 return phy; 257 } 258 259 bool cris_cpu_exec_interrupt(CPUState *cs, int interrupt_request) 260 { 261 CPUClass *cc = CPU_GET_CLASS(cs); 262 CPUCRISState *env = cpu_env(cs); 263 bool ret = false; 264 265 if (interrupt_request & CPU_INTERRUPT_HARD 266 && (env->pregs[PR_CCS] & I_FLAG) 267 && !env->locked_irq) { 268 cs->exception_index = EXCP_IRQ; 269 cc->tcg_ops->do_interrupt(cs); 270 ret = true; 271 } 272 if (interrupt_request & CPU_INTERRUPT_NMI) { 273 unsigned int m_flag_archval; 274 if (env->pregs[PR_VR] < 32) { 275 m_flag_archval = M_FLAG_V10; 276 } else { 277 m_flag_archval = M_FLAG_V32; 278 } 279 if ((env->pregs[PR_CCS] & m_flag_archval)) { 280 cs->exception_index = EXCP_NMI; 281 cc->tcg_ops->do_interrupt(cs); 282 ret = true; 283 } 284 } 285 286 return ret; 287 } 288