|
|
1.1 ! root 1: /* ! 2: * MIPS32 emulation for qemu: main translation routines. ! 3: * ! 4: * Copyright (c) 2004-2005 Jocelyn Mayer ! 5: * ! 6: * This library is free software; you can redistribute it and/or ! 7: * modify it under the terms of the GNU Lesser General Public ! 8: * License as published by the Free Software Foundation; either ! 9: * version 2 of the License, or (at your option) any later version. ! 10: * ! 11: * This library is distributed in the hope that it will be useful, ! 12: * but WITHOUT ANY WARRANTY; without even the implied warranty of ! 13: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ! 14: * Lesser General Public License for more details. ! 15: * ! 16: * You should have received a copy of the GNU Lesser General Public ! 17: * License along with this library; if not, write to the Free Software ! 18: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ! 19: */ ! 20: ! 21: #include <stdarg.h> ! 22: #include <stdlib.h> ! 23: #include <stdio.h> ! 24: #include <string.h> ! 25: #include <inttypes.h> ! 26: ! 27: #include "cpu.h" ! 28: #include "exec-all.h" ! 29: #include "disas.h" ! 30: ! 31: #define MIPS_DEBUG_DISAS ! 32: //#define MIPS_SINGLE_STEP ! 33: ! 34: enum { ! 35: #define DEF(s, n, copy_size) INDEX_op_ ## s, ! 36: #include "opc.h" ! 37: #undef DEF ! 38: NB_OPS, ! 39: }; ! 40: ! 41: static uint16_t *gen_opc_ptr; ! 42: static uint32_t *gen_opparam_ptr; ! 43: ! 44: #include "gen-op.h" ! 45: ! 46: /* MIPS opcodes */ ! 47: #define EXT_SPECIAL 0x100 ! 48: #define EXT_SPECIAL2 0x200 ! 49: #define EXT_REGIMM 0x300 ! 50: #define EXT_CP0 0x400 ! 51: #define EXT_CP1 0x500 ! 52: #define EXT_CP2 0x600 ! 53: #define EXT_CP3 0x700 ! 54: ! 55: enum { ! 56: /* indirect opcode tables */ ! 57: OPC_SPECIAL = 0x00, ! 58: OPC_BREGIMM = 0x01, ! 59: OPC_CP0 = 0x10, ! 60: OPC_CP1 = 0x11, ! 61: OPC_CP2 = 0x12, ! 62: OPC_CP3 = 0x13, ! 63: OPC_SPECIAL2 = 0x1C, ! 64: /* arithmetic with immediate */ ! 65: OPC_ADDI = 0x08, ! 66: OPC_ADDIU = 0x09, ! 67: OPC_SLTI = 0x0A, ! 68: OPC_SLTIU = 0x0B, ! 69: OPC_ANDI = 0x0C, ! 70: OPC_ORI = 0x0D, ! 71: OPC_XORI = 0x0E, ! 72: OPC_LUI = 0x0F, ! 73: /* Jump and branches */ ! 74: OPC_J = 0x02, ! 75: OPC_JAL = 0x03, ! 76: OPC_BEQ = 0x04, /* Unconditional if rs = rt = 0 (B) */ ! 77: OPC_BEQL = 0x14, ! 78: OPC_BNE = 0x05, ! 79: OPC_BNEL = 0x15, ! 80: OPC_BLEZ = 0x06, ! 81: OPC_BLEZL = 0x16, ! 82: OPC_BGTZ = 0x07, ! 83: OPC_BGTZL = 0x17, ! 84: OPC_JALX = 0x1D, /* MIPS 16 only */ ! 85: /* Load and stores */ ! 86: OPC_LB = 0x20, ! 87: OPC_LH = 0x21, ! 88: OPC_LWL = 0x22, ! 89: OPC_LW = 0x23, ! 90: OPC_LBU = 0x24, ! 91: OPC_LHU = 0x25, ! 92: OPC_LWR = 0x26, ! 93: OPC_SB = 0x28, ! 94: OPC_SH = 0x29, ! 95: OPC_SWL = 0x2A, ! 96: OPC_SW = 0x2B, ! 97: OPC_SWR = 0x2E, ! 98: OPC_LL = 0x30, ! 99: OPC_SC = 0x38, ! 100: /* Floating point load/store */ ! 101: OPC_LWC1 = 0x31, ! 102: OPC_LWC2 = 0x32, ! 103: OPC_LDC1 = 0x35, ! 104: OPC_LDC2 = 0x36, ! 105: OPC_SWC1 = 0x39, ! 106: OPC_SWC2 = 0x3A, ! 107: OPC_SDC1 = 0x3D, ! 108: OPC_SDC2 = 0x3E, ! 109: /* Cache and prefetch */ ! 110: OPC_CACHE = 0x2F, ! 111: OPC_PREF = 0x33, ! 112: }; ! 113: ! 114: /* MIPS special opcodes */ ! 115: enum { ! 116: /* Shifts */ ! 117: OPC_SLL = 0x00 | EXT_SPECIAL, ! 118: /* NOP is SLL r0, r0, 0 */ ! 119: /* SSNOP is SLL r0, r0, 1 */ ! 120: OPC_SRL = 0x02 | EXT_SPECIAL, ! 121: OPC_SRA = 0x03 | EXT_SPECIAL, ! 122: OPC_SLLV = 0x04 | EXT_SPECIAL, ! 123: OPC_SRLV = 0x06 | EXT_SPECIAL, ! 124: OPC_SRAV = 0x07 | EXT_SPECIAL, ! 125: /* Multiplication / division */ ! 126: OPC_MULT = 0x18 | EXT_SPECIAL, ! 127: OPC_MULTU = 0x19 | EXT_SPECIAL, ! 128: OPC_DIV = 0x1A | EXT_SPECIAL, ! 129: OPC_DIVU = 0x1B | EXT_SPECIAL, ! 130: /* 2 registers arithmetic / logic */ ! 131: OPC_ADD = 0x20 | EXT_SPECIAL, ! 132: OPC_ADDU = 0x21 | EXT_SPECIAL, ! 133: OPC_SUB = 0x22 | EXT_SPECIAL, ! 134: OPC_SUBU = 0x23 | EXT_SPECIAL, ! 135: OPC_AND = 0x24 | EXT_SPECIAL, ! 136: OPC_OR = 0x25 | EXT_SPECIAL, ! 137: OPC_XOR = 0x26 | EXT_SPECIAL, ! 138: OPC_NOR = 0x27 | EXT_SPECIAL, ! 139: OPC_SLT = 0x2A | EXT_SPECIAL, ! 140: OPC_SLTU = 0x2B | EXT_SPECIAL, ! 141: /* Jumps */ ! 142: OPC_JR = 0x08 | EXT_SPECIAL, ! 143: OPC_JALR = 0x09 | EXT_SPECIAL, ! 144: /* Traps */ ! 145: OPC_TGE = 0x30 | EXT_SPECIAL, ! 146: OPC_TGEU = 0x31 | EXT_SPECIAL, ! 147: OPC_TLT = 0x32 | EXT_SPECIAL, ! 148: OPC_TLTU = 0x33 | EXT_SPECIAL, ! 149: OPC_TEQ = 0x34 | EXT_SPECIAL, ! 150: OPC_TNE = 0x36 | EXT_SPECIAL, ! 151: /* HI / LO registers load & stores */ ! 152: OPC_MFHI = 0x10 | EXT_SPECIAL, ! 153: OPC_MTHI = 0x11 | EXT_SPECIAL, ! 154: OPC_MFLO = 0x12 | EXT_SPECIAL, ! 155: OPC_MTLO = 0x13 | EXT_SPECIAL, ! 156: /* Conditional moves */ ! 157: OPC_MOVZ = 0x0A | EXT_SPECIAL, ! 158: OPC_MOVN = 0x0B | EXT_SPECIAL, ! 159: ! 160: OPC_MOVCI = 0x01 | EXT_SPECIAL, ! 161: ! 162: /* Special */ ! 163: OPC_PMON = 0x05 | EXT_SPECIAL, ! 164: OPC_SYSCALL = 0x0C | EXT_SPECIAL, ! 165: OPC_BREAK = 0x0D | EXT_SPECIAL, ! 166: OPC_SYNC = 0x0F | EXT_SPECIAL, ! 167: }; ! 168: ! 169: enum { ! 170: /* Mutiply & xxx operations */ ! 171: OPC_MADD = 0x00 | EXT_SPECIAL2, ! 172: OPC_MADDU = 0x01 | EXT_SPECIAL2, ! 173: OPC_MUL = 0x02 | EXT_SPECIAL2, ! 174: OPC_MSUB = 0x04 | EXT_SPECIAL2, ! 175: OPC_MSUBU = 0x05 | EXT_SPECIAL2, ! 176: /* Misc */ ! 177: OPC_CLZ = 0x20 | EXT_SPECIAL2, ! 178: OPC_CLO = 0x21 | EXT_SPECIAL2, ! 179: /* Special */ ! 180: OPC_SDBBP = 0x3F | EXT_SPECIAL2, ! 181: }; ! 182: ! 183: /* Branch REGIMM */ ! 184: enum { ! 185: OPC_BLTZ = 0x00 | EXT_REGIMM, ! 186: OPC_BLTZL = 0x02 | EXT_REGIMM, ! 187: OPC_BGEZ = 0x01 | EXT_REGIMM, ! 188: OPC_BGEZL = 0x03 | EXT_REGIMM, ! 189: OPC_BLTZAL = 0x10 | EXT_REGIMM, ! 190: OPC_BLTZALL = 0x12 | EXT_REGIMM, ! 191: OPC_BGEZAL = 0x11 | EXT_REGIMM, ! 192: OPC_BGEZALL = 0x13 | EXT_REGIMM, ! 193: OPC_TGEI = 0x08 | EXT_REGIMM, ! 194: OPC_TGEIU = 0x09 | EXT_REGIMM, ! 195: OPC_TLTI = 0x0A | EXT_REGIMM, ! 196: OPC_TLTIU = 0x0B | EXT_REGIMM, ! 197: OPC_TEQI = 0x0C | EXT_REGIMM, ! 198: OPC_TNEI = 0x0E | EXT_REGIMM, ! 199: }; ! 200: ! 201: enum { ! 202: /* Coprocessor 0 (MMU) */ ! 203: OPC_MFC0 = 0x00 | EXT_CP0, ! 204: OPC_MTC0 = 0x04 | EXT_CP0, ! 205: OPC_TLBR = 0x01 | EXT_CP0, ! 206: OPC_TLBWI = 0x02 | EXT_CP0, ! 207: OPC_TLBWR = 0x06 | EXT_CP0, ! 208: OPC_TLBP = 0x08 | EXT_CP0, ! 209: OPC_ERET = 0x18 | EXT_CP0, ! 210: OPC_DERET = 0x1F | EXT_CP0, ! 211: OPC_WAIT = 0x20 | EXT_CP0, ! 212: }; ! 213: ! 214: const unsigned char *regnames[] = ! 215: { "r0", "at", "v0", "v1", "a0", "a1", "a2", "a3", ! 216: "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", ! 217: "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", ! 218: "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra", }; ! 219: ! 220: /* Warning: no function for r0 register (hard wired to zero) */ ! 221: #define GEN32(func, NAME) \ ! 222: static GenOpFunc *NAME ## _table [32] = { \ ! 223: NULL, NAME ## 1, NAME ## 2, NAME ## 3, \ ! 224: NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \ ! 225: NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11, \ ! 226: NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15, \ ! 227: NAME ## 16, NAME ## 17, NAME ## 18, NAME ## 19, \ ! 228: NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23, \ ! 229: NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27, \ ! 230: NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31, \ ! 231: }; \ ! 232: static inline void func(int n) \ ! 233: { \ ! 234: NAME ## _table[n](); \ ! 235: } ! 236: ! 237: /* General purpose registers moves */ ! 238: GEN32(gen_op_load_gpr_T0, gen_op_load_gpr_T0_gpr); ! 239: GEN32(gen_op_load_gpr_T1, gen_op_load_gpr_T1_gpr); ! 240: GEN32(gen_op_load_gpr_T2, gen_op_load_gpr_T2_gpr); ! 241: ! 242: GEN32(gen_op_store_T0_gpr, gen_op_store_T0_gpr_gpr); ! 243: GEN32(gen_op_store_T1_gpr, gen_op_store_T1_gpr_gpr); ! 244: ! 245: typedef struct DisasContext { ! 246: struct TranslationBlock *tb; ! 247: target_ulong pc, saved_pc; ! 248: uint32_t opcode; ! 249: /* Routine used to access memory */ ! 250: int mem_idx; ! 251: uint32_t hflags, saved_hflags; ! 252: uint32_t CP0_Status; ! 253: int bstate; ! 254: target_ulong btarget; ! 255: } DisasContext; ! 256: ! 257: enum { ! 258: BS_NONE = 0, /* We go out of the TB without reaching a branch or an ! 259: * exception condition ! 260: */ ! 261: BS_STOP = 1, /* We want to stop translation for any reason */ ! 262: BS_BRANCH = 2, /* We reached a branch condition */ ! 263: BS_EXCP = 3, /* We reached an exception condition */ ! 264: }; ! 265: ! 266: #if defined MIPS_DEBUG_DISAS ! 267: #define MIPS_DEBUG(fmt, args...) \ ! 268: do { \ ! 269: if (loglevel & CPU_LOG_TB_IN_ASM) { \ ! 270: fprintf(logfile, "%08x: %08x " fmt "\n", \ ! 271: ctx->pc, ctx->opcode , ##args); \ ! 272: } \ ! 273: } while (0) ! 274: #else ! 275: #define MIPS_DEBUG(fmt, args...) do { } while(0) ! 276: #endif ! 277: ! 278: #define MIPS_INVAL(op) \ ! 279: do { \ ! 280: MIPS_DEBUG("Invalid %s %03x %03x %03x", op, ctx->opcode >> 26, \ ! 281: ctx->opcode & 0x3F, ((ctx->opcode >> 16) & 0x1F)); \ ! 282: } while (0) ! 283: ! 284: #define GEN_LOAD_REG_TN(Tn, Rn) \ ! 285: do { \ ! 286: if (Rn == 0) { \ ! 287: glue(gen_op_reset_, Tn)(); \ ! 288: } else { \ ! 289: glue(gen_op_load_gpr_, Tn)(Rn); \ ! 290: } \ ! 291: } while (0) ! 292: ! 293: #define GEN_LOAD_IMM_TN(Tn, Imm) \ ! 294: do { \ ! 295: if (Imm == 0) { \ ! 296: glue(gen_op_reset_, Tn)(); \ ! 297: } else { \ ! 298: glue(gen_op_set_, Tn)(Imm); \ ! 299: } \ ! 300: } while (0) ! 301: ! 302: #define GEN_STORE_TN_REG(Rn, Tn) \ ! 303: do { \ ! 304: if (Rn != 0) { \ ! 305: glue(glue(gen_op_store_, Tn),_gpr)(Rn); \ ! 306: } \ ! 307: } while (0) ! 308: ! 309: static inline void save_cpu_state (DisasContext *ctx, int do_save_pc) ! 310: { ! 311: #if defined MIPS_DEBUG_DISAS ! 312: if (loglevel & CPU_LOG_TB_IN_ASM) { ! 313: fprintf(logfile, "hflags %08x saved %08x\n", ! 314: ctx->hflags, ctx->saved_hflags); ! 315: } ! 316: #endif ! 317: if (do_save_pc && ctx->pc != ctx->saved_pc) { ! 318: gen_op_save_pc(ctx->pc); ! 319: ctx->saved_pc = ctx->pc; ! 320: } ! 321: if (ctx->hflags != ctx->saved_hflags) { ! 322: gen_op_save_state(ctx->hflags); ! 323: ctx->saved_hflags = ctx->hflags; ! 324: if (ctx->hflags & MIPS_HFLAG_BR) { ! 325: gen_op_save_breg_target(); ! 326: } else if (ctx->hflags & MIPS_HFLAG_B) { ! 327: gen_op_save_btarget(ctx->btarget); ! 328: } else if (ctx->hflags & MIPS_HFLAG_BMASK) { ! 329: gen_op_save_bcond(); ! 330: gen_op_save_btarget(ctx->btarget); ! 331: } ! 332: } ! 333: } ! 334: ! 335: static inline void generate_exception (DisasContext *ctx, int excp) ! 336: { ! 337: #if defined MIPS_DEBUG_DISAS ! 338: if (loglevel & CPU_LOG_TB_IN_ASM) ! 339: fprintf(logfile, "%s: raise exception %d\n", __func__, excp); ! 340: #endif ! 341: save_cpu_state(ctx, 1); ! 342: gen_op_raise_exception(excp); ! 343: ctx->bstate = BS_EXCP; ! 344: } ! 345: ! 346: #if defined(CONFIG_USER_ONLY) ! 347: #define op_ldst(name) gen_op_##name##_raw() ! 348: #define OP_LD_TABLE(width) ! 349: #define OP_ST_TABLE(width) ! 350: #else ! 351: #define op_ldst(name) (*gen_op_##name[ctx->mem_idx])() ! 352: #define OP_LD_TABLE(width) \ ! 353: static GenOpFunc *gen_op_l##width[] = { \ ! 354: &gen_op_l##width##_user, \ ! 355: &gen_op_l##width##_kernel, \ ! 356: } ! 357: #define OP_ST_TABLE(width) \ ! 358: static GenOpFunc *gen_op_s##width[] = { \ ! 359: &gen_op_s##width##_user, \ ! 360: &gen_op_s##width##_kernel, \ ! 361: } ! 362: #endif ! 363: ! 364: #ifdef TARGET_MIPS64 ! 365: OP_LD_TABLE(d); ! 366: OP_LD_TABLE(dl); ! 367: OP_LD_TABLE(dr); ! 368: OP_ST_TABLE(d); ! 369: OP_ST_TABLE(dl); ! 370: OP_ST_TABLE(dr); ! 371: #endif ! 372: OP_LD_TABLE(w); ! 373: OP_LD_TABLE(wl); ! 374: OP_LD_TABLE(wr); ! 375: OP_ST_TABLE(w); ! 376: OP_ST_TABLE(wl); ! 377: OP_ST_TABLE(wr); ! 378: OP_LD_TABLE(h); ! 379: OP_LD_TABLE(hu); ! 380: OP_ST_TABLE(h); ! 381: OP_LD_TABLE(b); ! 382: OP_LD_TABLE(bu); ! 383: OP_ST_TABLE(b); ! 384: OP_LD_TABLE(l); ! 385: OP_ST_TABLE(c); ! 386: ! 387: /* Load and store */ ! 388: static void gen_ldst (DisasContext *ctx, uint16_t opc, int rt, ! 389: int base, int16_t offset) ! 390: { ! 391: const unsigned char *opn = "unk"; ! 392: ! 393: if (base == 0) { ! 394: GEN_LOAD_IMM_TN(T0, offset); ! 395: } else if (offset == 0) { ! 396: gen_op_load_gpr_T0(base); ! 397: } else { ! 398: gen_op_load_gpr_T0(base); ! 399: gen_op_set_T1(offset); ! 400: gen_op_add(); ! 401: } ! 402: /* Don't do NOP if destination is zero: we must perform the actual ! 403: * memory access ! 404: */ ! 405: switch (opc) { ! 406: #if defined(TARGET_MIPS64) ! 407: case OPC_LD: ! 408: #if defined (MIPS_HAS_UNALIGNED_LS) ! 409: case OPC_ULD: ! 410: #endif ! 411: op_ldst(ld); ! 412: GEN_STORE_TN_REG(rt, T0); ! 413: opn = "ld"; ! 414: break; ! 415: case OPC_SD: ! 416: #if defined (MIPS_HAS_UNALIGNED_LS) ! 417: case OPC_USD: ! 418: #endif ! 419: GEN_LOAD_REG_TN(T1, rt); ! 420: op_ldst(sd); ! 421: opn = "sd"; ! 422: break; ! 423: case OPC_LDL: ! 424: op_ldst(ldl); ! 425: GEN_STORE_TN_REG(rt, T0); ! 426: opn = "ldl"; ! 427: break; ! 428: case OPC_SDL: ! 429: GEN_LOAD_REG_TN(T1, rt); ! 430: op_ldst(sdl); ! 431: opn = "sdl"; ! 432: break; ! 433: case OPC_LDR: ! 434: op_ldst(ldr); ! 435: GEN_STORE_TN_REG(rt, T0); ! 436: opn = "ldr"; ! 437: break; ! 438: case OPC_SDR: ! 439: GEN_LOAD_REG_TN(T1, rt); ! 440: op_ldst(sdr); ! 441: opn = "sdr"; ! 442: break; ! 443: #endif ! 444: case OPC_LW: ! 445: #if defined (MIPS_HAS_UNALIGNED_LS) ! 446: case OPC_ULW: ! 447: #endif ! 448: op_ldst(lw); ! 449: GEN_STORE_TN_REG(rt, T0); ! 450: opn = "lw"; ! 451: break; ! 452: case OPC_SW: ! 453: #if defined (MIPS_HAS_UNALIGNED_LS) ! 454: case OPC_USW: ! 455: #endif ! 456: GEN_LOAD_REG_TN(T1, rt); ! 457: op_ldst(sw); ! 458: opn = "sw"; ! 459: break; ! 460: case OPC_LH: ! 461: #if defined (MIPS_HAS_UNALIGNED_LS) ! 462: case OPC_ULH: ! 463: #endif ! 464: op_ldst(lh); ! 465: GEN_STORE_TN_REG(rt, T0); ! 466: opn = "lh"; ! 467: break; ! 468: case OPC_SH: ! 469: #if defined (MIPS_HAS_UNALIGNED_LS) ! 470: case OPC_USH: ! 471: #endif ! 472: GEN_LOAD_REG_TN(T1, rt); ! 473: op_ldst(sh); ! 474: opn = "sh"; ! 475: break; ! 476: case OPC_LHU: ! 477: #if defined (MIPS_HAS_UNALIGNED_LS) ! 478: case OPC_ULHU: ! 479: #endif ! 480: op_ldst(lhu); ! 481: GEN_STORE_TN_REG(rt, T0); ! 482: opn = "lhu"; ! 483: break; ! 484: case OPC_LB: ! 485: op_ldst(lb); ! 486: GEN_STORE_TN_REG(rt, T0); ! 487: opn = "lb"; ! 488: break; ! 489: case OPC_SB: ! 490: GEN_LOAD_REG_TN(T1, rt); ! 491: op_ldst(sb); ! 492: opn = "sb"; ! 493: break; ! 494: case OPC_LBU: ! 495: op_ldst(lbu); ! 496: GEN_STORE_TN_REG(rt, T0); ! 497: opn = "lbu"; ! 498: break; ! 499: case OPC_LWL: ! 500: GEN_LOAD_REG_TN(T1, rt); ! 501: op_ldst(lwl); ! 502: GEN_STORE_TN_REG(rt, T0); ! 503: opn = "lwl"; ! 504: break; ! 505: case OPC_SWL: ! 506: GEN_LOAD_REG_TN(T1, rt); ! 507: op_ldst(swl); ! 508: opn = "swr"; ! 509: break; ! 510: case OPC_LWR: ! 511: GEN_LOAD_REG_TN(T1, rt); ! 512: op_ldst(lwr); ! 513: GEN_STORE_TN_REG(rt, T0); ! 514: opn = "lwr"; ! 515: break; ! 516: case OPC_SWR: ! 517: GEN_LOAD_REG_TN(T1, rt); ! 518: op_ldst(swr); ! 519: opn = "swr"; ! 520: break; ! 521: case OPC_LL: ! 522: op_ldst(ll); ! 523: GEN_STORE_TN_REG(rt, T0); ! 524: opn = "ll"; ! 525: break; ! 526: case OPC_SC: ! 527: GEN_LOAD_REG_TN(T1, rt); ! 528: op_ldst(sc); ! 529: GEN_STORE_TN_REG(rt, T0); ! 530: opn = "sc"; ! 531: break; ! 532: default: ! 533: MIPS_INVAL("load/store"); ! 534: generate_exception(ctx, EXCP_RI); ! 535: return; ! 536: } ! 537: MIPS_DEBUG("%s %s, %d(%s)", opn, regnames[rt], offset, regnames[base]); ! 538: } ! 539: ! 540: /* Arithmetic with immediate operand */ ! 541: static void gen_arith_imm (DisasContext *ctx, uint16_t opc, int rt, ! 542: int rs, int16_t imm) ! 543: { ! 544: uint32_t uimm; ! 545: const unsigned char *opn = "unk"; ! 546: ! 547: if (rt == 0 && opc != OPC_ADDI) { ! 548: /* if no destination, treat it as a NOP ! 549: * For addi, we must generate the overflow exception when needed. ! 550: */ ! 551: MIPS_DEBUG("NOP"); ! 552: return; ! 553: } ! 554: if (opc == OPC_ADDI || opc == OPC_ADDIU || ! 555: opc == OPC_SLTI || opc == OPC_SLTIU) ! 556: uimm = (int32_t)imm; /* Sign extent to 32 bits */ ! 557: else ! 558: uimm = (uint16_t)imm; ! 559: if (opc != OPC_LUI) { ! 560: GEN_LOAD_REG_TN(T0, rs); ! 561: GEN_LOAD_IMM_TN(T1, uimm); ! 562: } else { ! 563: uimm = uimm << 16; ! 564: GEN_LOAD_IMM_TN(T0, uimm); ! 565: } ! 566: switch (opc) { ! 567: case OPC_ADDI: ! 568: save_cpu_state(ctx, 1); ! 569: gen_op_addo(); ! 570: opn = "addi"; ! 571: break; ! 572: case OPC_ADDIU: ! 573: gen_op_add(); ! 574: opn = "addiu"; ! 575: break; ! 576: case OPC_SLTI: ! 577: gen_op_lt(); ! 578: opn = "slti"; ! 579: break; ! 580: case OPC_SLTIU: ! 581: gen_op_ltu(); ! 582: opn = "sltiu"; ! 583: break; ! 584: case OPC_ANDI: ! 585: gen_op_and(); ! 586: opn = "andi"; ! 587: break; ! 588: case OPC_ORI: ! 589: gen_op_or(); ! 590: opn = "ori"; ! 591: break; ! 592: case OPC_XORI: ! 593: gen_op_xor(); ! 594: opn = "xori"; ! 595: break; ! 596: case OPC_LUI: ! 597: opn = "lui"; ! 598: break; ! 599: case OPC_SLL: ! 600: gen_op_sll(); ! 601: opn = "sll"; ! 602: break; ! 603: case OPC_SRA: ! 604: gen_op_sra(); ! 605: opn = "sra"; ! 606: break; ! 607: case OPC_SRL: ! 608: gen_op_srl(); ! 609: opn = "srl"; ! 610: break; ! 611: default: ! 612: MIPS_INVAL("imm arith"); ! 613: generate_exception(ctx, EXCP_RI); ! 614: return; ! 615: } ! 616: GEN_STORE_TN_REG(rt, T0); ! 617: MIPS_DEBUG("%s %s, %s, %x", opn, regnames[rt], regnames[rs], uimm); ! 618: } ! 619: ! 620: /* Arithmetic */ ! 621: static void gen_arith (DisasContext *ctx, uint16_t opc, ! 622: int rd, int rs, int rt) ! 623: { ! 624: const unsigned char *opn = "unk"; ! 625: ! 626: if (rd == 0 && opc != OPC_ADD && opc != OPC_SUB) { ! 627: /* if no destination, treat it as a NOP ! 628: * For add & sub, we must generate the overflow exception when needed. ! 629: */ ! 630: MIPS_DEBUG("NOP"); ! 631: return; ! 632: } ! 633: GEN_LOAD_REG_TN(T0, rs); ! 634: GEN_LOAD_REG_TN(T1, rt); ! 635: switch (opc) { ! 636: case OPC_ADD: ! 637: save_cpu_state(ctx, 1); ! 638: gen_op_addo(); ! 639: opn = "add"; ! 640: break; ! 641: case OPC_ADDU: ! 642: gen_op_add(); ! 643: opn = "addu"; ! 644: break; ! 645: case OPC_SUB: ! 646: save_cpu_state(ctx, 1); ! 647: gen_op_subo(); ! 648: opn = "sub"; ! 649: break; ! 650: case OPC_SUBU: ! 651: gen_op_sub(); ! 652: opn = "subu"; ! 653: break; ! 654: case OPC_SLT: ! 655: gen_op_lt(); ! 656: opn = "slt"; ! 657: break; ! 658: case OPC_SLTU: ! 659: gen_op_ltu(); ! 660: opn = "sltu"; ! 661: break; ! 662: case OPC_AND: ! 663: gen_op_and(); ! 664: opn = "and"; ! 665: break; ! 666: case OPC_NOR: ! 667: gen_op_nor(); ! 668: opn = "nor"; ! 669: break; ! 670: case OPC_OR: ! 671: gen_op_or(); ! 672: opn = "or"; ! 673: break; ! 674: case OPC_XOR: ! 675: gen_op_xor(); ! 676: opn = "xor"; ! 677: break; ! 678: case OPC_MUL: ! 679: gen_op_mul(); ! 680: opn = "mul"; ! 681: break; ! 682: case OPC_MOVN: ! 683: gen_op_movn(rd); ! 684: opn = "movn"; ! 685: goto print; ! 686: case OPC_MOVZ: ! 687: gen_op_movz(rd); ! 688: opn = "movz"; ! 689: goto print; ! 690: case OPC_SLLV: ! 691: gen_op_sllv(); ! 692: opn = "sllv"; ! 693: break; ! 694: case OPC_SRAV: ! 695: gen_op_srav(); ! 696: opn = "srav"; ! 697: break; ! 698: case OPC_SRLV: ! 699: gen_op_srlv(); ! 700: opn = "srlv"; ! 701: break; ! 702: default: ! 703: MIPS_INVAL("arith"); ! 704: generate_exception(ctx, EXCP_RI); ! 705: return; ! 706: } ! 707: GEN_STORE_TN_REG(rd, T0); ! 708: print: ! 709: MIPS_DEBUG("%s %s, %s, %s", opn, regnames[rd], regnames[rs], regnames[rt]); ! 710: } ! 711: ! 712: /* Arithmetic on HI/LO registers */ ! 713: static void gen_HILO (DisasContext *ctx, uint16_t opc, int reg) ! 714: { ! 715: const unsigned char *opn = "unk"; ! 716: ! 717: if (reg == 0 && (opc == OPC_MFHI || opc == OPC_MFLO)) { ! 718: /* Treat as a NOP */ ! 719: MIPS_DEBUG("NOP"); ! 720: return; ! 721: } ! 722: switch (opc) { ! 723: case OPC_MFHI: ! 724: gen_op_load_HI(); ! 725: GEN_STORE_TN_REG(reg, T0); ! 726: opn = "mfhi"; ! 727: break; ! 728: case OPC_MFLO: ! 729: gen_op_load_LO(); ! 730: GEN_STORE_TN_REG(reg, T0); ! 731: opn = "mflo"; ! 732: break; ! 733: case OPC_MTHI: ! 734: GEN_LOAD_REG_TN(T0, reg); ! 735: gen_op_store_HI(); ! 736: opn = "mthi"; ! 737: break; ! 738: case OPC_MTLO: ! 739: GEN_LOAD_REG_TN(T0, reg); ! 740: gen_op_store_LO(); ! 741: opn = "mtlo"; ! 742: break; ! 743: default: ! 744: MIPS_INVAL("HILO"); ! 745: generate_exception(ctx, EXCP_RI); ! 746: return; ! 747: } ! 748: MIPS_DEBUG("%s %s", opn, regnames[reg]); ! 749: } ! 750: ! 751: static void gen_muldiv (DisasContext *ctx, uint16_t opc, ! 752: int rs, int rt) ! 753: { ! 754: const unsigned char *opn = "unk"; ! 755: ! 756: GEN_LOAD_REG_TN(T0, rs); ! 757: GEN_LOAD_REG_TN(T1, rt); ! 758: switch (opc) { ! 759: case OPC_DIV: ! 760: gen_op_div(); ! 761: opn = "div"; ! 762: break; ! 763: case OPC_DIVU: ! 764: gen_op_divu(); ! 765: opn = "divu"; ! 766: break; ! 767: case OPC_MULT: ! 768: gen_op_mult(); ! 769: opn = "mult"; ! 770: break; ! 771: case OPC_MULTU: ! 772: gen_op_multu(); ! 773: opn = "multu"; ! 774: break; ! 775: case OPC_MADD: ! 776: gen_op_madd(); ! 777: opn = "madd"; ! 778: break; ! 779: case OPC_MADDU: ! 780: gen_op_maddu(); ! 781: opn = "maddu"; ! 782: break; ! 783: case OPC_MSUB: ! 784: gen_op_msub(); ! 785: opn = "msub"; ! 786: break; ! 787: case OPC_MSUBU: ! 788: gen_op_msubu(); ! 789: opn = "msubu"; ! 790: break; ! 791: default: ! 792: MIPS_INVAL("mul/div"); ! 793: generate_exception(ctx, EXCP_RI); ! 794: return; ! 795: } ! 796: MIPS_DEBUG("%s %s %s", opn, regnames[rs], regnames[rt]); ! 797: } ! 798: ! 799: static void gen_cl (DisasContext *ctx, uint16_t opc, ! 800: int rd, int rs) ! 801: { ! 802: const unsigned char *opn = "unk"; ! 803: if (rd == 0) { ! 804: /* Treat as a NOP */ ! 805: MIPS_DEBUG("NOP"); ! 806: return; ! 807: } ! 808: GEN_LOAD_REG_TN(T0, rs); ! 809: switch (opc) { ! 810: case OPC_CLO: ! 811: /* CLO */ ! 812: gen_op_clo(); ! 813: opn = "clo"; ! 814: break; ! 815: case OPC_CLZ: ! 816: /* CLZ */ ! 817: gen_op_clz(); ! 818: opn = "clz"; ! 819: break; ! 820: default: ! 821: MIPS_INVAL("CLx"); ! 822: generate_exception(ctx, EXCP_RI); ! 823: return; ! 824: } ! 825: gen_op_store_T0_gpr(rd); ! 826: MIPS_DEBUG("%s %s, %s", opn, regnames[rd], regnames[rs]); ! 827: } ! 828: ! 829: /* Traps */ ! 830: static void gen_trap (DisasContext *ctx, uint16_t opc, ! 831: int rs, int rt, int16_t imm) ! 832: { ! 833: int cond; ! 834: ! 835: cond = 0; ! 836: /* Load needed operands */ ! 837: switch (opc) { ! 838: case OPC_TEQ: ! 839: case OPC_TGE: ! 840: case OPC_TGEU: ! 841: case OPC_TLT: ! 842: case OPC_TLTU: ! 843: case OPC_TNE: ! 844: /* Compare two registers */ ! 845: if (rs != rt) { ! 846: GEN_LOAD_REG_TN(T0, rs); ! 847: GEN_LOAD_REG_TN(T1, rt); ! 848: cond = 1; ! 849: } ! 850: case OPC_TEQI: ! 851: case OPC_TGEI: ! 852: case OPC_TGEIU: ! 853: case OPC_TLTI: ! 854: case OPC_TLTIU: ! 855: case OPC_TNEI: ! 856: /* Compare register to immediate */ ! 857: if (rs != 0 || imm != 0) { ! 858: GEN_LOAD_REG_TN(T0, rs); ! 859: GEN_LOAD_IMM_TN(T1, (int32_t)imm); ! 860: cond = 1; ! 861: } ! 862: break; ! 863: } ! 864: if (cond == 0) { ! 865: switch (opc) { ! 866: case OPC_TEQ: /* rs == rs */ ! 867: case OPC_TEQI: /* r0 == 0 */ ! 868: case OPC_TGE: /* rs >= rs */ ! 869: case OPC_TGEI: /* r0 >= 0 */ ! 870: case OPC_TGEU: /* rs >= rs unsigned */ ! 871: case OPC_TGEIU: /* r0 >= 0 unsigned */ ! 872: /* Always trap */ ! 873: gen_op_set_T0(1); ! 874: break; ! 875: case OPC_TLT: /* rs < rs */ ! 876: case OPC_TLTI: /* r0 < 0 */ ! 877: case OPC_TLTU: /* rs < rs unsigned */ ! 878: case OPC_TLTIU: /* r0 < 0 unsigned */ ! 879: case OPC_TNE: /* rs != rs */ ! 880: case OPC_TNEI: /* r0 != 0 */ ! 881: /* Never trap: treat as NOP */ ! 882: return; ! 883: default: ! 884: MIPS_INVAL("TRAP"); ! 885: generate_exception(ctx, EXCP_RI); ! 886: return; ! 887: } ! 888: } else { ! 889: switch (opc) { ! 890: case OPC_TEQ: ! 891: case OPC_TEQI: ! 892: gen_op_eq(); ! 893: break; ! 894: case OPC_TGE: ! 895: case OPC_TGEI: ! 896: gen_op_ge(); ! 897: break; ! 898: case OPC_TGEU: ! 899: case OPC_TGEIU: ! 900: gen_op_geu(); ! 901: break; ! 902: case OPC_TLT: ! 903: case OPC_TLTI: ! 904: gen_op_lt(); ! 905: break; ! 906: case OPC_TLTU: ! 907: case OPC_TLTIU: ! 908: gen_op_ltu(); ! 909: break; ! 910: case OPC_TNE: ! 911: case OPC_TNEI: ! 912: gen_op_ne(); ! 913: break; ! 914: default: ! 915: MIPS_INVAL("TRAP"); ! 916: generate_exception(ctx, EXCP_RI); ! 917: return; ! 918: } ! 919: } ! 920: save_cpu_state(ctx, 1); ! 921: gen_op_trap(); ! 922: ctx->bstate = BS_STOP; ! 923: } ! 924: ! 925: /* Branches (before delay slot) */ ! 926: static void gen_compute_branch (DisasContext *ctx, uint16_t opc, ! 927: int rs, int rt, int32_t offset) ! 928: { ! 929: target_ulong btarget; ! 930: int blink, bcond; ! 931: ! 932: btarget = -1; ! 933: blink = 0; ! 934: bcond = 0; ! 935: /* Load needed operands */ ! 936: switch (opc) { ! 937: case OPC_BEQ: ! 938: case OPC_BEQL: ! 939: case OPC_BNE: ! 940: case OPC_BNEL: ! 941: /* Compare two registers */ ! 942: if (rs != rt) { ! 943: GEN_LOAD_REG_TN(T0, rs); ! 944: GEN_LOAD_REG_TN(T1, rt); ! 945: bcond = 1; ! 946: } ! 947: btarget = ctx->pc + 4 + offset; ! 948: break; ! 949: case OPC_BGEZ: ! 950: case OPC_BGEZAL: ! 951: case OPC_BGEZALL: ! 952: case OPC_BGEZL: ! 953: case OPC_BGTZ: ! 954: case OPC_BGTZL: ! 955: case OPC_BLEZ: ! 956: case OPC_BLEZL: ! 957: case OPC_BLTZ: ! 958: case OPC_BLTZAL: ! 959: case OPC_BLTZALL: ! 960: case OPC_BLTZL: ! 961: /* Compare to zero */ ! 962: if (rs != 0) { ! 963: gen_op_load_gpr_T0(rs); ! 964: bcond = 1; ! 965: } ! 966: btarget = ctx->pc + 4 + offset; ! 967: break; ! 968: case OPC_J: ! 969: case OPC_JAL: ! 970: /* Jump to immediate */ ! 971: btarget = ((ctx->pc + 4) & 0xF0000000) | offset; ! 972: break; ! 973: case OPC_JR: ! 974: case OPC_JALR: ! 975: /* Jump to register */ ! 976: if (offset != 0) { ! 977: /* Only hint = 0 is valid */ ! 978: generate_exception(ctx, EXCP_RI); ! 979: return; ! 980: } ! 981: GEN_LOAD_REG_TN(T2, rs); ! 982: break; ! 983: default: ! 984: MIPS_INVAL("branch/jump"); ! 985: generate_exception(ctx, EXCP_RI); ! 986: return; ! 987: } ! 988: if (bcond == 0) { ! 989: /* No condition to be computed */ ! 990: switch (opc) { ! 991: case OPC_BEQ: /* rx == rx */ ! 992: case OPC_BEQL: /* rx == rx likely */ ! 993: case OPC_BGEZ: /* 0 >= 0 */ ! 994: case OPC_BGEZL: /* 0 >= 0 likely */ ! 995: case OPC_BLEZ: /* 0 <= 0 */ ! 996: case OPC_BLEZL: /* 0 <= 0 likely */ ! 997: /* Always take */ ! 998: ctx->hflags |= MIPS_HFLAG_DS | MIPS_HFLAG_B; ! 999: MIPS_DEBUG("balways"); ! 1000: break; ! 1001: case OPC_BGEZAL: /* 0 >= 0 */ ! 1002: case OPC_BGEZALL: /* 0 >= 0 likely */ ! 1003: /* Always take and link */ ! 1004: blink = 31; ! 1005: ctx->hflags |= MIPS_HFLAG_DS | MIPS_HFLAG_B; ! 1006: MIPS_DEBUG("balways and link"); ! 1007: break; ! 1008: case OPC_BNE: /* rx != rx */ ! 1009: case OPC_BGTZ: /* 0 > 0 */ ! 1010: case OPC_BLTZ: /* 0 < 0 */ ! 1011: case OPC_BLTZAL: /* 0 < 0 */ ! 1012: /* Treated as NOP */ ! 1013: MIPS_DEBUG("bnever (NOP)"); ! 1014: return; ! 1015: case OPC_BNEL: /* rx != rx likely */ ! 1016: case OPC_BGTZL: /* 0 > 0 likely */ ! 1017: case OPC_BLTZALL: /* 0 < 0 likely */ ! 1018: case OPC_BLTZL: /* 0 < 0 likely */ ! 1019: /* Skip the instruction in the delay slot */ ! 1020: MIPS_DEBUG("bnever and skip"); ! 1021: gen_op_branch((long)ctx->tb, ctx->pc + 4); ! 1022: return; ! 1023: case OPC_J: ! 1024: ctx->hflags |= MIPS_HFLAG_DS | MIPS_HFLAG_B; ! 1025: MIPS_DEBUG("j %08x", btarget); ! 1026: break; ! 1027: case OPC_JAL: ! 1028: blink = 31; ! 1029: ctx->hflags |= MIPS_HFLAG_DS | MIPS_HFLAG_B; ! 1030: MIPS_DEBUG("jal %08x", btarget); ! 1031: break; ! 1032: case OPC_JR: ! 1033: ctx->hflags |= MIPS_HFLAG_DS | MIPS_HFLAG_BR; ! 1034: MIPS_DEBUG("jr %s", regnames[rs]); ! 1035: break; ! 1036: case OPC_JALR: ! 1037: blink = rt; ! 1038: ctx->hflags |= MIPS_HFLAG_DS | MIPS_HFLAG_BR; ! 1039: MIPS_DEBUG("jalr %s, %s", regnames[rt], regnames[rs]); ! 1040: break; ! 1041: default: ! 1042: MIPS_INVAL("branch/jump"); ! 1043: generate_exception(ctx, EXCP_RI); ! 1044: return; ! 1045: } ! 1046: } else { ! 1047: switch (opc) { ! 1048: case OPC_BEQ: ! 1049: gen_op_eq(); ! 1050: MIPS_DEBUG("beq %s, %s, %08x", ! 1051: regnames[rs], regnames[rt], btarget); ! 1052: goto not_likely; ! 1053: case OPC_BEQL: ! 1054: gen_op_eq(); ! 1055: MIPS_DEBUG("beql %s, %s, %08x", ! 1056: regnames[rs], regnames[rt], btarget); ! 1057: goto likely; ! 1058: case OPC_BNE: ! 1059: gen_op_ne(); ! 1060: MIPS_DEBUG("bne %s, %s, %08x", ! 1061: regnames[rs], regnames[rt], btarget); ! 1062: goto not_likely; ! 1063: case OPC_BNEL: ! 1064: gen_op_ne(); ! 1065: MIPS_DEBUG("bnel %s, %s, %08x", ! 1066: regnames[rs], regnames[rt], btarget); ! 1067: goto likely; ! 1068: case OPC_BGEZ: ! 1069: gen_op_gez(); ! 1070: MIPS_DEBUG("bgez %s, %08x", regnames[rs], btarget); ! 1071: goto not_likely; ! 1072: case OPC_BGEZL: ! 1073: gen_op_gez(); ! 1074: MIPS_DEBUG("bgezl %s, %08x", regnames[rs], btarget); ! 1075: goto likely; ! 1076: case OPC_BGEZAL: ! 1077: gen_op_gez(); ! 1078: MIPS_DEBUG("bgezal %s, %08x", regnames[rs], btarget); ! 1079: blink = 31; ! 1080: goto not_likely; ! 1081: case OPC_BGEZALL: ! 1082: gen_op_gez(); ! 1083: blink = 31; ! 1084: MIPS_DEBUG("bgezall %s, %08x", regnames[rs], btarget); ! 1085: goto likely; ! 1086: case OPC_BGTZ: ! 1087: gen_op_gtz(); ! 1088: MIPS_DEBUG("bgtz %s, %08x", regnames[rs], btarget); ! 1089: goto not_likely; ! 1090: case OPC_BGTZL: ! 1091: gen_op_gtz(); ! 1092: MIPS_DEBUG("bgtzl %s, %08x", regnames[rs], btarget); ! 1093: goto likely; ! 1094: case OPC_BLEZ: ! 1095: gen_op_lez(); ! 1096: MIPS_DEBUG("blez %s, %08x", regnames[rs], btarget); ! 1097: goto not_likely; ! 1098: case OPC_BLEZL: ! 1099: gen_op_lez(); ! 1100: MIPS_DEBUG("blezl %s, %08x", regnames[rs], btarget); ! 1101: goto likely; ! 1102: case OPC_BLTZ: ! 1103: gen_op_ltz(); ! 1104: MIPS_DEBUG("bltz %s, %08x", regnames[rs], btarget); ! 1105: goto not_likely; ! 1106: case OPC_BLTZL: ! 1107: gen_op_ltz(); ! 1108: MIPS_DEBUG("bltzl %s, %08x", regnames[rs], btarget); ! 1109: goto likely; ! 1110: case OPC_BLTZAL: ! 1111: gen_op_ltz(); ! 1112: blink = 31; ! 1113: MIPS_DEBUG("bltzal %s, %08x", regnames[rs], btarget); ! 1114: not_likely: ! 1115: ctx->hflags |= MIPS_HFLAG_DS | MIPS_HFLAG_BC; ! 1116: break; ! 1117: case OPC_BLTZALL: ! 1118: gen_op_ltz(); ! 1119: blink = 31; ! 1120: MIPS_DEBUG("bltzall %s, %08x", regnames[rs], btarget); ! 1121: likely: ! 1122: ctx->hflags |= MIPS_HFLAG_DS | MIPS_HFLAG_BL; ! 1123: break; ! 1124: } ! 1125: gen_op_set_bcond(); ! 1126: } ! 1127: MIPS_DEBUG("enter ds: link %d cond %02x target %08x", ! 1128: blink, ctx->hflags, btarget); ! 1129: ctx->btarget = btarget; ! 1130: if (blink > 0) { ! 1131: gen_op_set_T0(ctx->pc + 8); ! 1132: gen_op_store_T0_gpr(blink); ! 1133: } ! 1134: return; ! 1135: } ! 1136: ! 1137: /* CP0 (MMU and control) */ ! 1138: static void gen_cp0 (DisasContext *ctx, uint16_t opc, int rt, int rd) ! 1139: { ! 1140: const unsigned char *opn = "unk"; ! 1141: ! 1142: if (!(ctx->CP0_Status & (1 << CP0St_CU0)) && ! 1143: !(ctx->hflags & MIPS_HFLAG_UM) && ! 1144: !(ctx->hflags & MIPS_HFLAG_ERL) && ! 1145: !(ctx->hflags & MIPS_HFLAG_EXL)) { ! 1146: if (loglevel & CPU_LOG_TB_IN_ASM) { ! 1147: fprintf(logfile, "CP0 is not usable\n"); ! 1148: } ! 1149: gen_op_raise_exception_err(EXCP_CpU, 0); ! 1150: return; ! 1151: } ! 1152: switch (opc) { ! 1153: case OPC_MFC0: ! 1154: if (rt == 0) { ! 1155: /* Treat as NOP */ ! 1156: return; ! 1157: } ! 1158: gen_op_mfc0(rd, ctx->opcode & 0x7); ! 1159: gen_op_store_T0_gpr(rt); ! 1160: opn = "mfc0"; ! 1161: break; ! 1162: case OPC_MTC0: ! 1163: /* If we get an exception, we want to restart at next instruction */ ! 1164: ctx->pc += 4; ! 1165: save_cpu_state(ctx, 1); ! 1166: ctx->pc -= 4; ! 1167: GEN_LOAD_REG_TN(T0, rt); ! 1168: gen_op_mtc0(rd, ctx->opcode & 0x7); ! 1169: /* Stop translation as we may have switched the execution mode */ ! 1170: ctx->bstate = BS_STOP; ! 1171: opn = "mtc0"; ! 1172: break; ! 1173: #if defined(MIPS_USES_R4K_TLB) ! 1174: case OPC_TLBWI: ! 1175: gen_op_tlbwi(); ! 1176: opn = "tlbwi"; ! 1177: break; ! 1178: case OPC_TLBWR: ! 1179: gen_op_tlbwr(); ! 1180: opn = "tlbwr"; ! 1181: break; ! 1182: case OPC_TLBP: ! 1183: gen_op_tlbp(); ! 1184: opn = "tlbp"; ! 1185: break; ! 1186: case OPC_TLBR: ! 1187: gen_op_tlbr(); ! 1188: opn = "tlbr"; ! 1189: break; ! 1190: #endif ! 1191: case OPC_ERET: ! 1192: opn = "eret"; ! 1193: save_cpu_state(ctx, 0); ! 1194: gen_op_eret(); ! 1195: ctx->bstate = BS_EXCP; ! 1196: break; ! 1197: case OPC_DERET: ! 1198: opn = "deret"; ! 1199: if (!(ctx->hflags & MIPS_HFLAG_DM)) { ! 1200: generate_exception(ctx, EXCP_RI); ! 1201: } else { ! 1202: save_cpu_state(ctx, 0); ! 1203: gen_op_deret(); ! 1204: ctx->bstate = BS_EXCP; ! 1205: } ! 1206: break; ! 1207: /* XXX: TODO: WAIT */ ! 1208: default: ! 1209: if (loglevel & CPU_LOG_TB_IN_ASM) { ! 1210: fprintf(logfile, "Invalid CP0 opcode: %08x %03x %03x %03x\n", ! 1211: ctx->opcode, ctx->opcode >> 26, ctx->opcode & 0x3F, ! 1212: ((ctx->opcode >> 16) & 0x1F)); ! 1213: } ! 1214: generate_exception(ctx, EXCP_RI); ! 1215: return; ! 1216: } ! 1217: MIPS_DEBUG("%s %s %d", opn, regnames[rt], rd); ! 1218: } ! 1219: ! 1220: /* Coprocessor 1 (FPU) */ ! 1221: ! 1222: /* ISA extensions */ ! 1223: /* MIPS16 extension to MIPS32 */ ! 1224: /* SmartMIPS extension to MIPS32 */ ! 1225: ! 1226: #ifdef TARGET_MIPS64 ! 1227: static void gen_arith64 (DisasContext *ctx, uint16_t opc) ! 1228: { ! 1229: if (func == 0x02 && rd == 0) { ! 1230: /* NOP */ ! 1231: return; ! 1232: } ! 1233: if (rs == 0 || rt == 0) { ! 1234: gen_op_reset_T0(); ! 1235: gen_op_save64(); ! 1236: } else { ! 1237: gen_op_load_gpr_T0(rs); ! 1238: gen_op_load_gpr_T1(rt); ! 1239: gen_op_save64(); ! 1240: if (func & 0x01) ! 1241: gen_op_mul64u(); ! 1242: else ! 1243: gen_op_mul64s(); ! 1244: } ! 1245: if (func & 0x02) ! 1246: gen_op_add64(); ! 1247: else ! 1248: gen_op_sub64(); ! 1249: } ! 1250: ! 1251: /* Coprocessor 3 (FPU) */ ! 1252: ! 1253: /* MDMX extension to MIPS64 */ ! 1254: /* MIPS-3D extension to MIPS64 */ ! 1255: ! 1256: #endif ! 1257: ! 1258: static void decode_opc (DisasContext *ctx) ! 1259: { ! 1260: int32_t offset; ! 1261: int rs, rt, rd, sa; ! 1262: uint16_t op, op1; ! 1263: int16_t imm; ! 1264: ! 1265: if ((ctx->hflags & MIPS_HFLAG_DS) && ! 1266: (ctx->hflags & MIPS_HFLAG_BL)) { ! 1267: /* Handle blikely not taken case */ ! 1268: MIPS_DEBUG("blikely condition (%08x)", ctx->pc + 4); ! 1269: gen_op_blikely((long)ctx->tb, ctx->pc + 4, ! 1270: ctx->hflags & ~(MIPS_HFLAG_BMASK | MIPS_HFLAG_DS)); ! 1271: } ! 1272: op = ctx->opcode >> 26; ! 1273: rs = ((ctx->opcode >> 21) & 0x1F); ! 1274: rt = ((ctx->opcode >> 16) & 0x1F); ! 1275: rd = ((ctx->opcode >> 11) & 0x1F); ! 1276: sa = ((ctx->opcode >> 6) & 0x1F); ! 1277: imm = (int16_t)ctx->opcode; ! 1278: switch (op) { ! 1279: case 0x00: /* Special opcode */ ! 1280: op1 = ctx->opcode & 0x3F; ! 1281: switch (op1) { ! 1282: case 0x00: /* Arithmetic with immediate */ ! 1283: case 0x02 ... 0x03: ! 1284: gen_arith_imm(ctx, op1 | EXT_SPECIAL, rd, rt, sa); ! 1285: break; ! 1286: case 0x04: /* Arithmetic */ ! 1287: case 0x06 ... 0x07: ! 1288: case 0x0A ... 0x0B: ! 1289: case 0x20 ... 0x27: ! 1290: case 0x2A ... 0x2B: ! 1291: gen_arith(ctx, op1 | EXT_SPECIAL, rd, rs, rt); ! 1292: break; ! 1293: case 0x18 ... 0x1B: /* MULT / DIV */ ! 1294: gen_muldiv(ctx, op1 | EXT_SPECIAL, rs, rt); ! 1295: break; ! 1296: case 0x08 ... 0x09: /* Jumps */ ! 1297: gen_compute_branch(ctx, op1 | EXT_SPECIAL, rs, rd, sa); ! 1298: return; ! 1299: case 0x30 ... 0x34: /* Traps */ ! 1300: case 0x36: ! 1301: gen_trap(ctx, op1 | EXT_SPECIAL, rs, rt, -1); ! 1302: break; ! 1303: case 0x10: /* Move from HI/LO */ ! 1304: case 0x12: ! 1305: gen_HILO(ctx, op1 | EXT_SPECIAL, rd); ! 1306: break; ! 1307: case 0x11: ! 1308: case 0x13: /* Move to HI/LO */ ! 1309: gen_HILO(ctx, op1 | EXT_SPECIAL, rs); ! 1310: break; ! 1311: case 0x0C: /* SYSCALL */ ! 1312: generate_exception(ctx, EXCP_SYSCALL); ! 1313: break; ! 1314: case 0x0D: /* BREAK */ ! 1315: generate_exception(ctx, EXCP_BREAK); ! 1316: break; ! 1317: case 0x0F: /* SYNC */ ! 1318: /* Treat as a noop */ ! 1319: break; ! 1320: case 0x05: /* Pmon entry point */ ! 1321: gen_op_pmon((ctx->opcode >> 6) & 0x1F); ! 1322: break; ! 1323: #if defined (MIPS_HAS_MOVCI) ! 1324: case 0x01: /* MOVCI */ ! 1325: #endif ! 1326: #if defined (TARGET_MIPS64) ! 1327: case 0x14: /* MIPS64 specific opcodes */ ! 1328: case 0x16: ! 1329: case 0x17: ! 1330: case 0x1C ... 0x1F: ! 1331: case 0x2C ... 0x2F: ! 1332: case 0x37: ! 1333: case 0x39 ... 0x3B: ! 1334: case 0x3E ... 0x3F: ! 1335: #endif ! 1336: default: /* Invalid */ ! 1337: MIPS_INVAL("special"); ! 1338: generate_exception(ctx, EXCP_RI); ! 1339: break; ! 1340: } ! 1341: break; ! 1342: case 0x1C: /* Special2 opcode */ ! 1343: op1 = ctx->opcode & 0x3F; ! 1344: switch (op1) { ! 1345: #if defined (MIPS_USES_R4K_EXT) ! 1346: /* Those instructions are not part of MIPS32 core */ ! 1347: case 0x00 ... 0x01: /* Multiply and add/sub */ ! 1348: case 0x04 ... 0x05: ! 1349: gen_muldiv(ctx, op1 | EXT_SPECIAL2, rs, rt); ! 1350: break; ! 1351: case 0x02: /* MUL */ ! 1352: gen_arith(ctx, op1 | EXT_SPECIAL2, rd, rs, rt); ! 1353: break; ! 1354: case 0x20 ... 0x21: /* CLO / CLZ */ ! 1355: gen_cl(ctx, op1 | EXT_SPECIAL2, rd, rs); ! 1356: break; ! 1357: #endif ! 1358: case 0x3F: /* SDBBP */ ! 1359: /* XXX: not clear which exception should be raised ! 1360: * when in debug mode... ! 1361: */ ! 1362: if (!(ctx->hflags & MIPS_HFLAG_DM)) { ! 1363: generate_exception(ctx, EXCP_DBp); ! 1364: } else { ! 1365: generate_exception(ctx, EXCP_DBp); ! 1366: } ! 1367: /* Treat as a noop */ ! 1368: break; ! 1369: default: /* Invalid */ ! 1370: MIPS_INVAL("special2"); ! 1371: generate_exception(ctx, EXCP_RI); ! 1372: break; ! 1373: } ! 1374: break; ! 1375: case 0x01: /* B REGIMM opcode */ ! 1376: op1 = ((ctx->opcode >> 16) & 0x1F); ! 1377: switch (op1) { ! 1378: case 0x00 ... 0x03: /* REGIMM branches */ ! 1379: case 0x10 ... 0x13: ! 1380: gen_compute_branch(ctx, op1 | EXT_REGIMM, rs, -1, imm << 2); ! 1381: return; ! 1382: case 0x08 ... 0x0C: /* Traps */ ! 1383: case 0x0E: ! 1384: gen_trap(ctx, op1 | EXT_REGIMM, rs, -1, imm); ! 1385: break; ! 1386: default: /* Invalid */ ! 1387: MIPS_INVAL("REGIMM"); ! 1388: generate_exception(ctx, EXCP_RI); ! 1389: break; ! 1390: } ! 1391: break; ! 1392: case 0x10: /* CP0 opcode */ ! 1393: op1 = ((ctx->opcode >> 21) & 0x1F); ! 1394: switch (op1) { ! 1395: case 0x00: ! 1396: case 0x04: ! 1397: gen_cp0(ctx, op1 | EXT_CP0, rt, rd); ! 1398: break; ! 1399: default: ! 1400: gen_cp0(ctx, (ctx->opcode & 0x1F) | EXT_CP0, rt, rd); ! 1401: break; ! 1402: } ! 1403: break; ! 1404: case 0x08 ... 0x0F: /* Arithmetic with immediate opcode */ ! 1405: gen_arith_imm(ctx, op, rt, rs, imm); ! 1406: break; ! 1407: case 0x02 ... 0x03: /* Jump */ ! 1408: offset = (int32_t)(ctx->opcode & 0x03FFFFFF) << 2; ! 1409: gen_compute_branch(ctx, op, rs, rt, offset); ! 1410: return; ! 1411: case 0x04 ... 0x07: /* Branch */ ! 1412: case 0x14 ... 0x17: ! 1413: gen_compute_branch(ctx, op, rs, rt, imm << 2); ! 1414: return; ! 1415: case 0x20 ... 0x26: /* Load and stores */ ! 1416: case 0x28 ... 0x2E: ! 1417: case 0x30: ! 1418: case 0x38: ! 1419: gen_ldst(ctx, op, rt, rs, imm); ! 1420: break; ! 1421: case 0x2F: /* Cache operation */ ! 1422: /* Treat as a noop */ ! 1423: break; ! 1424: case 0x33: /* Prefetch */ ! 1425: /* Treat as a noop */ ! 1426: break; ! 1427: case 0x3F: /* HACK */ ! 1428: break; ! 1429: #if defined(MIPS_USES_FPU) ! 1430: case 0x31 ... 0x32: /* Floating point load/store */ ! 1431: case 0x35 ... 0x36: ! 1432: case 0x3A ... 0x3B: ! 1433: case 0x3D ... 0x3E: ! 1434: /* Not implemented */ ! 1435: /* XXX: not correct */ ! 1436: #endif ! 1437: case 0x11: /* CP1 opcode */ ! 1438: /* Not implemented */ ! 1439: /* XXX: not correct */ ! 1440: case 0x12: /* CP2 opcode */ ! 1441: /* Not implemented */ ! 1442: /* XXX: not correct */ ! 1443: case 0x13: /* CP3 opcode */ ! 1444: /* Not implemented */ ! 1445: /* XXX: not correct */ ! 1446: #if defined (TARGET_MIPS64) ! 1447: case 0x18 ... 0x1B: ! 1448: case 0x27: ! 1449: case 0x34: ! 1450: case 0x37: ! 1451: /* MIPS64 opcodes */ ! 1452: #endif ! 1453: #if defined (MIPS_HAS_JALX) ! 1454: case 0x1D: ! 1455: /* JALX: not implemented */ ! 1456: #endif ! 1457: case 0x1E: ! 1458: /* ASE specific */ ! 1459: #if defined (MIPS_HAS_LSC) ! 1460: case 0x31: /* LWC1 */ ! 1461: case 0x32: /* LWC2 */ ! 1462: case 0x35: /* SDC1 */ ! 1463: case 0x36: /* SDC2 */ ! 1464: #endif ! 1465: default: /* Invalid */ ! 1466: MIPS_INVAL(""); ! 1467: generate_exception(ctx, EXCP_RI); ! 1468: break; ! 1469: } ! 1470: if (ctx->hflags & MIPS_HFLAG_DS) { ! 1471: int hflags = ctx->hflags; ! 1472: /* Branches completion */ ! 1473: ctx->hflags &= ~(MIPS_HFLAG_BMASK | MIPS_HFLAG_DS); ! 1474: ctx->bstate = BS_BRANCH; ! 1475: save_cpu_state(ctx, 0); ! 1476: switch (hflags & MIPS_HFLAG_BMASK) { ! 1477: case MIPS_HFLAG_B: ! 1478: /* unconditional branch */ ! 1479: MIPS_DEBUG("unconditional branch"); ! 1480: gen_op_branch((long)ctx->tb, ctx->btarget); ! 1481: break; ! 1482: case MIPS_HFLAG_BL: ! 1483: /* blikely taken case */ ! 1484: MIPS_DEBUG("blikely branch taken"); ! 1485: gen_op_branch((long)ctx->tb, ctx->btarget); ! 1486: break; ! 1487: case MIPS_HFLAG_BC: ! 1488: /* Conditional branch */ ! 1489: MIPS_DEBUG("conditional branch"); ! 1490: gen_op_bcond((long)ctx->tb, ctx->btarget, ctx->pc + 4); ! 1491: break; ! 1492: case MIPS_HFLAG_BR: ! 1493: /* unconditional branch to register */ ! 1494: MIPS_DEBUG("branch to register"); ! 1495: gen_op_breg(); ! 1496: break; ! 1497: default: ! 1498: MIPS_DEBUG("unknown branch"); ! 1499: break; ! 1500: } ! 1501: } ! 1502: } ! 1503: ! 1504: int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, ! 1505: int search_pc) ! 1506: { ! 1507: DisasContext ctx, *ctxp = &ctx; ! 1508: target_ulong pc_start; ! 1509: uint16_t *gen_opc_end; ! 1510: int j, lj = -1; ! 1511: ! 1512: pc_start = tb->pc; ! 1513: gen_opc_ptr = gen_opc_buf; ! 1514: gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; ! 1515: gen_opparam_ptr = gen_opparam_buf; ! 1516: ctx.pc = pc_start; ! 1517: ctx.tb = tb; ! 1518: ctx.bstate = BS_NONE; ! 1519: /* Restore delay slot state */ ! 1520: ctx.hflags = env->hflags; ! 1521: ctx.saved_hflags = ctx.hflags; ! 1522: if (ctx.hflags & MIPS_HFLAG_BR) { ! 1523: gen_op_restore_breg_target(); ! 1524: } else if (ctx.hflags & MIPS_HFLAG_B) { ! 1525: ctx.btarget = env->btarget; ! 1526: } else if (ctx.hflags & MIPS_HFLAG_BMASK) { ! 1527: /* If we are in the delay slot of a conditional branch, ! 1528: * restore the branch condition from env->bcond to T2 ! 1529: */ ! 1530: ctx.btarget = env->btarget; ! 1531: gen_op_restore_bcond(); ! 1532: } ! 1533: #if defined(CONFIG_USER_ONLY) ! 1534: ctx.mem_idx = 0; ! 1535: #else ! 1536: ctx.mem_idx = (ctx.hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM ? 0 : 1; ! 1537: #endif ! 1538: ctx.CP0_Status = env->CP0_Status; ! 1539: #ifdef DEBUG_DISAS ! 1540: if (loglevel & CPU_LOG_TB_CPU) { ! 1541: fprintf(logfile, "------------------------------------------------\n"); ! 1542: cpu_dump_state(env, logfile, fprintf, 0); ! 1543: } ! 1544: #endif ! 1545: #if defined MIPS_DEBUG_DISAS ! 1546: if (loglevel & CPU_LOG_TB_IN_ASM) ! 1547: fprintf(logfile, "\ntb %p super %d cond %04x %04x\n", ! 1548: tb, ctx.mem_idx, ctx.hflags, env->hflags); ! 1549: #endif ! 1550: while (ctx.bstate == BS_NONE && gen_opc_ptr < gen_opc_end) { ! 1551: if (search_pc) { ! 1552: j = gen_opc_ptr - gen_opc_buf; ! 1553: save_cpu_state(ctxp, 1); ! 1554: if (lj < j) { ! 1555: lj++; ! 1556: while (lj < j) ! 1557: gen_opc_instr_start[lj++] = 0; ! 1558: gen_opc_pc[lj] = ctx.pc; ! 1559: gen_opc_instr_start[lj] = 1; ! 1560: } ! 1561: } ! 1562: ctx.opcode = ldl_code(ctx.pc); ! 1563: decode_opc(&ctx); ! 1564: ctx.pc += 4; ! 1565: if ((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0) ! 1566: break; ! 1567: #if defined (MIPS_SINGLE_STEP) ! 1568: break; ! 1569: #endif ! 1570: } ! 1571: if (ctx.bstate != BS_BRANCH && ctx.bstate != BS_EXCP) { ! 1572: save_cpu_state(ctxp, 0); ! 1573: gen_op_branch((long)ctx.tb, ctx.pc); ! 1574: } ! 1575: gen_op_reset_T0(); ! 1576: /* Generate the return instruction */ ! 1577: gen_op_exit_tb(); ! 1578: *gen_opc_ptr = INDEX_op_end; ! 1579: if (search_pc) { ! 1580: j = gen_opc_ptr - gen_opc_buf; ! 1581: lj++; ! 1582: while (lj <= j) ! 1583: gen_opc_instr_start[lj++] = 0; ! 1584: tb->size = 0; ! 1585: } else { ! 1586: tb->size = ctx.pc - pc_start; ! 1587: } ! 1588: #ifdef DEBUG_DISAS ! 1589: #if defined MIPS_DEBUG_DISAS ! 1590: if (loglevel & CPU_LOG_TB_IN_ASM) ! 1591: fprintf(logfile, "\n"); ! 1592: #endif ! 1593: if (loglevel & CPU_LOG_TB_IN_ASM) { ! 1594: fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start)); ! 1595: target_disas(logfile, pc_start, ctx.pc - pc_start, 0); ! 1596: fprintf(logfile, "\n"); ! 1597: } ! 1598: if (loglevel & CPU_LOG_TB_OP) { ! 1599: fprintf(logfile, "OP:\n"); ! 1600: dump_ops(gen_opc_buf, gen_opparam_buf); ! 1601: fprintf(logfile, "\n"); ! 1602: } ! 1603: if (loglevel & CPU_LOG_TB_CPU) { ! 1604: fprintf(logfile, "---------------- %d %08x\n", ctx.bstate, ctx.hflags); ! 1605: } ! 1606: #endif ! 1607: ! 1608: return 0; ! 1609: } ! 1610: ! 1611: int gen_intermediate_code (CPUState *env, struct TranslationBlock *tb) ! 1612: { ! 1613: return gen_intermediate_code_internal(env, tb, 0); ! 1614: } ! 1615: ! 1616: int gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb) ! 1617: { ! 1618: return gen_intermediate_code_internal(env, tb, 1); ! 1619: } ! 1620: ! 1621: void cpu_dump_state (CPUState *env, FILE *f, ! 1622: int (*cpu_fprintf)(FILE *f, const char *fmt, ...), ! 1623: int flags) ! 1624: { ! 1625: uint32_t c0_status; ! 1626: int i; ! 1627: ! 1628: cpu_fprintf(f, "pc=0x%08x HI=0x%08x LO=0x%08x ds %04x %08x %d\n", ! 1629: env->PC, env->HI, env->LO, env->hflags, env->btarget, env->bcond); ! 1630: for (i = 0; i < 32; i++) { ! 1631: if ((i & 3) == 0) ! 1632: cpu_fprintf(f, "GPR%02d:", i); ! 1633: cpu_fprintf(f, " %s %08x", regnames[i], env->gpr[i]); ! 1634: if ((i & 3) == 3) ! 1635: cpu_fprintf(f, "\n"); ! 1636: } ! 1637: ! 1638: c0_status = env->CP0_Status; ! 1639: if (env->hflags & MIPS_HFLAG_UM) ! 1640: c0_status |= (1 << CP0St_UM); ! 1641: if (env->hflags & MIPS_HFLAG_ERL) ! 1642: c0_status |= (1 << CP0St_ERL); ! 1643: if (env->hflags & MIPS_HFLAG_EXL) ! 1644: c0_status |= (1 << CP0St_EXL); ! 1645: ! 1646: cpu_fprintf(f, "CP0 Status 0x%08x Cause 0x%08x EPC 0x%08x\n", ! 1647: c0_status, env->CP0_Cause, env->CP0_EPC); ! 1648: cpu_fprintf(f, " Config0 0x%08x Config1 0x%08x LLAddr 0x%08x\n", ! 1649: env->CP0_Config0, env->CP0_Config1, env->CP0_LLAddr); ! 1650: } ! 1651: ! 1652: CPUMIPSState *cpu_mips_init (void) ! 1653: { ! 1654: CPUMIPSState *env; ! 1655: ! 1656: cpu_exec_init(); ! 1657: env = qemu_mallocz(sizeof(CPUMIPSState)); ! 1658: if (!env) ! 1659: return NULL; ! 1660: tlb_flush(env, 1); ! 1661: /* Minimal init */ ! 1662: env->PC = 0xBFC00000; ! 1663: #if defined (MIPS_USES_R4K_TLB) ! 1664: env->CP0_random = MIPS_TLB_NB - 1; ! 1665: #endif ! 1666: env->CP0_Wired = 0; ! 1667: env->CP0_Config0 = MIPS_CONFIG0; ! 1668: #if defined (MIPS_CONFIG1) ! 1669: env->CP0_Config1 = MIPS_CONFIG1; ! 1670: #endif ! 1671: #if defined (MIPS_CONFIG2) ! 1672: env->CP0_Config2 = MIPS_CONFIG2; ! 1673: #endif ! 1674: #if defined (MIPS_CONFIG3) ! 1675: env->CP0_Config3 = MIPS_CONFIG3; ! 1676: #endif ! 1677: env->CP0_Status = (1 << CP0St_CU0) | (1 << CP0St_BEV); ! 1678: env->CP0_WatchLo = 0; ! 1679: env->hflags = MIPS_HFLAG_ERL; ! 1680: /* Count register increments in debug mode, EJTAG version 1 */ ! 1681: env->CP0_Debug = (1 << CP0DB_CNT) | (0x1 << CP0DB_VER); ! 1682: env->CP0_PRid = MIPS_CPU; ! 1683: env->exception_index = EXCP_NONE; ! 1684: ! 1685: cpu_single_env = env; ! 1686: ! 1687: return env; ! 1688: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.