translate.c
来自「xen虚拟机源代码安装包」· C语言 代码 · 共 2,182 行 · 第 1/5 页
C
2,182 行
generate_exception_err(ctx, EXCP_CpU, 1);}static always_inline void check_cp1_enabled(DisasContext *ctx){ if (unlikely(!(ctx->hflags & MIPS_HFLAG_FPU))) generate_exception_err(ctx, EXCP_CpU, 1);}/* Verify that the processor is running with COP1X instructions enabled. This is associated with the nabla symbol in the MIPS32 and MIPS64 opcode tables. */static always_inline void check_cop1x(DisasContext *ctx){ if (unlikely(!(ctx->hflags & MIPS_HFLAG_COP1X))) generate_exception(ctx, EXCP_RI);}/* Verify that the processor is running with 64-bit floating-point operations enabled. */static always_inline void check_cp1_64bitmode(DisasContext *ctx){ if (unlikely(~ctx->hflags & (MIPS_HFLAG_F64 | MIPS_HFLAG_COP1X))) generate_exception(ctx, EXCP_RI);}/* * Verify if floating point register is valid; an operation is not defined * if bit 0 of any register specification is set and the FR bit in the * Status register equals zero, since the register numbers specify an * even-odd pair of adjacent coprocessor general registers. When the FR bit * in the Status register equals one, both even and odd register numbers * are valid. This limitation exists only for 64 bit wide (d,l,ps) registers. * * Multiple 64 bit wide registers can be checked by calling * gen_op_cp1_registers(freg1 | freg2 | ... | fregN); */void check_cp1_registers(DisasContext *ctx, int regs){ if (unlikely(!(ctx->hflags & MIPS_HFLAG_F64) && (regs & 1))) generate_exception(ctx, EXCP_RI);}/* This code generates a "reserved instruction" exception if the CPU does not support the instruction set corresponding to flags. */static always_inline void check_insn(CPUState *env, DisasContext *ctx, int flags){ if (unlikely(!(env->insn_flags & flags))) generate_exception(ctx, EXCP_RI);}/* This code generates a "reserved instruction" exception if 64-bit instructions are not enabled. */static always_inline void check_mips_64(DisasContext *ctx){ if (unlikely(!(ctx->hflags & MIPS_HFLAG_64))) generate_exception(ctx, EXCP_RI);}/* load/store instructions. */#if defined(CONFIG_USER_ONLY)#define op_ldst(name) gen_op_##name##_raw()#define OP_LD_TABLE(width)#define OP_ST_TABLE(width)#else#define op_ldst(name) (*gen_op_##name[ctx->mem_idx])()#define OP_LD_TABLE(width) \static GenOpFunc *gen_op_l##width[] = { \ &gen_op_l##width##_kernel, \ &gen_op_l##width##_super, \ &gen_op_l##width##_user, \}#define OP_ST_TABLE(width) \static GenOpFunc *gen_op_s##width[] = { \ &gen_op_s##width##_kernel, \ &gen_op_s##width##_super, \ &gen_op_s##width##_user, \}#endif#if defined(TARGET_MIPS64)OP_LD_TABLE(dl);OP_LD_TABLE(dr);OP_ST_TABLE(dl);OP_ST_TABLE(dr);#endifOP_LD_TABLE(wl);OP_LD_TABLE(wr);OP_ST_TABLE(wl);OP_ST_TABLE(wr);OP_LD_TABLE(wc1);OP_ST_TABLE(wc1);OP_LD_TABLE(dc1);OP_ST_TABLE(dc1);OP_LD_TABLE(uxc1);OP_ST_TABLE(uxc1);#define OP_LD(insn,fname) \void inline op_ldst_##insn(DisasContext *ctx) \{ \ tcg_gen_qemu_##fname(cpu_T[0], cpu_T[0], ctx->mem_idx); \}OP_LD(lb,ld8s);OP_LD(lbu,ld8u);OP_LD(lh,ld16s);OP_LD(lhu,ld16u);OP_LD(lw,ld32s);#if defined(TARGET_MIPS64)OP_LD(lwu,ld32u);OP_LD(ld,ld64);#endif#undef OP_LD#define OP_ST(insn,fname) \void inline op_ldst_##insn(DisasContext *ctx) \{ \ tcg_gen_qemu_##fname(cpu_T[1], cpu_T[0], ctx->mem_idx); \}OP_ST(sb,st8);OP_ST(sh,st16);OP_ST(sw,st32);#if defined(TARGET_MIPS64)OP_ST(sd,st64);#endif#undef OP_ST#define OP_LD_ATOMIC(insn,fname) \void inline op_ldst_##insn(DisasContext *ctx) \{ \ tcg_gen_mov_tl(cpu_T[1], cpu_T[0]); \ tcg_gen_qemu_##fname(cpu_T[0], cpu_T[0], ctx->mem_idx); \ tcg_gen_st_tl(cpu_T[1], cpu_env, offsetof(CPUState, CP0_LLAddr)); \}OP_LD_ATOMIC(ll,ld32s);#if defined(TARGET_MIPS64)OP_LD_ATOMIC(lld,ld64);#endif#undef OP_LD_ATOMIC#define OP_ST_ATOMIC(insn,fname,almask) \void inline op_ldst_##insn(DisasContext *ctx) \{ \ int r_tmp = tcg_temp_new(TCG_TYPE_TL); \ int l1 = gen_new_label(); \ int l2 = gen_new_label(); \ int l3 = gen_new_label(); \ \ tcg_gen_andi_tl(r_tmp, cpu_T[0], almask); \ tcg_gen_brcond_tl(TCG_COND_EQ, r_tmp, tcg_const_tl(0), l1); \ tcg_gen_st_tl(cpu_T[0], cpu_env, offsetof(CPUState, CP0_BadVAddr)); \ generate_tcg_exception(ctx, EXCP_AdES); \ gen_set_label(l1); \ tcg_gen_ld_tl(r_tmp, cpu_env, offsetof(CPUState, CP0_LLAddr)); \ tcg_gen_brcond_tl(TCG_COND_NE, cpu_T[0], r_tmp, l2); \ tcg_gen_qemu_##fname(cpu_T[1], cpu_T[0], ctx->mem_idx); \ tcg_gen_movi_tl(cpu_T[0], 1); \ tcg_gen_br(l3); \ gen_set_label(l2); \ tcg_gen_movi_tl(cpu_T[0], 0); \ gen_set_label(l3); \}OP_ST_ATOMIC(sc,st32,0x3);#if defined(TARGET_MIPS64)OP_ST_ATOMIC(scd,st64,0x7);#endif#undef OP_ST_ATOMICvoid inline op_ldst_lwc1(DisasContext *ctx){ op_ldst(lwc1);}void inline op_ldst_ldc1(DisasContext *ctx){ op_ldst(ldc1);}void inline op_ldst_swc1(DisasContext *ctx){ op_ldst(swc1);}void inline op_ldst_sdc1(DisasContext *ctx){ op_ldst(sdc1);}/* Load and store */static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt, int base, int16_t offset){ const char *opn = "ldst"; if (base == 0) { GEN_LOAD_IMM_TN(T0, offset); } else if (offset == 0) { gen_op_load_gpr_T0(base); } else { gen_op_load_gpr_T0(base); gen_op_set_T1(offset); gen_op_addr_add(); } /* Don't do NOP if destination is zero: we must perform the actual memory access. */ switch (opc) {#if defined(TARGET_MIPS64) case OPC_LWU: op_ldst_lwu(ctx); GEN_STORE_T0_REG(rt); opn = "lwu"; break; case OPC_LD: op_ldst_ld(ctx); GEN_STORE_T0_REG(rt); opn = "ld"; break; case OPC_LLD: op_ldst_lld(ctx); GEN_STORE_T0_REG(rt); opn = "lld"; break; case OPC_SD: GEN_LOAD_REG_T1(rt); op_ldst_sd(ctx); opn = "sd"; break; case OPC_SCD: save_cpu_state(ctx, 1); GEN_LOAD_REG_T1(rt); op_ldst_scd(ctx); GEN_STORE_T0_REG(rt); opn = "scd"; break; case OPC_LDL: GEN_LOAD_REG_T1(rt); op_ldst(ldl); GEN_STORE_T1_REG(rt); opn = "ldl"; break; case OPC_SDL: GEN_LOAD_REG_T1(rt); op_ldst(sdl); opn = "sdl"; break; case OPC_LDR: GEN_LOAD_REG_T1(rt); op_ldst(ldr); GEN_STORE_T1_REG(rt); opn = "ldr"; break; case OPC_SDR: GEN_LOAD_REG_T1(rt); op_ldst(sdr); opn = "sdr"; break;#endif case OPC_LW: op_ldst_lw(ctx); GEN_STORE_T0_REG(rt); opn = "lw"; break; case OPC_SW: GEN_LOAD_REG_T1(rt); op_ldst_sw(ctx); opn = "sw"; break; case OPC_LH: op_ldst_lh(ctx); GEN_STORE_T0_REG(rt); opn = "lh"; break; case OPC_SH: GEN_LOAD_REG_T1(rt); op_ldst_sh(ctx); opn = "sh"; break; case OPC_LHU: op_ldst_lhu(ctx); GEN_STORE_T0_REG(rt); opn = "lhu"; break; case OPC_LB: op_ldst_lb(ctx); GEN_STORE_T0_REG(rt); opn = "lb"; break; case OPC_SB: GEN_LOAD_REG_T1(rt); op_ldst_sb(ctx); opn = "sb"; break; case OPC_LBU: op_ldst_lbu(ctx); GEN_STORE_T0_REG(rt); opn = "lbu"; break; case OPC_LWL: GEN_LOAD_REG_T1(rt); op_ldst(lwl); GEN_STORE_T1_REG(rt); opn = "lwl"; break; case OPC_SWL: GEN_LOAD_REG_T1(rt); op_ldst(swl); opn = "swr"; break; case OPC_LWR: GEN_LOAD_REG_T1(rt); op_ldst(lwr); GEN_STORE_T1_REG(rt); opn = "lwr"; break; case OPC_SWR: GEN_LOAD_REG_T1(rt); op_ldst(swr); opn = "swr"; break; case OPC_LL: op_ldst_ll(ctx); GEN_STORE_T0_REG(rt); opn = "ll"; break; case OPC_SC: save_cpu_state(ctx, 1); GEN_LOAD_REG_T1(rt); op_ldst_sc(ctx); GEN_STORE_T0_REG(rt); opn = "sc"; break; default: MIPS_INVAL(opn); generate_exception(ctx, EXCP_RI); return; } MIPS_DEBUG("%s %s, %d(%s)", opn, regnames[rt], offset, regnames[base]);}/* Load and store */static void gen_flt_ldst (DisasContext *ctx, uint32_t opc, int ft, int base, int16_t offset){ const char *opn = "flt_ldst"; if (base == 0) { GEN_LOAD_IMM_TN(T0, offset); } else if (offset == 0) { gen_op_load_gpr_T0(base); } else { gen_op_load_gpr_T0(base); gen_op_set_T1(offset); gen_op_addr_add(); } /* Don't do NOP if destination is zero: we must perform the actual memory access. */ switch (opc) { case OPC_LWC1: op_ldst_lwc1(ctx); GEN_STORE_FTN_FREG(ft, WT0); opn = "lwc1"; break; case OPC_SWC1: GEN_LOAD_FREG_FTN(WT0, ft); op_ldst_swc1(ctx); opn = "swc1"; break; case OPC_LDC1: op_ldst_ldc1(ctx); GEN_STORE_FTN_FREG(ft, DT0); opn = "ldc1"; break; case OPC_SDC1: GEN_LOAD_FREG_FTN(DT0, ft); op_ldst_sdc1(ctx); opn = "sdc1"; break; default: MIPS_INVAL(opn); generate_exception(ctx, EXCP_RI); return; } MIPS_DEBUG("%s %s, %d(%s)", opn, fregnames[ft], offset, regnames[base]);}/* Arithmetic with immediate operand */static void gen_arith_imm (CPUState *env, DisasContext *ctx, uint32_t opc, int rt, int rs, int16_t imm){ target_ulong uimm; 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. */ MIPS_DEBUG("NOP"); return; } uimm = (uint16_t)imm; switch (opc) { case OPC_ADDI: case OPC_ADDIU:#if defined(TARGET_MIPS64) case OPC_DADDI: case OPC_DADDIU:#endif case OPC_SLTI: case OPC_SLTIU: uimm = (target_long)imm; /* Sign extend to 32/64 bits */ /* Fall through. */ case OPC_ANDI: case OPC_ORI: case OPC_XORI: GEN_LOAD_REG_T0(rs); GEN_LOAD_IMM_TN(T1, uimm); break; case OPC_LUI: GEN_LOAD_IMM_TN(T0, imm << 16); break; case OPC_SLL: case OPC_SRA: case OPC_SRL:#if defined(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_T0(rs); GEN_LOAD_IMM_TN(T1, uimm); break; } switch (opc) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?