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