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