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