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