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