📄 translate.c
字号:
case OPC_DSLL: gen_op_dsll(); opn = "dsll"; break; case OPC_DSRA: gen_op_dsra(); opn = "dsra"; break; case OPC_DSRL: if ((ctx->opcode >> 21) & 1) { gen_op_drotr(); opn = "drotr"; } else { gen_op_dsrl(); opn = "dsrl"; } break; case OPC_DSLL32: gen_op_dsll32(); opn = "dsll32"; break; case OPC_DSRA32: gen_op_dsra32(); opn = "dsra32"; break; case OPC_DSRL32: if ((ctx->opcode >> 21) & 1) { gen_op_drotr32(); opn = "drotr32"; } else { gen_op_dsrl32(); opn = "dsrl32"; } break;#endif default: MIPS_INVAL("imm arith"); generate_exception(ctx, EXCP_RI); return; } GEN_STORE_TN_REG(rt, T0); MIPS_DEBUG("%s %s, %s, %x", opn, regnames[rt], regnames[rs], uimm);}/* Arithmetic */static void gen_arith (DisasContext *ctx, uint32_t opc, int rd, int rs, int rt){ const char *opn = "unk"; 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. */ MIPS_DEBUG("NOP"); return; } GEN_LOAD_REG_TN(T0, rs); GEN_LOAD_REG_TN(T1, rt); switch (opc) { case OPC_ADD: save_cpu_state(ctx, 1); gen_op_addo(); opn = "add"; break; case OPC_ADDU: gen_op_add(); opn = "addu"; break; case OPC_SUB: save_cpu_state(ctx, 1); gen_op_subo(); opn = "sub"; break; case OPC_SUBU: gen_op_sub(); opn = "subu"; break;#ifdef MIPS_HAS_MIPS64 case OPC_DADD: save_cpu_state(ctx, 1); gen_op_daddo(); opn = "dadd"; break; case OPC_DADDU: gen_op_dadd(); opn = "daddu"; break; case OPC_DSUB: save_cpu_state(ctx, 1); gen_op_dsubo(); opn = "dsub"; break; case OPC_DSUBU: gen_op_dsub(); opn = "dsubu"; break;#endif case OPC_SLT: gen_op_lt(); opn = "slt"; break; case OPC_SLTU: gen_op_ltu(); opn = "sltu"; break; case OPC_AND: gen_op_and(); opn = "and"; break; case OPC_NOR: gen_op_nor(); opn = "nor"; break; case OPC_OR: gen_op_or(); opn = "or"; break; case OPC_XOR: gen_op_xor(); opn = "xor"; break; case OPC_MUL: gen_op_mul(); opn = "mul"; break; case OPC_MOVN: gen_op_movn(rd); opn = "movn"; goto print; case OPC_MOVZ: gen_op_movz(rd); opn = "movz"; goto print; case OPC_SLLV: gen_op_sllv(); opn = "sllv"; break; case OPC_SRAV: gen_op_srav(); opn = "srav"; break; case OPC_SRLV: if ((ctx->opcode >> 6) & 1) { gen_op_rotrv(); opn = "rotrv"; } else { gen_op_srlv(); opn = "srlv"; } break;#ifdef MIPS_HAS_MIPS64 case OPC_DSLLV: gen_op_dsllv(); opn = "dsllv"; break; case OPC_DSRAV: gen_op_dsrav(); opn = "dsrav"; break; case OPC_DSRLV: if ((ctx->opcode >> 6) & 1) { gen_op_drotrv(); opn = "drotrv"; } else { gen_op_dsrlv(); opn = "dsrlv"; } break;#endif default: MIPS_INVAL("arith"); generate_exception(ctx, EXCP_RI); return; } GEN_STORE_TN_REG(rd, T0); print: MIPS_DEBUG("%s %s, %s, %s", opn, regnames[rd], regnames[rs], regnames[rt]);}/* Arithmetic on HI/LO registers */static void gen_HILO (DisasContext *ctx, uint32_t opc, int reg){ const char *opn = "unk"; if (reg == 0 && (opc == OPC_MFHI || opc == OPC_MFLO)) { /* Treat as a NOP */ MIPS_DEBUG("NOP"); return; } switch (opc) { case OPC_MFHI: gen_op_load_HI(); GEN_STORE_TN_REG(reg, T0); opn = "mfhi"; break; case OPC_MFLO: gen_op_load_LO(); GEN_STORE_TN_REG(reg, T0); opn = "mflo"; break; case OPC_MTHI: GEN_LOAD_REG_TN(T0, reg); gen_op_store_HI(); opn = "mthi"; break; case OPC_MTLO: GEN_LOAD_REG_TN(T0, reg); gen_op_store_LO(); opn = "mtlo"; break; default: MIPS_INVAL("HILO"); generate_exception(ctx, EXCP_RI); return; } MIPS_DEBUG("%s %s", opn, regnames[reg]);}static void gen_muldiv (DisasContext *ctx, uint32_t opc, int rs, int rt){ const char *opn = "unk"; GEN_LOAD_REG_TN(T0, rs); GEN_LOAD_REG_TN(T1, rt); switch (opc) { case OPC_DIV: gen_op_div(); opn = "div"; break; case OPC_DIVU: gen_op_divu(); opn = "divu"; break; case OPC_MULT: gen_op_mult(); opn = "mult"; break; case OPC_MULTU: gen_op_multu(); opn = "multu"; break;#ifdef MIPS_HAS_MIPS64 case OPC_DDIV: gen_op_ddiv(); opn = "ddiv"; break; case OPC_DDIVU: gen_op_ddivu(); opn = "ddivu"; break; case OPC_DMULT: gen_op_dmult(); opn = "dmult"; break; case OPC_DMULTU: gen_op_dmultu(); opn = "dmultu"; break;#endif case OPC_MADD: gen_op_madd(); opn = "madd"; break; case OPC_MADDU: gen_op_maddu(); opn = "maddu"; break; case OPC_MSUB: gen_op_msub(); opn = "msub"; break; case OPC_MSUBU: gen_op_msubu(); opn = "msubu"; break; default: MIPS_INVAL("mul/div"); generate_exception(ctx, EXCP_RI); return; } MIPS_DEBUG("%s %s %s", opn, regnames[rs], regnames[rt]);}static void gen_cl (DisasContext *ctx, uint32_t opc, int rd, int rs){ const char *opn = "unk"; if (rd == 0) { /* Treat as a NOP */ MIPS_DEBUG("NOP"); return; } GEN_LOAD_REG_TN(T0, rs); switch (opc) { case OPC_CLO: gen_op_clo(); opn = "clo"; break; case OPC_CLZ: gen_op_clz(); opn = "clz"; break;#ifdef MIPS_HAS_MIPS64 case OPC_DCLO: gen_op_dclo(); opn = "dclo"; break; case OPC_DCLZ: gen_op_dclz(); opn = "dclz"; break;#endif default: MIPS_INVAL("CLx"); generate_exception(ctx, EXCP_RI); return; } gen_op_store_T0_gpr(rd); MIPS_DEBUG("%s %s, %s", opn, regnames[rd], regnames[rs]);}/* Traps */static void gen_trap (DisasContext *ctx, uint32_t opc, int rs, int rt, int16_t imm){ int cond; cond = 0; /* Load needed operands */ switch (opc) { case OPC_TEQ: case OPC_TGE: case OPC_TGEU: case OPC_TLT: case OPC_TLTU: case OPC_TNE: /* Compare two registers */ if (rs != rt) { GEN_LOAD_REG_TN(T0, rs); GEN_LOAD_REG_TN(T1, rt); cond = 1; } break; case OPC_TEQI: case OPC_TGEI: case OPC_TGEIU: case OPC_TLTI: case OPC_TLTIU: case OPC_TNEI: /* Compare register to immediate */ if (rs != 0 || imm != 0) { GEN_LOAD_REG_TN(T0, rs); GEN_LOAD_IMM_TN(T1, (int32_t)imm); cond = 1; } break; } if (cond == 0) { switch (opc) { case OPC_TEQ: /* rs == rs */ case OPC_TEQI: /* r0 == 0 */ case OPC_TGE: /* rs >= rs */ case OPC_TGEI: /* r0 >= 0 */ case OPC_TGEU: /* rs >= rs unsigned */ case OPC_TGEIU: /* r0 >= 0 unsigned */ /* Always trap */ gen_op_set_T0(1); break; case OPC_TLT: /* rs < rs */ case OPC_TLTI: /* r0 < 0 */ case OPC_TLTU: /* rs < rs unsigned */ case OPC_TLTIU: /* r0 < 0 unsigned */ case OPC_TNE: /* rs != rs */ case OPC_TNEI: /* r0 != 0 */ /* Never trap: treat as NOP */ return; default: MIPS_INVAL("TRAP"); generate_exception(ctx, EXCP_RI); return; } } else { switch (opc) { case OPC_TEQ: case OPC_TEQI: gen_op_eq(); break; case OPC_TGE: case OPC_TGEI: gen_op_ge(); break; case OPC_TGEU: case OPC_TGEIU: gen_op_geu(); break; case OPC_TLT: case OPC_TLTI: gen_op_lt(); break; case OPC_TLTU: case OPC_TLTIU: gen_op_ltu(); break; case OPC_TNE: case OPC_TNEI: gen_op_ne(); break; default: MIPS_INVAL("TRAP"); generate_exception(ctx, EXCP_RI); return; } } save_cpu_state(ctx, 1); gen_op_trap(); ctx->bstate = BS_STOP;}static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest){ TranslationBlock *tb; tb = ctx->tb; if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) { if (n == 0) gen_op_goto_tb0(TBPARAM(tb)); else gen_op_goto_tb1(TBPARAM(tb)); gen_op_save_pc(dest); gen_op_set_T0((long)tb + n); gen_op_exit_tb(); } else { gen_op_save_pc(dest); gen_op_set_T0(0); gen_op_exit_tb(); }}/* Branches (before delay slot) */static void gen_compute_branch (DisasContext *ctx, uint32_t opc, int rs, int rt, int32_t offset){ target_ulong btarget; int blink, bcond; btarget = -1; blink = 0; bcond = 0; /* Load needed operands */ switch (opc) { case OPC_BEQ: case OPC_BEQL: case OPC_BNE: case OPC_BNEL: /* Compare two registers */ if (rs != rt) { GEN_LOAD_REG_TN(T0, rs); GEN_LOAD_REG_TN(T1, rt); bcond = 1; } btarget = ctx->pc + 4 + offset; break; case OPC_BGEZ: case OPC_BGEZAL: case OPC_BGEZALL: case OPC_BGEZL:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -