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