1 /* 2 * CRIS helper routines 3 * 4 * Copyright (c) 2007 AXIS Communications 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 "mmu.h" 24 #include "exec/helper-proto.h" 25 #include "qemu/host-utils.h" 26 #include "exec/exec-all.h" 27 28 //#define CRIS_OP_HELPER_DEBUG 29 30 31 #ifdef CRIS_OP_HELPER_DEBUG 32 #define D(x) x 33 #define D_LOG(...) qemu_log(__VA_ARGS__) 34 #else 35 #define D(x) 36 #define D_LOG(...) do { } while (0) 37 #endif 38 39 void helper_raise_exception(CPUCRISState *env, uint32_t index) 40 { 41 CPUState *cs = env_cpu(env); 42 43 cs->exception_index = index; 44 cpu_loop_exit(cs); 45 } 46 47 void helper_tlb_flush_pid(CPUCRISState *env, uint32_t pid) 48 { 49 #if !defined(CONFIG_USER_ONLY) 50 pid &= 0xff; 51 if (pid != (env->pregs[PR_PID] & 0xff)) { 52 cris_mmu_flush_pid(env, env->pregs[PR_PID]); 53 } 54 #endif 55 } 56 57 void helper_spc_write(CPUCRISState *env, uint32_t new_spc) 58 { 59 #if !defined(CONFIG_USER_ONLY) 60 CPUState *cs = env_cpu(env); 61 62 tlb_flush_page(cs, env->pregs[PR_SPC]); 63 tlb_flush_page(cs, new_spc); 64 #endif 65 } 66 67 /* Used by the tlb decoder. */ 68 #define EXTRACT_FIELD(src, start, end) \ 69 (((src) >> start) & ((1 << (end - start + 1)) - 1)) 70 71 void helper_movl_sreg_reg(CPUCRISState *env, uint32_t sreg, uint32_t reg) 72 { 73 uint32_t srs; 74 srs = env->pregs[PR_SRS]; 75 srs &= 3; 76 env->sregs[srs][sreg] = env->regs[reg]; 77 78 #if !defined(CONFIG_USER_ONLY) 79 if (srs == 1 || srs == 2) { 80 if (sreg == 6) { 81 /* Writes to tlb-hi write to mm_cause as a side effect. */ 82 env->sregs[SFR_RW_MM_TLB_HI] = env->regs[reg]; 83 env->sregs[SFR_R_MM_CAUSE] = env->regs[reg]; 84 } else if (sreg == 5) { 85 uint32_t set; 86 uint32_t idx; 87 uint32_t lo, hi; 88 uint32_t vaddr; 89 int tlb_v; 90 91 idx = set = env->sregs[SFR_RW_MM_TLB_SEL]; 92 set >>= 4; 93 set &= 3; 94 95 idx &= 15; 96 /* We've just made a write to tlb_lo. */ 97 lo = env->sregs[SFR_RW_MM_TLB_LO]; 98 /* Writes are done via r_mm_cause. */ 99 hi = env->sregs[SFR_R_MM_CAUSE]; 100 101 vaddr = EXTRACT_FIELD(env->tlbsets[srs - 1][set][idx].hi, 13, 31); 102 vaddr <<= TARGET_PAGE_BITS; 103 tlb_v = EXTRACT_FIELD(env->tlbsets[srs - 1][set][idx].lo, 3, 3); 104 env->tlbsets[srs - 1][set][idx].lo = lo; 105 env->tlbsets[srs - 1][set][idx].hi = hi; 106 107 D_LOG("tlb flush vaddr=%x v=%d pc=%x\n", 108 vaddr, tlb_v, env->pc); 109 if (tlb_v) { 110 tlb_flush_page(env_cpu(env), vaddr); 111 } 112 } 113 } 114 #endif 115 } 116 117 void helper_movl_reg_sreg(CPUCRISState *env, uint32_t reg, uint32_t sreg) 118 { 119 uint32_t srs; 120 env->pregs[PR_SRS] &= 3; 121 srs = env->pregs[PR_SRS]; 122 123 #if !defined(CONFIG_USER_ONLY) 124 if (srs == 1 || srs == 2) { 125 uint32_t set; 126 uint32_t idx; 127 uint32_t lo, hi; 128 129 idx = set = env->sregs[SFR_RW_MM_TLB_SEL]; 130 set >>= 4; 131 set &= 3; 132 idx &= 15; 133 134 /* Update the mirror regs. */ 135 hi = env->tlbsets[srs - 1][set][idx].hi; 136 lo = env->tlbsets[srs - 1][set][idx].lo; 137 env->sregs[SFR_RW_MM_TLB_HI] = hi; 138 env->sregs[SFR_RW_MM_TLB_LO] = lo; 139 } 140 #endif 141 env->regs[reg] = env->sregs[srs][sreg]; 142 } 143 144 static void cris_ccs_rshift(CPUCRISState *env) 145 { 146 uint32_t ccs; 147 148 /* Apply the ccs shift. */ 149 ccs = env->pregs[PR_CCS]; 150 ccs = (ccs & 0xc0000000) | ((ccs & 0x0fffffff) >> 10); 151 if (ccs & U_FLAG) { 152 /* Enter user mode. */ 153 env->ksp = env->regs[R_SP]; 154 env->regs[R_SP] = env->pregs[PR_USP]; 155 } 156 157 env->pregs[PR_CCS] = ccs; 158 } 159 160 void helper_rfe(CPUCRISState *env) 161 { 162 int rflag = env->pregs[PR_CCS] & R_FLAG; 163 164 D_LOG("rfe: erp=%x pid=%x ccs=%x btarget=%x\n", 165 env->pregs[PR_ERP], env->pregs[PR_PID], 166 env->pregs[PR_CCS], 167 env->btarget); 168 169 cris_ccs_rshift(env); 170 171 /* RFE sets the P_FLAG only if the R_FLAG is not set. */ 172 if (!rflag) { 173 env->pregs[PR_CCS] |= P_FLAG; 174 } 175 } 176 177 void helper_rfn(CPUCRISState *env) 178 { 179 int rflag = env->pregs[PR_CCS] & R_FLAG; 180 181 D_LOG("rfn: erp=%x pid=%x ccs=%x btarget=%x\n", 182 env->pregs[PR_ERP], env->pregs[PR_PID], 183 env->pregs[PR_CCS], 184 env->btarget); 185 186 cris_ccs_rshift(env); 187 188 /* Set the P_FLAG only if the R_FLAG is not set. */ 189 if (!rflag) { 190 env->pregs[PR_CCS] |= P_FLAG; 191 } 192 193 /* Always set the M flag. */ 194 env->pregs[PR_CCS] |= M_FLAG_V32; 195 } 196 197 uint32_t helper_btst(CPUCRISState *env, uint32_t t0, uint32_t t1, uint32_t ccs) 198 { 199 /* FIXME: clean this up. */ 200 201 /* 202 * des ref: 203 * The N flag is set according to the selected bit in the dest reg. 204 * The Z flag is set if the selected bit and all bits to the right are 205 * zero. 206 * The X flag is cleared. 207 * Other flags are left untouched. 208 * The destination reg is not affected. 209 */ 210 unsigned int fz, sbit, bset, mask, masked_t0; 211 212 sbit = t1 & 31; 213 bset = !!(t0 & (1 << sbit)); 214 mask = sbit == 31 ? -1 : (1 << (sbit + 1)) - 1; 215 masked_t0 = t0 & mask; 216 fz = !(masked_t0 | bset); 217 218 /* Clear the X, N and Z flags. */ 219 ccs = ccs & ~(X_FLAG | N_FLAG | Z_FLAG); 220 if (env->pregs[PR_VR] < 32) { 221 ccs &= ~(V_FLAG | C_FLAG); 222 } 223 /* Set the N and Z flags accordingly. */ 224 ccs |= (bset << 3) | (fz << 2); 225 return ccs; 226 } 227 228 static inline uint32_t evaluate_flags_writeback(CPUCRISState *env, 229 uint32_t flags, uint32_t ccs) 230 { 231 unsigned int x, z, mask; 232 233 /* Extended arithmetic, leave the z flag alone. */ 234 x = env->cc_x; 235 mask = env->cc_mask | X_FLAG; 236 if (x) { 237 z = flags & Z_FLAG; 238 mask = mask & ~z; 239 } 240 flags &= mask; 241 242 /* all insn clear the x-flag except setf or clrf. */ 243 ccs &= ~mask; 244 ccs |= flags; 245 return ccs; 246 } 247 248 uint32_t helper_evaluate_flags_muls(CPUCRISState *env, 249 uint32_t ccs, uint32_t res, uint32_t mof) 250 { 251 uint32_t flags = 0; 252 int64_t tmp; 253 int dneg; 254 255 dneg = ((int32_t)res) < 0; 256 257 tmp = mof; 258 tmp <<= 32; 259 tmp |= res; 260 if (tmp == 0) { 261 flags |= Z_FLAG; 262 } else if (tmp < 0) { 263 flags |= N_FLAG; 264 } 265 if ((dneg && mof != -1) || (!dneg && mof != 0)) { 266 flags |= V_FLAG; 267 } 268 return evaluate_flags_writeback(env, flags, ccs); 269 } 270 271 uint32_t helper_evaluate_flags_mulu(CPUCRISState *env, 272 uint32_t ccs, uint32_t res, uint32_t mof) 273 { 274 uint32_t flags = 0; 275 uint64_t tmp; 276 277 tmp = mof; 278 tmp <<= 32; 279 tmp |= res; 280 if (tmp == 0) { 281 flags |= Z_FLAG; 282 } else if (tmp >> 63) { 283 flags |= N_FLAG; 284 } 285 if (mof) { 286 flags |= V_FLAG; 287 } 288 289 return evaluate_flags_writeback(env, flags, ccs); 290 } 291 292 uint32_t helper_evaluate_flags_mcp(CPUCRISState *env, uint32_t ccs, 293 uint32_t src, uint32_t dst, uint32_t res) 294 { 295 uint32_t flags = 0; 296 297 src = src & 0x80000000; 298 dst = dst & 0x80000000; 299 300 if ((res & 0x80000000L) != 0L) { 301 flags |= N_FLAG; 302 if (!src && !dst) { 303 flags |= V_FLAG; 304 } else if (src & dst) { 305 flags |= R_FLAG; 306 } 307 } else { 308 if (res == 0L) { 309 flags |= Z_FLAG; 310 } 311 if (src & dst) { 312 flags |= V_FLAG; 313 } 314 if (dst | src) { 315 flags |= R_FLAG; 316 } 317 } 318 319 return evaluate_flags_writeback(env, flags, ccs); 320 } 321 322 uint32_t helper_evaluate_flags_alu_4(CPUCRISState *env, uint32_t ccs, 323 uint32_t src, uint32_t dst, uint32_t res) 324 { 325 uint32_t flags = 0; 326 327 src = src & 0x80000000; 328 dst = dst & 0x80000000; 329 330 if ((res & 0x80000000L) != 0L) { 331 flags |= N_FLAG; 332 if (!src && !dst) { 333 flags |= V_FLAG; 334 } else if (src & dst) { 335 flags |= C_FLAG; 336 } 337 } else { 338 if (res == 0L) { 339 flags |= Z_FLAG; 340 } 341 if (src & dst) { 342 flags |= V_FLAG; 343 } 344 if (dst | src) { 345 flags |= C_FLAG; 346 } 347 } 348 349 return evaluate_flags_writeback(env, flags, ccs); 350 } 351 352 uint32_t helper_evaluate_flags_sub_4(CPUCRISState *env, uint32_t ccs, 353 uint32_t src, uint32_t dst, uint32_t res) 354 { 355 uint32_t flags = 0; 356 357 src = (~src) & 0x80000000; 358 dst = dst & 0x80000000; 359 360 if ((res & 0x80000000L) != 0L) { 361 flags |= N_FLAG; 362 if (!src && !dst) { 363 flags |= V_FLAG; 364 } else if (src & dst) { 365 flags |= C_FLAG; 366 } 367 } else { 368 if (res == 0L) { 369 flags |= Z_FLAG; 370 } 371 if (src & dst) { 372 flags |= V_FLAG; 373 } 374 if (dst | src) { 375 flags |= C_FLAG; 376 } 377 } 378 379 flags ^= C_FLAG; 380 return evaluate_flags_writeback(env, flags, ccs); 381 } 382 383 uint32_t helper_evaluate_flags_move_4(CPUCRISState *env, 384 uint32_t ccs, uint32_t res) 385 { 386 uint32_t flags = 0; 387 388 if ((int32_t)res < 0) { 389 flags |= N_FLAG; 390 } else if (res == 0L) { 391 flags |= Z_FLAG; 392 } 393 394 return evaluate_flags_writeback(env, flags, ccs); 395 } 396 397 uint32_t helper_evaluate_flags_move_2(CPUCRISState *env, 398 uint32_t ccs, uint32_t res) 399 { 400 uint32_t flags = 0; 401 402 if ((int16_t)res < 0L) { 403 flags |= N_FLAG; 404 } else if (res == 0) { 405 flags |= Z_FLAG; 406 } 407 408 return evaluate_flags_writeback(env, flags, ccs); 409 } 410 411 /* 412 * TODO: This is expensive. We could split things up and only evaluate part of 413 * CCR on a need to know basis. For now, we simply re-evaluate everything. 414 */ 415 void helper_evaluate_flags(CPUCRISState *env) 416 { 417 uint32_t src, dst, res; 418 uint32_t flags = 0; 419 420 src = env->cc_src; 421 dst = env->cc_dest; 422 res = env->cc_result; 423 424 if (env->cc_op == CC_OP_SUB || env->cc_op == CC_OP_CMP) { 425 src = ~src; 426 } 427 428 /* 429 * Now, evaluate the flags. This stuff is based on 430 * Per Zander's CRISv10 simulator. 431 */ 432 switch (env->cc_size) { 433 case 1: 434 if ((res & 0x80L) != 0L) { 435 flags |= N_FLAG; 436 if (((src & 0x80L) == 0L) && ((dst & 0x80L) == 0L)) { 437 flags |= V_FLAG; 438 } else if (((src & 0x80L) != 0L) && ((dst & 0x80L) != 0L)) { 439 flags |= C_FLAG; 440 } 441 } else { 442 if ((res & 0xFFL) == 0L) { 443 flags |= Z_FLAG; 444 } 445 if (((src & 0x80L) != 0L) && ((dst & 0x80L) != 0L)) { 446 flags |= V_FLAG; 447 } 448 if ((dst & 0x80L) != 0L || (src & 0x80L) != 0L) { 449 flags |= C_FLAG; 450 } 451 } 452 break; 453 case 2: 454 if ((res & 0x8000L) != 0L) { 455 flags |= N_FLAG; 456 if (((src & 0x8000L) == 0L) && ((dst & 0x8000L) == 0L)) { 457 flags |= V_FLAG; 458 } else if (((src & 0x8000L) != 0L) && ((dst & 0x8000L) != 0L)) { 459 flags |= C_FLAG; 460 } 461 } else { 462 if ((res & 0xFFFFL) == 0L) { 463 flags |= Z_FLAG; 464 } 465 if (((src & 0x8000L) != 0L) && ((dst & 0x8000L) != 0L)) { 466 flags |= V_FLAG; 467 } 468 if ((dst & 0x8000L) != 0L || (src & 0x8000L) != 0L) { 469 flags |= C_FLAG; 470 } 471 } 472 break; 473 case 4: 474 if ((res & 0x80000000L) != 0L) { 475 flags |= N_FLAG; 476 if (((src & 0x80000000L) == 0L) && ((dst & 0x80000000L) == 0L)) { 477 flags |= V_FLAG; 478 } else if (((src & 0x80000000L) != 0L) && 479 ((dst & 0x80000000L) != 0L)) { 480 flags |= C_FLAG; 481 } 482 } else { 483 if (res == 0L) { 484 flags |= Z_FLAG; 485 } 486 if (((src & 0x80000000L) != 0L) && ((dst & 0x80000000L) != 0L)) { 487 flags |= V_FLAG; 488 } 489 if ((dst & 0x80000000L) != 0L || (src & 0x80000000L) != 0L) { 490 flags |= C_FLAG; 491 } 492 } 493 break; 494 default: 495 break; 496 } 497 498 if (env->cc_op == CC_OP_SUB || env->cc_op == CC_OP_CMP) { 499 flags ^= C_FLAG; 500 } 501 502 env->pregs[PR_CCS] = evaluate_flags_writeback(env, flags, 503 env->pregs[PR_CCS]); 504 } 505 506 void helper_top_evaluate_flags(CPUCRISState *env) 507 { 508 switch (env->cc_op) { 509 case CC_OP_MCP: 510 env->pregs[PR_CCS] 511 = helper_evaluate_flags_mcp(env, env->pregs[PR_CCS], 512 env->cc_src, env->cc_dest, 513 env->cc_result); 514 break; 515 case CC_OP_MULS: 516 env->pregs[PR_CCS] 517 = helper_evaluate_flags_muls(env, env->pregs[PR_CCS], 518 env->cc_result, env->pregs[PR_MOF]); 519 break; 520 case CC_OP_MULU: 521 env->pregs[PR_CCS] 522 = helper_evaluate_flags_mulu(env, env->pregs[PR_CCS], 523 env->cc_result, env->pregs[PR_MOF]); 524 break; 525 case CC_OP_MOVE: 526 case CC_OP_AND: 527 case CC_OP_OR: 528 case CC_OP_XOR: 529 case CC_OP_ASR: 530 case CC_OP_LSR: 531 case CC_OP_LSL: 532 switch (env->cc_size) { 533 case 4: 534 env->pregs[PR_CCS] = 535 helper_evaluate_flags_move_4(env, 536 env->pregs[PR_CCS], 537 env->cc_result); 538 break; 539 case 2: 540 env->pregs[PR_CCS] = 541 helper_evaluate_flags_move_2(env, 542 env->pregs[PR_CCS], 543 env->cc_result); 544 break; 545 default: 546 helper_evaluate_flags(env); 547 break; 548 } 549 break; 550 case CC_OP_FLAGS: 551 /* live. */ 552 break; 553 case CC_OP_SUB: 554 case CC_OP_CMP: 555 if (env->cc_size == 4) { 556 env->pregs[PR_CCS] = 557 helper_evaluate_flags_sub_4(env, 558 env->pregs[PR_CCS], 559 env->cc_src, env->cc_dest, 560 env->cc_result); 561 } else { 562 helper_evaluate_flags(env); 563 } 564 break; 565 default: 566 switch (env->cc_size) { 567 case 4: 568 env->pregs[PR_CCS] = 569 helper_evaluate_flags_alu_4(env, 570 env->pregs[PR_CCS], 571 env->cc_src, env->cc_dest, 572 env->cc_result); 573 break; 574 default: 575 helper_evaluate_flags(env); 576 break; 577 } 578 break; 579 } 580 } 581