diff options
Diffstat (limited to 'target-mips/translate.c')
-rw-r--r-- | target-mips/translate.c | 949 |
1 files changed, 713 insertions, 236 deletions
diff --git a/target-mips/translate.c b/target-mips/translate.c index 07dca14595..c87f2c9874 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -266,6 +266,8 @@ enum { OPC_DINSM = 0x05 | OPC_SPECIAL3, OPC_DINSU = 0x06 | OPC_SPECIAL3, OPC_DINS = 0x07 | OPC_SPECIAL3, + OPC_FORK = 0x08 | OPC_SPECIAL3, + OPC_YIELD = 0x09 | OPC_SPECIAL3, OPC_BSHFL = 0x20 | OPC_SPECIAL3, OPC_DBSHFL = 0x24 | OPC_SPECIAL3, OPC_RDHWR = 0x3B | OPC_SPECIAL3, @@ -296,8 +298,10 @@ enum { OPC_DMFC0 = (0x01 << 21) | OPC_CP0, OPC_MTC0 = (0x04 << 21) | OPC_CP0, OPC_DMTC0 = (0x05 << 21) | OPC_CP0, + OPC_MFTR = (0x08 << 21) | OPC_CP0, OPC_RDPGPR = (0x0A << 21) | OPC_CP0, OPC_MFMC0 = (0x0B << 21) | OPC_CP0, + OPC_MTTR = (0x0C << 21) | OPC_CP0, OPC_WRPGPR = (0x0E << 21) | OPC_CP0, OPC_C0 = (0x10 << 21) | OPC_CP0, OPC_C0_FIRST = (0x10 << 21) | OPC_CP0, @@ -308,6 +312,10 @@ enum { #define MASK_MFMC0(op) MASK_CP0(op) | (op & 0xFFFF) enum { + OPC_DMT = 0x01 | (0 << 5) | (0x0F << 6) | (0x01 << 11) | OPC_MFMC0, + OPC_EMT = 0x01 | (1 << 5) | (0x0F << 6) | (0x01 << 11) | OPC_MFMC0, + OPC_DVPE = 0x01 | (0 << 5) | OPC_MFMC0, + OPC_EVPE = 0x01 | (1 << 5) | OPC_MFMC0, OPC_DI = (0 << 5) | (0x0C << 11) | OPC_MFMC0, OPC_EI = (1 << 5) | (0x0C << 11) | OPC_MFMC0, }; @@ -441,6 +449,10 @@ GEN32(gen_op_load_gpr_T2, gen_op_load_gpr_T2_gpr); GEN32(gen_op_store_T0_gpr, gen_op_store_T0_gpr_gpr); GEN32(gen_op_store_T1_gpr, gen_op_store_T1_gpr_gpr); +/* Moves to/from shadow registers */ +GEN32(gen_op_load_srsgpr_T0, gen_op_load_srsgpr_T0_gpr); +GEN32(gen_op_store_T0_srsgpr, gen_op_store_T0_srsgpr_gpr); + static const char *fregnames[] = { "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", @@ -569,6 +581,15 @@ do { \ } \ } while (0) +#define GEN_LOAD_SRSREG_TN(Tn, Rn) \ +do { \ + if (Rn == 0) { \ + glue(gen_op_reset_, Tn)(); \ + } else { \ + glue(gen_op_load_srsgpr_, Tn)(Rn); \ + } \ +} while (0) + #ifdef TARGET_MIPS64 #define GEN_LOAD_IMM_TN(Tn, Imm) \ do { \ @@ -598,6 +619,13 @@ do { \ } \ } while (0) +#define GEN_STORE_TN_SRSREG(Rn, Tn) \ +do { \ + if (Rn != 0) { \ + glue(glue(gen_op_store_, Tn),_srsgpr)(Rn); \ + } \ +} while (0) + #define GEN_LOAD_FREG_FTN(FTn, Fn) \ do { \ glue(gen_op_load_fpr_, FTn)(Fn); \ @@ -740,6 +768,14 @@ static inline void check_mips_r2(CPUState *env, DisasContext *ctx) generate_exception(ctx, EXCP_RI); } +/* This code generates a "reserved instruction" exception if the + CPU is not MIPS MT capable. */ +static inline void check_mips_mt(CPUState *env, DisasContext *ctx) +{ + if (!(env->CP0_Config3 & (1 << CP0C3_MT))) + generate_exception(ctx, EXCP_RI); +} + #if defined(CONFIG_USER_ONLY) #define op_ldst(name) gen_op_##name##_raw() #define OP_LD_TABLE(width) @@ -806,8 +842,7 @@ static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt, gen_op_addr_add(); } /* Don't do NOP if destination is zero: we must perform the actual - * memory access - */ + memory access. */ switch (opc) { #ifdef TARGET_MIPS64 case OPC_LWU: @@ -958,8 +993,7 @@ static void gen_flt_ldst (DisasContext *ctx, uint32_t opc, int ft, gen_op_addr_add(); } /* Don't do NOP if destination is zero: we must perform the actual - * memory access - */ + memory access. */ switch (opc) { case OPC_LWC1: op_ldst(lwc1); @@ -997,9 +1031,8 @@ static void gen_arith_imm (DisasContext *ctx, uint32_t opc, int rt, const char *opn = "imm arith"; if (rt == 0 && opc != OPC_ADDI && opc != OPC_DADDI) { - /* if no destination, treat it as a NOP - * For addi, we must generate the overflow exception when needed. - */ + /* If no destination, treat it as a NOP. + For addi, we must generate the overflow exception when needed. */ MIPS_DEBUG("NOP"); return; } @@ -1175,9 +1208,8 @@ static void gen_arith (DisasContext *ctx, uint32_t opc, if (rd == 0 && opc != OPC_ADD && opc != OPC_SUB && opc != OPC_DADD && opc != OPC_DSUB) { - /* if no destination, treat it as a NOP - * For add & sub, we must generate the overflow exception when needed. - */ + /* If no destination, treat it as a NOP. + For add & sub, we must generate the overflow exception when needed. */ MIPS_DEBUG("NOP"); return; } @@ -1324,29 +1356,29 @@ static void gen_HILO (DisasContext *ctx, uint32_t opc, int reg) const char *opn = "hilo"; if (reg == 0 && (opc == OPC_MFHI || opc == OPC_MFLO)) { - /* Treat as a NOP */ + /* Treat as NOP. */ MIPS_DEBUG("NOP"); return; } switch (opc) { case OPC_MFHI: - gen_op_load_HI(); + gen_op_load_HI(0); GEN_STORE_TN_REG(reg, T0); opn = "mfhi"; break; case OPC_MFLO: - gen_op_load_LO(); + gen_op_load_LO(0); GEN_STORE_TN_REG(reg, T0); opn = "mflo"; break; case OPC_MTHI: GEN_LOAD_REG_TN(T0, reg); - gen_op_store_HI(); + gen_op_store_HI(0); opn = "mthi"; break; case OPC_MTLO: GEN_LOAD_REG_TN(T0, reg); - gen_op_store_LO(); + gen_op_store_LO(0); opn = "mtlo"; break; default: @@ -1428,7 +1460,7 @@ static void gen_cl (DisasContext *ctx, uint32_t opc, { const char *opn = "CLx"; if (rd == 0) { - /* Treat as a NOP */ + /* Treat as NOP. */ MIPS_DEBUG("NOP"); return; } @@ -1514,7 +1546,7 @@ static void gen_trap (DisasContext *ctx, uint32_t opc, case OPC_TLTIU: /* r0 < 0 unsigned */ case OPC_TNE: /* rs != rs */ case OPC_TNEI: /* r0 != 0 */ - /* Never trap: treat as NOP */ + /* Never trap: treat as NOP. */ return; default: MIPS_INVAL("trap"); @@ -1674,7 +1706,7 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, case OPC_BNE: /* rx != rx */ case OPC_BGTZ: /* 0 > 0 */ case OPC_BLTZ: /* 0 < 0 */ - /* Treated as NOP */ + /* Treat as NOP. */ MIPS_DEBUG("bnever (NOP)"); return; case OPC_BLTZAL: /* 0 < 0 */ @@ -1886,17 +1918,20 @@ static void gen_mfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "Index"; break; case 1: -// gen_op_mfc0_mvpcontrol(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_mvpcontrol(); rn = "MVPControl"; -// break; + break; case 2: -// gen_op_mfc0_mvpconf0(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_mvpconf0(); rn = "MVPConf0"; -// break; + break; case 3: -// gen_op_mfc0_mvpconf1(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_mvpconf1(); rn = "MVPConf1"; -// break; + break; default: goto die; } @@ -1908,33 +1943,40 @@ static void gen_mfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "Random"; break; case 1: -// gen_op_mfc0_vpecontrol(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_vpecontrol(); rn = "VPEControl"; -// break; + break; case 2: -// gen_op_mfc0_vpeconf0(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_vpeconf0(); rn = "VPEConf0"; -// break; + break; case 3: -// gen_op_mfc0_vpeconf1(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_vpeconf1(); rn = "VPEConf1"; -// break; + break; case 4: -// gen_op_mfc0_YQMask(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_yqmask(); rn = "YQMask"; -// break; + break; case 5: -// gen_op_mfc0_vpeschedule(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_vpeschedule(); rn = "VPESchedule"; -// break; + break; case 6: -// gen_op_mfc0_vpeschefback(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_vpeschefback(); rn = "VPEScheFBack"; -// break; + break; case 7: -// gen_op_mfc0_vpeopt(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_vpeopt(); rn = "VPEOpt"; -// break; + break; default: goto die; } @@ -1946,33 +1988,40 @@ static void gen_mfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "EntryLo0"; break; case 1: -// gen_op_mfc0_tcstatus(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_tcstatus(); rn = "TCStatus"; -// break; + break; case 2: -// gen_op_mfc0_tcbind(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_tcbind(); rn = "TCBind"; -// break; + break; case 3: -// gen_op_mfc0_tcrestart(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_tcrestart(); rn = "TCRestart"; -// break; + break; case 4: -// gen_op_mfc0_tchalt(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_tchalt(); rn = "TCHalt"; -// break; + break; case 5: -// gen_op_mfc0_tccontext(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_tccontext(); rn = "TCContext"; -// break; + break; case 6: -// gen_op_mfc0_tcschedule(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_tcschedule(); rn = "TCSchedule"; -// break; + break; case 7: -// gen_op_mfc0_tcschefback(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_tcschefback(); rn = "TCScheFBack"; -// break; + break; default: goto die; } @@ -2023,25 +2072,25 @@ static void gen_mfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "Wired"; break; case 1: -// gen_op_mfc0_srsconf0(); /* shadow registers */ + gen_op_mfc0_srsconf0(); rn = "SRSConf0"; -// break; + break; case 2: -// gen_op_mfc0_srsconf1(); /* shadow registers */ + gen_op_mfc0_srsconf1(); rn = "SRSConf1"; -// break; + break; case 3: -// gen_op_mfc0_srsconf2(); /* shadow registers */ + gen_op_mfc0_srsconf2(); rn = "SRSConf2"; -// break; + break; case 4: -// gen_op_mfc0_srsconf3(); /* shadow registers */ + gen_op_mfc0_srsconf3(); rn = "SRSConf3"; -// break; + break; case 5: -// gen_op_mfc0_srsconf4(); /* shadow registers */ + gen_op_mfc0_srsconf4(); rn = "SRSConf4"; -// break; + break; default: goto die; } @@ -2430,17 +2479,20 @@ static void gen_mtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "Index"; break; case 1: -// gen_op_mtc0_mvpcontrol(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_mvpcontrol(); rn = "MVPControl"; -// break; + break; case 2: -// gen_op_mtc0_mvpconf0(); /* MT ASE */ + check_mips_mt(env, ctx); + /* ignored */ rn = "MVPConf0"; -// break; + break; case 3: -// gen_op_mtc0_mvpconf1(); /* MT ASE */ + check_mips_mt(env, ctx); + /* ignored */ rn = "MVPConf1"; -// break; + break; default: goto die; } @@ -2452,33 +2504,40 @@ static void gen_mtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "Random"; break; case 1: -// gen_op_mtc0_vpecontrol(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_vpecontrol(); rn = "VPEControl"; -// break; + break; case 2: -// gen_op_mtc0_vpeconf0(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_vpeconf0(); rn = "VPEConf0"; -// break; + break; case 3: -// gen_op_mtc0_vpeconf1(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_vpeconf1(); rn = "VPEConf1"; -// break; + break; case 4: -// gen_op_mtc0_YQMask(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_yqmask(); rn = "YQMask"; -// break; + break; case 5: -// gen_op_mtc0_vpeschedule(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_vpeschedule(); rn = "VPESchedule"; -// break; + break; case 6: -// gen_op_mtc0_vpeschefback(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_vpeschefback(); rn = "VPEScheFBack"; -// break; + break; case 7: -// gen_op_mtc0_vpeopt(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_vpeopt(); rn = "VPEOpt"; -// break; + break; default: goto die; } @@ -2490,33 +2549,40 @@ static void gen_mtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "EntryLo0"; break; case 1: -// gen_op_mtc0_tcstatus(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_tcstatus(); rn = "TCStatus"; -// break; + break; case 2: -// gen_op_mtc0_tcbind(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_tcbind(); rn = "TCBind"; -// break; + break; case 3: -// gen_op_mtc0_tcrestart(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_tcrestart(); rn = "TCRestart"; -// break; + break; case 4: -// gen_op_mtc0_tchalt(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_tchalt(); rn = "TCHalt"; -// break; + break; case 5: -// gen_op_mtc0_tccontext(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_tccontext(); rn = "TCContext"; -// break; + break; case 6: -// gen_op_mtc0_tcschedule(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_tcschedule(); rn = "TCSchedule"; -// break; + break; case 7: -// gen_op_mtc0_tcschefback(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_tcschefback(); rn = "TCScheFBack"; -// break; + break; default: goto die; } @@ -2567,25 +2633,25 @@ static void gen_mtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "Wired"; break; case 1: -// gen_op_mtc0_srsconf0(); /* shadow registers */ + gen_op_mtc0_srsconf0(); rn = "SRSConf0"; -// break; + break; case 2: -// gen_op_mtc0_srsconf1(); /* shadow registers */ + gen_op_mtc0_srsconf1(); rn = "SRSConf1"; -// break; + break; case 3: -// gen_op_mtc0_srsconf2(); /* shadow registers */ + gen_op_mtc0_srsconf2(); rn = "SRSConf2"; -// break; + break; case 4: -// gen_op_mtc0_srsconf3(); /* shadow registers */ + gen_op_mtc0_srsconf3(); rn = "SRSConf3"; -// break; + break; case 5: -// gen_op_mtc0_srsconf4(); /* shadow registers */ + gen_op_mtc0_srsconf4(); rn = "SRSConf4"; -// break; + break; default: goto die; } @@ -3006,17 +3072,20 @@ static void gen_dmfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "Index"; break; case 1: -// gen_op_dmfc0_mvpcontrol(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_mvpcontrol(); rn = "MVPControl"; -// break; + break; case 2: -// gen_op_dmfc0_mvpconf0(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_mvpconf0(); rn = "MVPConf0"; -// break; + break; case 3: -// gen_op_dmfc0_mvpconf1(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_mvpconf1(); rn = "MVPConf1"; -// break; + break; default: goto die; } @@ -3028,33 +3097,40 @@ static void gen_dmfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "Random"; break; case 1: -// gen_op_dmfc0_vpecontrol(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_vpecontrol(); rn = "VPEControl"; -// break; + break; case 2: -// gen_op_dmfc0_vpeconf0(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_vpeconf0(); rn = "VPEConf0"; -// break; + break; case 3: -// gen_op_dmfc0_vpeconf1(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_vpeconf1(); rn = "VPEConf1"; -// break; + break; case 4: -// gen_op_dmfc0_YQMask(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_dmfc0_yqmask(); rn = "YQMask"; -// break; + break; case 5: -// gen_op_dmfc0_vpeschedule(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_dmfc0_vpeschedule(); rn = "VPESchedule"; -// break; + break; case 6: -// gen_op_dmfc0_vpeschefback(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_dmfc0_vpeschefback(); rn = "VPEScheFBack"; -// break; + break; case 7: -// gen_op_dmfc0_vpeopt(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_vpeopt(); rn = "VPEOpt"; -// break; + break; default: goto die; } @@ -3066,33 +3142,40 @@ static void gen_dmfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "EntryLo0"; break; case 1: -// gen_op_dmfc0_tcstatus(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_tcstatus(); rn = "TCStatus"; -// break; + break; case 2: -// gen_op_dmfc0_tcbind(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_tcbind(); rn = "TCBind"; -// break; + break; case 3: -// gen_op_dmfc0_tcrestart(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_dmfc0_tcrestart(); rn = "TCRestart"; -// break; + break; case 4: -// gen_op_dmfc0_tchalt(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_dmfc0_tchalt(); rn = "TCHalt"; -// break; + break; case 5: -// gen_op_dmfc0_tccontext(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_dmfc0_tccontext(); rn = "TCContext"; -// break; + break; case 6: -// gen_op_dmfc0_tcschedule(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_dmfc0_tcschedule(); rn = "TCSchedule"; -// break; + break; case 7: -// gen_op_dmfc0_tcschefback(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_dmfc0_tcschefback(); rn = "TCScheFBack"; -// break; + break; default: goto die; } @@ -3143,25 +3226,25 @@ static void gen_dmfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "Wired"; break; case 1: -// gen_op_dmfc0_srsconf0(); /* shadow registers */ + gen_op_mfc0_srsconf0(); rn = "SRSConf0"; -// break; + break; case 2: -// gen_op_dmfc0_srsconf1(); /* shadow registers */ + gen_op_mfc0_srsconf1(); rn = "SRSConf1"; -// break; + break; case 3: -// gen_op_dmfc0_srsconf2(); /* shadow registers */ + gen_op_mfc0_srsconf2(); rn = "SRSConf2"; -// break; + break; case 4: -// gen_op_dmfc0_srsconf3(); /* shadow registers */ + gen_op_mfc0_srsconf3(); rn = "SRSConf3"; -// break; + break; case 5: -// gen_op_dmfc0_srsconf4(); /* shadow registers */ + gen_op_mfc0_srsconf4(); rn = "SRSConf4"; -// break; + break; default: goto die; } @@ -3237,7 +3320,7 @@ static void gen_dmfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) break; case 3: check_mips_r2(env, ctx); - gen_op_mfc0_srsmap(); /* shadow registers */ + gen_op_mfc0_srsmap(); rn = "SRSMap"; break; default: @@ -3537,17 +3620,20 @@ static void gen_dmtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "Index"; break; case 1: -// gen_op_mtc0_mvpcontrol(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_mvpcontrol(); rn = "MVPControl"; -// break; + break; case 2: -// gen_op_mtc0_mvpconf0(); /* MT ASE */ + check_mips_mt(env, ctx); + /* ignored */ rn = "MVPConf0"; -// break; + break; case 3: -// gen_op_mtc0_mvpconf1(); /* MT ASE */ + check_mips_mt(env, ctx); + /* ignored */ rn = "MVPConf1"; -// break; + break; default: goto die; } @@ -3559,33 +3645,40 @@ static void gen_dmtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "Random"; break; case 1: -// gen_op_mtc0_vpecontrol(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_vpecontrol(); rn = "VPEControl"; -// break; + break; case 2: -// gen_op_mtc0_vpeconf0(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_vpeconf0(); rn = "VPEConf0"; -// break; + break; case 3: -// gen_op_mtc0_vpeconf1(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_vpeconf1(); rn = "VPEConf1"; -// break; + break; case 4: -// gen_op_mtc0_YQMask(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_yqmask(); rn = "YQMask"; -// break; + break; case 5: -// gen_op_mtc0_vpeschedule(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_vpeschedule(); rn = "VPESchedule"; -// break; + break; case 6: -// gen_op_mtc0_vpeschefback(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_vpeschefback(); rn = "VPEScheFBack"; -// break; + break; case 7: -// gen_op_mtc0_vpeopt(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_vpeopt(); rn = "VPEOpt"; -// break; + break; default: goto die; } @@ -3597,33 +3690,40 @@ static void gen_dmtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "EntryLo0"; break; case 1: -// gen_op_mtc0_tcstatus(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_tcstatus(); rn = "TCStatus"; -// break; + break; case 2: -// gen_op_mtc0_tcbind(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_tcbind(); rn = "TCBind"; -// break; + break; case 3: -// gen_op_mtc0_tcrestart(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_tcrestart(); rn = "TCRestart"; -// break; + break; case 4: -// gen_op_mtc0_tchalt(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_tchalt(); rn = "TCHalt"; -// break; + break; case 5: -// gen_op_mtc0_tccontext(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_tccontext(); rn = "TCContext"; -// break; + break; case 6: -// gen_op_mtc0_tcschedule(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_tcschedule(); rn = "TCSchedule"; -// break; + break; case 7: -// gen_op_mtc0_tcschefback(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_tcschefback(); rn = "TCScheFBack"; -// break; + break; default: goto die; } @@ -3674,25 +3774,25 @@ static void gen_dmtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "Wired"; break; case 1: -// gen_op_mtc0_srsconf0(); /* shadow registers */ + gen_op_mtc0_srsconf0(); rn = "SRSConf0"; -// break; + break; case 2: -// gen_op_mtc0_srsconf1(); /* shadow registers */ + gen_op_mtc0_srsconf1(); rn = "SRSConf1"; -// break; + break; case 3: -// gen_op_mtc0_srsconf2(); /* shadow registers */ + gen_op_mtc0_srsconf2(); rn = "SRSConf2"; -// break; + break; case 4: -// gen_op_mtc0_srsconf3(); /* shadow registers */ + gen_op_mtc0_srsconf3(); rn = "SRSConf3"; -// break; + break; case 5: -// gen_op_mtc0_srsconf4(); /* shadow registers */ + gen_op_mtc0_srsconf4(); rn = "SRSConf4"; -// break; + break; default: goto die; } @@ -4086,6 +4186,334 @@ die: } #endif /* TARGET_MIPS64 */ +static void gen_mftr(CPUState *env, DisasContext *ctx, int rt, + int u, int sel, int h) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + if ((env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP)) == 0 && + ((env->CP0_TCBind[other_tc] & (0xf << CP0TCBd_CurVPE)) != + (env->CP0_TCBind[env->current_tc] & (0xf << CP0TCBd_CurVPE)))) + gen_op_set_T0(-1); + else if ((env->CP0_VPEControl & (0xff << CP0VPECo_TargTC)) > + (env->mvp->CP0_MVPConf0 & (0xff << CP0MVPC0_PTC))) + gen_op_set_T0(-1); + else if (u == 0) { + switch (rt) { + case 2: + switch (sel) { + case 1: + gen_op_mftc0_tcstatus(); + break; + case 2: + gen_op_mftc0_tcbind(); + break; + case 3: + gen_op_mftc0_tcrestart(); + break; + case 4: + gen_op_mftc0_tchalt(); + break; + case 5: + gen_op_mftc0_tccontext(); + break; + case 6: + gen_op_mftc0_tcschedule(); + break; + case 7: + gen_op_mftc0_tcschefback(); + break; + default: + gen_mfc0(env, ctx, rt, sel); + break; + } + break; + case 10: + switch (sel) { + case 0: + gen_op_mftc0_entryhi(); + break; + default: + gen_mfc0(env, ctx, rt, sel); + break; + } + case 12: + switch (sel) { + case 0: + gen_op_mftc0_status(); + break; + default: + gen_mfc0(env, ctx, rt, sel); + break; + } + case 23: + switch (sel) { + case 0: + gen_op_mftc0_debug(); + break; + default: + gen_mfc0(env, ctx, rt, sel); + break; + } + break; + default: + gen_mfc0(env, ctx, rt, sel); + } + } else switch (sel) { + /* GPR registers. */ + case 0: + gen_op_mftgpr(rt); + break; + /* Auxiliary CPU registers */ + case 1: + switch (rt) { + case 0: + gen_op_mftlo(0); + break; + case 1: + gen_op_mfthi(0); + break; + case 2: + gen_op_mftacx(0); + break; + case 4: + gen_op_mftlo(1); + break; + case 5: + gen_op_mfthi(1); + break; + case 6: + gen_op_mftacx(1); + break; + case 8: + gen_op_mftlo(2); + break; + case 9: + gen_op_mfthi(2); + break; + case 10: + gen_op_mftacx(2); + break; + case 12: + gen_op_mftlo(3); + break; + case 13: + gen_op_mfthi(3); + break; + case 14: + gen_op_mftacx(3); + break; + case 16: + gen_op_mftdsp(); + break; + default: + goto die; + } + break; + /* Floating point (COP1). */ + case 2: + /* XXX: For now we support only a single FPU context. */ + if (h == 0) { + GEN_LOAD_FREG_FTN(WT0, rt); + gen_op_mfc1(); + } else { + GEN_LOAD_FREG_FTN(WTH0, rt); + gen_op_mfhc1(); + } + break; + case 3: + /* XXX: For now we support only a single FPU context. */ + gen_op_cfc1(rt); + break; + /* COP2: Not implemented. */ + case 4: + case 5: + /* fall through */ + default: + goto die; + } +#if defined MIPS_DEBUG_DISAS + if (loglevel & CPU_LOG_TB_IN_ASM) { + fprintf(logfile, "mftr (reg %d u %d sel %d h %d)\n", + rt, u, sel, h); + } +#endif + return; + +die: +#if defined MIPS_DEBUG_DISAS + if (loglevel & CPU_LOG_TB_IN_ASM) { + fprintf(logfile, "mftr (reg %d u %d sel %d h %d)\n", + rt, u, sel, h); + } +#endif + generate_exception(ctx, EXCP_RI); +} + +static void gen_mttr(CPUState *env, DisasContext *ctx, int rd, + int u, int sel, int h) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + if ((env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP)) == 0 && + ((env->CP0_TCBind[other_tc] & (0xf << CP0TCBd_CurVPE)) != + (env->CP0_TCBind[env->current_tc] & (0xf << CP0TCBd_CurVPE)))) + /* NOP */ ; + else if ((env->CP0_VPEControl & (0xff << CP0VPECo_TargTC)) > + (env->mvp->CP0_MVPConf0 & (0xff << CP0MVPC0_PTC))) + /* NOP */ ; + else if (u == 0) { + switch (rd) { + case 2: + switch (sel) { + case 1: + gen_op_mttc0_tcstatus(); + break; + case 2: + gen_op_mttc0_tcbind(); + break; + case 3: + gen_op_mttc0_tcrestart(); + break; + case 4: + gen_op_mttc0_tchalt(); + break; + case 5: + gen_op_mttc0_tccontext(); + break; + case 6: + gen_op_mttc0_tcschedule(); + break; + case 7: + gen_op_mttc0_tcschefback(); + break; + default: + gen_mtc0(env, ctx, rd, sel); + break; + } + break; + case 10: + switch (sel) { + case 0: + gen_op_mttc0_entryhi(); + break; + default: + gen_mtc0(env, ctx, rd, sel); + break; + } + case 12: + switch (sel) { + case 0: + gen_op_mttc0_status(); + break; + default: + gen_mtc0(env, ctx, rd, sel); + break; + } + case 23: + switch (sel) { + case 0: + gen_op_mttc0_debug(); + break; + default: + gen_mtc0(env, ctx, rd, sel); + break; + } + break; + default: + gen_mtc0(env, ctx, rd, sel); + } + } else switch (sel) { + /* GPR registers. */ + case 0: + gen_op_mttgpr(rd); + break; + /* Auxiliary CPU registers */ + case 1: + switch (rd) { + case 0: + gen_op_mttlo(0); + break; + case 1: + gen_op_mtthi(0); + break; + case 2: + gen_op_mttacx(0); + break; + case 4: + gen_op_mttlo(1); + break; + case 5: + gen_op_mtthi(1); + break; + case 6: + gen_op_mttacx(1); + break; + case 8: + gen_op_mttlo(2); + break; + case 9: + gen_op_mtthi(2); + break; + case 10: + gen_op_mttacx(2); + break; + case 12: + gen_op_mttlo(3); + break; + case 13: + gen_op_mtthi(3); + break; + case 14: + gen_op_mttacx(3); + break; + case 16: + gen_op_mttdsp(); + break; + default: + goto die; + } + break; + /* Floating point (COP1). */ + case 2: + /* XXX: For now we support only a single FPU context. */ + if (h == 0) { + gen_op_mtc1(); + GEN_STORE_FTN_FREG(rd, WT0); + } else { + gen_op_mthc1(); + GEN_STORE_FTN_FREG(rd, WTH0); + } + break; + case 3: + /* XXX: For now we support only a single FPU context. */ + gen_op_ctc1(rd); + break; + /* COP2: Not implemented. */ + case 4: + case 5: + /* fall through */ + default: + goto die; + } +#if defined MIPS_DEBUG_DISAS + if (loglevel & CPU_LOG_TB_IN_ASM) { + fprintf(logfile, "mttr (reg %d u %d sel %d h %d)\n", + rd, u, sel, h); + } +#endif + return; + +die: +#if defined MIPS_DEBUG_DISAS + if (loglevel & CPU_LOG_TB_IN_ASM) { + fprintf(logfile, "mttr (reg %d u %d sel %d h %d)\n", + rd, u, sel, h); + } +#endif + generate_exception(ctx, EXCP_RI); +} + static void gen_cp0 (CPUState *env, DisasContext *ctx, uint32_t opc, int rt, int rd) { const char *opn = "ldst"; @@ -4093,7 +4521,7 @@ static void gen_cp0 (CPUState *env, DisasContext *ctx, uint32_t opc, int rt, int switch (opc) { case OPC_MFC0: if (rt == 0) { - /* Treat as NOP */ + /* Treat as NOP. */ return; } gen_mfc0(env, ctx, rd, ctx->opcode & 0x7); @@ -4110,7 +4538,7 @@ static void gen_cp0 (CPUState *env, DisasContext *ctx, uint32_t opc, int rt, int if (!(ctx->hflags & MIPS_HFLAG_64)) generate_exception(ctx, EXCP_RI); if (rt == 0) { - /* Treat as NOP */ + /* Treat as NOP. */ return; } gen_dmfc0(env, ctx, rd, ctx->opcode & 0x7); @@ -4121,31 +4549,49 @@ static void gen_cp0 (CPUState *env, DisasContext *ctx, uint32_t opc, int rt, int if (!(ctx->hflags & MIPS_HFLAG_64)) generate_exception(ctx, EXCP_RI); GEN_LOAD_REG_TN(T0, rt); - gen_dmtc0(env,ctx, rd, ctx->opcode & 0x7); + gen_dmtc0(env, ctx, rd, ctx->opcode & 0x7); opn = "dmtc0"; break; #endif + case OPC_MFTR: + check_mips_mt(env, ctx); + if (rd == 0) { + /* Treat as NOP. */ + return; + } + gen_mftr(env, ctx, rt, (ctx->opcode >> 5) & 1, + ctx->opcode & 0x7, (ctx->opcode >> 4) & 1); + gen_op_store_T0_gpr(rd); + opn = "mftr"; + break; + case OPC_MTTR: + check_mips_mt(env, ctx); + GEN_LOAD_REG_TN(T0, rt); + gen_mttr(env, ctx, rd, (ctx->opcode >> 5) & 1, + ctx->opcode & 0x7, (ctx->opcode >> 4) & 1); + opn = "mttr"; + break; case OPC_TLBWI: opn = "tlbwi"; - if (!env->do_tlbwi) + if (!env->tlb->do_tlbwi) goto die; gen_op_tlbwi(); break; case OPC_TLBWR: opn = "tlbwr"; - if (!env->do_tlbwr) + if (!env->tlb->do_tlbwr) goto die; gen_op_tlbwr(); break; case OPC_TLBP: opn = "tlbp"; - if (!env->do_tlbp) + if (!env->tlb->do_tlbp) goto die; gen_op_tlbp(); break; case OPC_TLBR: opn = "tlbr"; - if (!env->do_tlbr) + if (!env->tlb->do_tlbr) goto die; gen_op_tlbr(); break; @@ -4263,15 +4709,13 @@ static void gen_cp1 (DisasContext *ctx, uint32_t opc, int rt, int fs) opn = "mtc1"; break; case OPC_CFC1: - GEN_LOAD_IMM_TN(T1, fs); - gen_op_cfc1(); + gen_op_cfc1(fs); GEN_STORE_TN_REG(rt, T0); opn = "cfc1"; break; case OPC_CTC1: - GEN_LOAD_IMM_TN(T1, fs); GEN_LOAD_REG_TN(T0, rt); - gen_op_ctc1(); + gen_op_ctc1(fs); opn = "ctc1"; break; case OPC_DMFC1: @@ -5171,8 +5615,7 @@ static void gen_flt3_ldst (DisasContext *ctx, uint32_t opc, gen_op_addr_add(); } /* Don't do NOP if destination is zero: we must perform the actual - * memory access - */ + memory access. */ switch (opc) { case OPC_LWXC1: op_ldst(lwc1); @@ -5456,7 +5899,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) #endif break; case OPC_SYNC: - /* Treat as a noop. */ + /* Treat as NOP. */ break; case OPC_MOVCI: @@ -5521,7 +5964,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) } else { generate_exception(ctx, EXCP_DBp); } - /* Treat as a noop */ + /* Treat as NOP. */ break; #ifdef TARGET_MIPS64 case OPC_DCLZ ... OPC_DCLO: @@ -5586,7 +6029,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) break; case 29: #if defined (CONFIG_USER_ONLY) - gen_op_tls_value (); + gen_op_tls_value(); break; #endif default: /* Invalid */ @@ -5596,6 +6039,18 @@ static void decode_opc (CPUState *env, DisasContext *ctx) } GEN_STORE_TN_REG(rt, T0); break; + case OPC_FORK: + check_mips_mt(env, ctx); + GEN_LOAD_REG_TN(T0, rt); + GEN_LOAD_REG_TN(T1, rs); + gen_op_fork(); + break; + case OPC_YIELD: + check_mips_mt(env, ctx); + GEN_LOAD_REG_TN(T0, rs); + gen_op_yield(); + GEN_STORE_TN_REG(rd, T0); + break; #ifdef TARGET_MIPS64 case OPC_DEXTM ... OPC_DEXT: case OPC_DINSM ... OPC_DINS: @@ -5642,7 +6097,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) break; case OPC_SYNCI: check_mips_r2(env, ctx); - /* treat as noop */ + /* Treat as NOP. */ break; default: /* Invalid */ MIPS_INVAL("regimm"); @@ -5657,6 +6112,8 @@ static void decode_opc (CPUState *env, DisasContext *ctx) switch (op1) { case OPC_MFC0: case OPC_MTC0: + case OPC_MFTR: + case OPC_MTTR: #ifdef TARGET_MIPS64 case OPC_DMFC0: case OPC_DMTC0: @@ -5670,6 +6127,22 @@ static void decode_opc (CPUState *env, DisasContext *ctx) check_mips_r2(env, ctx); op2 = MASK_MFMC0(ctx->opcode); switch (op2) { + case OPC_DMT: + check_mips_mt(env, ctx); + gen_op_dmt(); + break; + case OPC_EMT: + check_mips_mt(env, ctx); + gen_op_emt(); + break; + case OPC_DVPE: + check_mips_mt(env, ctx); + gen_op_dvpe(); + break; + case OPC_EVPE: + check_mips_mt(env, ctx); + gen_op_evpe(); + break; case OPC_DI: gen_op_di(); /* Stop translation as we may have switched the execution mode */ @@ -5688,11 +6161,14 @@ static void decode_opc (CPUState *env, DisasContext *ctx) GEN_STORE_TN_REG(rt, T0); break; case OPC_RDPGPR: + check_mips_r2(env, ctx); + GEN_LOAD_SRSREG_TN(T0, rt); + GEN_STORE_TN_REG(rd, T0); + break; case OPC_WRPGPR: check_mips_r2(env, ctx); - /* Shadow registers not implemented. */ GEN_LOAD_REG_TN(T0, rt); - GEN_STORE_TN_REG(rd, T0); + GEN_STORE_TN_SRSREG(rd, T0); break; default: MIPS_INVAL("cp0"); @@ -5719,10 +6195,10 @@ static void decode_opc (CPUState *env, DisasContext *ctx) gen_ldst(ctx, op, rt, rs, imm); break; case OPC_CACHE: - /* Treat as a noop */ + /* Treat as NOP. */ break; case OPC_PREF: - /* Treat as a noop */ + /* Treat as NOP. */ break; /* Floating point (COP1). */ @@ -5807,7 +6283,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) gen_flt3_ldst(ctx, op1, sa, rd, rs, rt); break; case OPC_PREFX: - /* treat as noop */ + /* Treat as NOP. */ break; case OPC_ALNV_PS: case OPC_MADD_S: @@ -6079,13 +6555,14 @@ void fpu_dump_state(CPUState *env, FILE *f, fpu_fprintf(f, "CP1 FCR0 0x%08x FCR31 0x%08x SR.FR %d fp_status 0x%08x(0x%02x)\n", - env->fcr0, env->fcr31, is_fpu64, env->fp_status, get_float_exception_flags(&env->fp_status)); - fpu_fprintf(f, "FT0: "); printfpr(&env->ft0); - fpu_fprintf(f, "FT1: "); printfpr(&env->ft1); - fpu_fprintf(f, "FT2: "); printfpr(&env->ft2); + env->fpu->fcr0, env->fpu->fcr31, is_fpu64, env->fpu->fp_status, + get_float_exception_flags(&env->fpu->fp_status)); + fpu_fprintf(f, "FT0: "); printfpr(&env->fpu->ft0); + fpu_fprintf(f, "FT1: "); printfpr(&env->fpu->ft1); + fpu_fprintf(f, "FT2: "); printfpr(&env->fpu->ft2); for (i = 0; i < 32; (is_fpu64) ? i++ : (i += 2)) { fpu_fprintf(f, "%3s: ", fregnames[i]); - printfpr(&env->fpr[i]); + printfpr(&env->fpu->fpr[i]); } #undef printfpr @@ -6095,7 +6572,7 @@ void dump_fpu (CPUState *env) { if (loglevel) { fprintf(logfile, "pc=0x" TARGET_FMT_lx " HI=0x" TARGET_FMT_lx " LO=0x" TARGET_FMT_lx " ds %04x " TARGET_FMT_lx " %d\n", - env->PC, env->HI, env->LO, env->hflags, env->btarget, env->bcond); + env->PC[env->current_tc], env->HI[0][env->current_tc], env->LO[0][env->current_tc], env->hflags, env->btarget, env->bcond); fpu_dump_state(env, logfile, fprintf, 0); } } @@ -6112,18 +6589,18 @@ void cpu_mips_check_sign_extensions (CPUState *env, FILE *f, { int i; - if (!SIGN_EXT_P(env->PC)) - cpu_fprintf(f, "BROKEN: pc=0x" TARGET_FMT_lx "\n", env->PC); - if (!SIGN_EXT_P(env->HI)) - cpu_fprintf(f, "BROKEN: HI=0x" TARGET_FMT_lx "\n", env->HI); - if (!SIGN_EXT_P(env->LO)) - cpu_fprintf(f, "BROKEN: LO=0x" TARGET_FMT_lx "\n", env->LO); + if (!SIGN_EXT_P(env->PC[env->current_tc])) + cpu_fprintf(f, "BROKEN: pc=0x" TARGET_FMT_lx "\n", env->PC[env->current_tc]); + if (!SIGN_EXT_P(env->HI[env->current_tc])) + cpu_fprintf(f, "BROKEN: HI=0x" TARGET_FMT_lx "\n", env->HI[env->current_tc]); + if (!SIGN_EXT_P(env->LO[env->current_tc])) + cpu_fprintf(f, "BROKEN: LO=0x" TARGET_FMT_lx "\n", env->LO[env->current_tc]); if (!SIGN_EXT_P(env->btarget)) cpu_fprintf(f, "BROKEN: btarget=0x" TARGET_FMT_lx "\n", env->btarget); for (i = 0; i < 32; i++) { - if (!SIGN_EXT_P(env->gpr[i])) - cpu_fprintf(f, "BROKEN: %s=0x" TARGET_FMT_lx "\n", regnames[i], env->gpr[i]); + if (!SIGN_EXT_P(env->gpr[i][env->current_tc])) + cpu_fprintf(f, "BROKEN: %s=0x" TARGET_FMT_lx "\n", regnames[i], env->gpr[i][env->current_tc]); } if (!SIGN_EXT_P(env->CP0_EPC)) @@ -6140,11 +6617,11 @@ void cpu_dump_state (CPUState *env, FILE *f, int i; cpu_fprintf(f, "pc=0x" TARGET_FMT_lx " HI=0x" TARGET_FMT_lx " LO=0x" TARGET_FMT_lx " ds %04x " TARGET_FMT_lx " %d\n", - env->PC, env->HI, env->LO, env->hflags, env->btarget, env->bcond); + env->PC[env->current_tc], env->HI[env->current_tc], env->LO[env->current_tc], env->hflags, env->btarget, env->bcond); for (i = 0; i < 32; i++) { if ((i & 3) == 0) cpu_fprintf(f, "GPR%02d:", i); - cpu_fprintf(f, " %s " TARGET_FMT_lx, regnames[i], env->gpr[i]); + cpu_fprintf(f, " %s " TARGET_FMT_lx, regnames[i], env->gpr[i][env->current_tc]); if ((i & 3) == 3) cpu_fprintf(f, "\n"); } @@ -6183,12 +6660,12 @@ void cpu_reset (CPUMIPSState *env) if (env->hflags & MIPS_HFLAG_BMASK) { /* If the exception was raised from a delay slot, * come back to the jump. */ - env->CP0_ErrorEPC = env->PC - 4; + env->CP0_ErrorEPC = env->PC[env->current_tc] - 4; } else { - env->CP0_ErrorEPC = env->PC; + env->CP0_ErrorEPC = env->PC[env->current_tc]; } env->hflags = 0; - env->PC = (int32_t)0xBFC00000; + env->PC[env->current_tc] = (int32_t)0xBFC00000; env->CP0_Wired = 0; /* SMP not implemented */ env->CP0_EBase = 0x80000000; |