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