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