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