#define MASK_CP1_FUNC(op) MASK_CP1(op) | (op & 0x3F)
#define MASK_CP2(op) MASK_OP_MAJOR(op) | (op & (0x1F << 21))
-#define MASK_CP3(op) MASK_OP_MAJOR(op) | (op & (0x1F << 21))
+
+enum {
+ OPC_MFC2 = (0x00 << 21) | OPC_CP2,
+ OPC_DMFC2 = (0x01 << 21) | OPC_CP2,
+ OPC_CFC2 = (0x02 << 21) | OPC_CP2,
+ OPC_MFHC2 = (0x03 << 21) | OPC_CP2,
+ OPC_MTC2 = (0x04 << 21) | OPC_CP2,
+ OPC_DMTC2 = (0x05 << 21) | OPC_CP2,
+ OPC_CTC2 = (0x06 << 21) | OPC_CP2,
+ OPC_MTHC2 = (0x07 << 21) | OPC_CP2,
+ OPC_BC2 = (0x08 << 21) | OPC_CP2,
+};
+
+#define MASK_CP3(op) MASK_OP_MAJOR(op) | (op & 0x3F)
+
+enum {
+ OPC_LWXC1 = 0x00 | OPC_CP3,
+ OPC_LDXC1 = 0x01 | OPC_CP3,
+ OPC_LUXC1 = 0x05 | OPC_CP3,
+ OPC_SWXC1 = 0x08 | OPC_CP3,
+ OPC_SDXC1 = 0x09 | OPC_CP3,
+ OPC_SUXC1 = 0x0D | OPC_CP3,
+ OPC_PREFX = 0x0F | OPC_CP3,
+ OPC_ALNV_PS = 0x1E | OPC_CP3,
+ OPC_MADD_S = 0x20 | OPC_CP3,
+ OPC_MADD_D = 0x21 | OPC_CP3,
+ OPC_MADD_PS = 0x26 | OPC_CP3,
+ OPC_MSUB_S = 0x28 | OPC_CP3,
+ OPC_MSUB_D = 0x29 | OPC_CP3,
+ OPC_MSUB_PS = 0x2E | OPC_CP3,
+ OPC_NMADD_S = 0x30 | OPC_CP3,
+ OPC_NMADD_D = 0x32 | OPC_CP3,
+ OPC_NMADD_PS= 0x36 | OPC_CP3,
+ OPC_NMSUB_S = 0x38 | OPC_CP3,
+ OPC_NMSUB_D = 0x39 | OPC_CP3,
+ OPC_NMSUB_PS= 0x3E | OPC_CP3,
+};
+
const unsigned char *regnames[] =
{ "r0", "at", "v0", "v1", "a0", "a1", "a2", "a3",
MIPS_DEBUG("NOP");
return;
}
- if (opc == OPC_ADDI || opc == OPC_ADDIU ||
- opc == OPC_DADDI || opc == OPC_DADDIU ||
- opc == OPC_SLTI || opc == OPC_SLTIU)
+ uimm = (uint16_t)imm;
+ switch (opc) {
+ case OPC_ADDI:
+ case OPC_ADDIU:
+#ifdef TARGET_MIPS64
+ case OPC_DADDI:
+ case OPC_DADDIU:
+#endif
+ case OPC_SLTI:
+ case OPC_SLTIU:
uimm = (int32_t)imm; /* Sign extend to 32 bits */
- else
- uimm = (uint16_t)imm;
- if (opc != OPC_LUI) {
+ /* Fall through. */
+ case OPC_ANDI:
+ case OPC_ORI:
+ case OPC_XORI:
GEN_LOAD_REG_TN(T0, rs);
GEN_LOAD_IMM_TN(T1, uimm);
- } else {
- uimm = uimm << 16;
+ break;
+ case OPC_LUI:
+ uimm <<= 16;
GEN_LOAD_IMM_TN(T0, uimm);
+ break;
+ case OPC_SLL:
+ case OPC_SRA:
+ case OPC_SRL:
+#ifdef TARGET_MIPS64
+ case OPC_DSLL:
+ case OPC_DSRA:
+ case OPC_DSRL:
+ case OPC_DSLL32:
+ case OPC_DSRA32:
+ case OPC_DSRL32:
+#endif
+ uimm &= 0x1f;
+ GEN_LOAD_REG_TN(T0, rs);
+ GEN_LOAD_IMM_TN(T1, uimm);
+ break;
}
switch (opc) {
case OPC_ADDI:
opn = "sra";
break;
case OPC_SRL:
- if ((ctx->opcode >> 21) & 1) {
- gen_op_rotr();
- opn = "rotr";
- } else {
+ switch ((ctx->opcode >> 21) & 0x1f) {
+ case 0:
gen_op_srl();
opn = "srl";
- }
+ break;
+ case 1:
+ gen_op_rotr();
+ opn = "rotr";
+ break;
+ default:
+ MIPS_INVAL("invalid srl flag");
+ generate_exception(ctx, EXCP_RI);
+ break;
+ }
break;
#ifdef TARGET_MIPS64
case OPC_DSLL:
opn = "dsra";
break;
case OPC_DSRL:
- if ((ctx->opcode >> 21) & 1) {
- gen_op_drotr();
- opn = "drotr";
- } else {
+ switch ((ctx->opcode >> 21) & 0x1f) {
+ case 0:
gen_op_dsrl();
opn = "dsrl";
- }
+ break;
+ case 1:
+ gen_op_drotr();
+ opn = "drotr";
+ break;
+ default:
+ MIPS_INVAL("invalid dsrl flag");
+ generate_exception(ctx, EXCP_RI);
+ break;
+ }
break;
case OPC_DSLL32:
gen_op_dsll32();
opn = "dsra32";
break;
case OPC_DSRL32:
- if ((ctx->opcode >> 21) & 1) {
- gen_op_drotr32();
- opn = "drotr32";
- } else {
+ switch ((ctx->opcode >> 21) & 0x1f) {
+ case 0:
gen_op_dsrl32();
opn = "dsrl32";
- }
+ break;
+ case 1:
+ gen_op_drotr32();
+ opn = "drotr32";
+ break;
+ default:
+ MIPS_INVAL("invalid dsrl32 flag");
+ generate_exception(ctx, EXCP_RI);
+ break;
+ }
break;
#endif
default:
opn = "srav";
break;
case OPC_SRLV:
- if ((ctx->opcode >> 6) & 1) {
- gen_op_rotrv();
- opn = "rotrv";
- } else {
+ switch ((ctx->opcode >> 6) & 0x1f) {
+ case 0:
gen_op_srlv();
opn = "srlv";
- }
+ break;
+ case 1:
+ gen_op_rotrv();
+ opn = "rotrv";
+ break;
+ default:
+ MIPS_INVAL("invalid srlv flag");
+ generate_exception(ctx, EXCP_RI);
+ break;
+ }
break;
#ifdef TARGET_MIPS64
case OPC_DSLLV:
opn = "dsrav";
break;
case OPC_DSRLV:
- if ((ctx->opcode >> 6) & 1) {
- gen_op_drotrv();
- opn = "drotrv";
- } else {
+ switch ((ctx->opcode >> 6) & 0x1f) {
+ case 0:
gen_op_dsrlv();
opn = "dsrlv";
- }
+ break;
+ case 1:
+ gen_op_drotrv();
+ opn = "drotrv";
+ break;
+ default:
+ MIPS_INVAL("invalid dsrlv flag");
+ generate_exception(ctx, EXCP_RI);
+ break;
+ }
break;
#endif
default:
/* Jump to register */
if (offset != 0 && offset != 16) {
/* Hint = 0 is JR/JALR, hint 16 is JR.HB/JALR.HB, the
- others are reserved. */
+ others are reserved. */
generate_exception(ctx, EXCP_RI);
return;
}
case OPC_BLTZALL: /* 0 < 0 likely */
gen_op_set_T0(ctx->pc + 8);
gen_op_store_T0_gpr(31);
- gen_goto_tb(ctx, 0, ctx->pc + 4);
+ gen_goto_tb(ctx, 0, ctx->pc + 8);
return;
case OPC_BNEL: /* rx != rx likely */
case OPC_BGTZL: /* 0 > 0 likely */
case OPC_BLTZL: /* 0 < 0 likely */
/* Skip the instruction in the delay slot */
MIPS_DEBUG("bnever and skip");
- gen_goto_tb(ctx, 0, ctx->pc + 4);
+ gen_goto_tb(ctx, 0, ctx->pc + 8);
return;
case OPC_J:
ctx->hflags |= MIPS_HFLAG_B;
likely:
ctx->hflags |= MIPS_HFLAG_BL;
break;
+ default:
+ MIPS_INVAL("conditional branch/jump");
+ generate_exception(ctx, EXCP_RI);
+ return;
}
gen_op_set_bcond();
}
gen_op_set_T0(ctx->pc + 8);
gen_op_store_T0_gpr(blink);
}
- return;
}
/* special3 bitfield operations */
opn = "mfc0";
break;
case OPC_MTC0:
- /* If we get an exception, we want to restart at next instruction */
- /* XXX: breaks for mtc in delay slot */
- ctx->pc += 4;
- save_cpu_state(ctx, 1);
- ctx->pc -= 4;
GEN_LOAD_REG_TN(T0, rt);
gen_mtc0(ctx, rd, ctx->opcode & 0x7);
opn = "mtc0";
opn = "dmfc0";
break;
case OPC_DMTC0:
- /* If we get an exception, we want to restart at next instruction */
- /* XXX: breaks for dmtc in delay slot */
- ctx->pc += 4;
- save_cpu_state(ctx, 1);
- ctx->pc -= 4;
GEN_LOAD_REG_TN(T0, rt);
gen_dmtc0(ctx, rd, ctx->opcode & 0x7);
opn = "dmtc0";
/* make sure instructions are on a word boundary */
if (ctx->pc & 0x3) {
+ env->CP0_BadVAddr = ctx->pc;
generate_exception(ctx, EXCP_AdEL);
return;
}
case OPC_RDHWR:
switch (rd) {
case 0:
+ save_cpu_state(ctx, 1);
gen_op_rdhwr_cpunum();
break;
case 1:
+ save_cpu_state(ctx, 1);
gen_op_rdhwr_synci_step();
break;
case 2:
+ save_cpu_state(ctx, 1);
gen_op_rdhwr_cc();
break;
case 3:
+ save_cpu_state(ctx, 1);
gen_op_rdhwr_ccres();
break;
case 29:
#if defined (CONFIG_USER_ONLY)
gen_op_tls_value ();
-#else
- generate_exception(ctx, EXCP_RI);
-#endif
- break;
- case 30:
- /* Implementation dependent */;
- gen_op_rdhwr_unimpl30();
- break;
- case 31:
- /* Implementation dependent */;
- gen_op_rdhwr_unimpl31();
break;
+#endif
default: /* Invalid */
MIPS_INVAL("rdhwr");
generate_exception(ctx, EXCP_RI);
}
break;
case OPC_CP0:
+ save_cpu_state(ctx, 1);
gen_op_cp0_enabled();
op1 = MASK_CP0(ctx->opcode);
switch (op1) {
gen_op_cp1_enabled();
op1 = MASK_CP3(ctx->opcode);
switch (op1) {
+ case OPC_PREFX:
+ /* treat as noop */
+ break;
/* Not implemented */
default:
generate_exception (ctx, EXCP_RI);
break;
}
if (ctx->hflags & MIPS_HFLAG_BMASK) {
- int hflags = ctx->hflags;
+ int hflags = ctx->hflags & MIPS_HFLAG_BMASK;
/* Branches completion */
ctx->hflags &= ~MIPS_HFLAG_BMASK;
ctx->bstate = BS_BRANCH;