📄 translate.c
字号:
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, uint16_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: case OPC_BGTZ: case OPC_BGTZL: case OPC_BLEZ: case OPC_BLEZL: case OPC_BLTZ: case OPC_BLTZAL: case OPC_BLTZALL: case OPC_BLTZL: /* Compare to zero */ if (rs != 0) { gen_op_load_gpr_T0(rs); bcond = 1; } btarget = ctx->pc + 4 + offset; break; case OPC_J: case OPC_JAL: /* Jump to immediate */ btarget = ((ctx->pc + 4) & 0xF0000000) | offset; break; case OPC_JR: case OPC_JALR: /* Jump to register */ if (offset != 0) { /* Only hint = 0 is valid */ generate_exception(ctx, EXCP_RI); return; } GEN_LOAD_REG_TN(T2, rs); break; default: MIPS_INVAL("branch/jump"); generate_exception(ctx, EXCP_RI); return; } if (bcond == 0) { /* No condition to be computed */ switch (opc) { case OPC_BEQ: /* rx == rx */ case OPC_BEQL: /* rx == rx likely */ case OPC_BGEZ: /* 0 >= 0 */ case OPC_BGEZL: /* 0 >= 0 likely */ case OPC_BLEZ: /* 0 <= 0 */ case OPC_BLEZL: /* 0 <= 0 likely */ /* Always take */ ctx->hflags |= MIPS_HFLAG_B; MIPS_DEBUG("balways"); break; case OPC_BGEZAL: /* 0 >= 0 */ case OPC_BGEZALL: /* 0 >= 0 likely */ /* Always take and link */ blink = 31; ctx->hflags |= MIPS_HFLAG_B; MIPS_DEBUG("balways and link"); break; case OPC_BNE: /* rx != rx */ case OPC_BGTZ: /* 0 > 0 */ case OPC_BLTZ: /* 0 < 0 */ /* Treated as NOP */ MIPS_DEBUG("bnever (NOP)"); return; case OPC_BLTZAL: /* 0 < 0 */ gen_op_set_T0(ctx->pc + 8); gen_op_store_T0_gpr(31); 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); 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); return; case OPC_J: ctx->hflags |= MIPS_HFLAG_B; MIPS_DEBUG("j %08x", btarget); break; case OPC_JAL: blink = 31; ctx->hflags |= MIPS_HFLAG_B; MIPS_DEBUG("jal %08x", btarget); break; case OPC_JR: ctx->hflags |= MIPS_HFLAG_BR; MIPS_DEBUG("jr %s", regnames[rs]); break; case OPC_JALR: blink = rt; ctx->hflags |= MIPS_HFLAG_BR; MIPS_DEBUG("jalr %s, %s", regnames[rt], regnames[rs]); break; default: MIPS_INVAL("branch/jump"); generate_exception(ctx, EXCP_RI); return; } } else { switch (opc) { case OPC_BEQ: gen_op_eq(); MIPS_DEBUG("beq %s, %s, %08x", regnames[rs], regnames[rt], btarget); goto not_likely; case OPC_BEQL: gen_op_eq(); MIPS_DEBUG("beql %s, %s, %08x", regnames[rs], regnames[rt], btarget); goto likely; case OPC_BNE: gen_op_ne(); MIPS_DEBUG("bne %s, %s, %08x", regnames[rs], regnames[rt], btarget); goto not_likely; case OPC_BNEL: gen_op_ne(); MIPS_DEBUG("bnel %s, %s, %08x", regnames[rs], regnames[rt], btarget); goto likely; case OPC_BGEZ: gen_op_gez(); MIPS_DEBUG("bgez %s, %08x", regnames[rs], btarget); goto not_likely; case OPC_BGEZL: gen_op_gez(); MIPS_DEBUG("bgezl %s, %08x", regnames[rs], btarget); goto likely; case OPC_BGEZAL: gen_op_gez(); MIPS_DEBUG("bgezal %s, %08x", regnames[rs], btarget); blink = 31; goto not_likely; case OPC_BGEZALL: gen_op_gez(); blink = 31; MIPS_DEBUG("bgezall %s, %08x", regnames[rs], btarget); goto likely; case OPC_BGTZ: gen_op_gtz(); MIPS_DEBUG("bgtz %s, %08x", regnames[rs], btarget); goto not_likely; case OPC_BGTZL: gen_op_gtz(); MIPS_DEBUG("bgtzl %s, %08x", regnames[rs], btarget); goto likely; case OPC_BLEZ: gen_op_lez(); MIPS_DEBUG("blez %s, %08x", regnames[rs], btarget); goto not_likely; case OPC_BLEZL: gen_op_lez(); MIPS_DEBUG("blezl %s, %08x", regnames[rs], btarget); goto likely; case OPC_BLTZ: gen_op_ltz(); MIPS_DEBUG("bltz %s, %08x", regnames[rs], btarget); goto not_likely; case OPC_BLTZL: gen_op_ltz(); MIPS_DEBUG("bltzl %s, %08x", regnames[rs], btarget); goto likely; case OPC_BLTZAL: gen_op_ltz(); blink = 31; MIPS_DEBUG("bltzal %s, %08x", regnames[rs], btarget); not_likely: ctx->hflags |= MIPS_HFLAG_BC; break; case OPC_BLTZALL: gen_op_ltz(); blink = 31; MIPS_DEBUG("bltzall %s, %08x", regnames[rs], btarget); likely: ctx->hflags |= MIPS_HFLAG_BL; break; } gen_op_set_bcond(); } MIPS_DEBUG("enter ds: link %d cond %02x target %08x", blink, ctx->hflags, btarget); ctx->btarget = btarget; if (blink > 0) { gen_op_set_T0(ctx->pc + 8); gen_op_store_T0_gpr(blink); } return;}/* CP0 (MMU and control) */static void gen_cp0 (DisasContext *ctx, uint16_t opc, int rt, int rd){ const unsigned char *opn = "unk"; if (!(ctx->CP0_Status & (1 << CP0St_CU0)) && (ctx->hflags & MIPS_HFLAG_UM) && !(ctx->hflags & MIPS_HFLAG_ERL) && !(ctx->hflags & MIPS_HFLAG_EXL)) { if (loglevel & CPU_LOG_TB_IN_ASM) { fprintf(logfile, "CP0 is not usable\n"); } generate_exception_err (ctx, EXCP_CpU, 0); return; } switch (opc) { case OPC_MFC0: if (rt == 0) { /* Treat as NOP */ return; } gen_op_mfc0(rd, ctx->opcode & 0x7); gen_op_store_T0_gpr(rt); opn = "mfc0"; break; case OPC_MTC0: /* If we get an exception, we want to restart at next instruction */ ctx->pc += 4; save_cpu_state(ctx, 1); ctx->pc -= 4; GEN_LOAD_REG_TN(T0, rt); gen_op_mtc0(rd, ctx->opcode & 0x7); /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; opn = "mtc0"; break;#if defined(MIPS_USES_R4K_TLB) case OPC_TLBWI: gen_op_tlbwi(); opn = "tlbwi"; break; case OPC_TLBWR: gen_op_tlbwr(); opn = "tlbwr"; break; case OPC_TLBP: gen_op_tlbp(); opn = "tlbp"; break; case OPC_TLBR: gen_op_tlbr(); opn = "tlbr"; break;#endif case OPC_ERET: opn = "eret"; save_cpu_state(ctx, 0); gen_op_eret(); ctx->bstate = BS_EXCP; break; case OPC_DERET: opn = "deret"; if (!(ctx->hflags & MIPS_HFLAG_DM)) { generate_exception(ctx, EXCP_RI); } else { save_cpu_state(ctx, 0); gen_op_deret(); ctx->bstate = BS_EXCP; } break; case OPC_WAIT: opn = "wait"; /* If we get an exception, we want to restart at next instruction */ ctx->pc += 4; save_cpu_state(ctx, 1); ctx->pc -= 4; gen_op_wait(); ctx->bstate = BS_EXCP; break; default: if (loglevel & CPU_LOG_TB_IN_ASM) { fprintf(logfile, "Invalid CP0 opcode: %08x %03x %03x %03x\n", ctx->opcode, ctx->opcode >> 26, ctx->opcode & 0x3F, ((ctx->opcode >> 16) & 0x1F)); } generate_exception(ctx, EXCP_RI); return; } MIPS_DEBUG("%s %s %d", opn, regnames[rt], rd);}/* Coprocessor 1 (FPU) *//* ISA extensions *//* MIPS16 extension to MIPS32 *//* SmartMIPS extension to MIPS32 */#ifdef TARGET_MIPS64static void gen_arith64 (DisasContext *ctx, uint16_t opc){ if (func == 0x02 && rd == 0) { /* NOP */ return; } if (rs == 0 || rt == 0) { gen_op_reset_T0(); gen_op_save64(); } else { gen_op_load_gpr_T0(rs); gen_op_load_gpr_T1(rt); gen_op_save64(); if (func & 0x01) gen_op_mul64u(); else gen_op_mul64s(); } if (func & 0x02) gen_op_add64(); else gen_op_sub64();}/* Coprocessor 3 (FPU) *//* MDMX extension to MIPS64 *//* MIPS-3D extension to MIPS64 */#endifstatic void gen_blikely(DisasContext *ctx){ int l1; l1 = gen_new_label(); gen_op_jnz_T2(l1); gen_op_save_state(ctx->hflags & ~MIPS_HFLAG_BMASK); gen_goto_tb(ctx, 1, ctx->pc + 4); gen_set_label(l1);}static void decode_opc (DisasContext *ctx){ int32_t offset; int rs, rt, rd, sa; uint16_t op, op1; int16_t imm; if ((ctx->hflags & MIPS_HFLAG_BMASK) == MIPS_HFLAG_BL) { /* Handle blikely not taken case */ MIPS_DEBUG("blikely condition (%08x)", ctx->pc + 4); gen_blikely(ctx); } op = ctx->opcode >> 26; rs = ((ctx->opcode >> 21) & 0x1F); rt = ((ctx->opcode >> 16) & 0x1F); rd = ((ctx->opcode >> 11) & 0x1F); sa = ((ctx->opcode >> 6) & 0x1F); imm = (int16_t)ctx->opcode; switch (op) { case 0x00: /* Special opcode */ op1 = ctx->opcode & 0x3F; switch (op1) { case 0x00: /* Arithmetic with immediate */ case 0x02 ... 0x03: gen_arith_imm(ctx, op1 | EXT_SPECIAL, rd, rt, sa); break; case 0x04: /* Arithmetic */ case 0x06 ... 0x07: case 0x0A ... 0x0B: case 0x20 ... 0x27: case 0x2A ... 0x2B: gen_arith(ctx, op1 | EXT_SPECIAL, rd, rs, rt);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -