?? translate.c
字號(hào):
if (insn & ARM_CP_RW_BIT) { gen_op_movl_T0_cp15(insn); /* If the destination register is r15 then sets condition codes. */ if (rd != 15) gen_movl_reg_T0(s, rd); } else { gen_movl_T0_reg(s, rd); gen_op_movl_cp15_T0(insn); /* Normally we would always end the TB here, but Linux * arch/arm/mach-pxa/sleep.S expects two instructions following * an MMU enable to execute from cache. Imitate this behaviour. */ if (!arm_feature(env, ARM_FEATURE_XSCALE) || (insn & 0x0fff0fff) != 0x0e010f10) gen_lookup_tb(s); } return 0;}#define VFP_REG_SHR(x, n) (((n) > 0) ? (x) >> (n) : (x) << -(n))#define VFP_SREG(insn, bigbit, smallbit) \ ((VFP_REG_SHR(insn, bigbit - 1) & 0x1e) | (((insn) >> (smallbit)) & 1))#define VFP_DREG(reg, insn, bigbit, smallbit) do { \ if (arm_feature(env, ARM_FEATURE_VFP3)) { \ reg = (((insn) >> (bigbit)) & 0x0f) \ | (((insn) >> ((smallbit) - 4)) & 0x10); \ } else { \ if (insn & (1 << (smallbit))) \ return 1; \ reg = ((insn) >> (bigbit)) & 0x0f; \ }} while (0)#define VFP_SREG_D(insn) VFP_SREG(insn, 12, 22)#define VFP_DREG_D(reg, insn) VFP_DREG(reg, insn, 12, 22)#define VFP_SREG_N(insn) VFP_SREG(insn, 16, 7)#define VFP_DREG_N(reg, insn) VFP_DREG(reg, insn, 16, 7)#define VFP_SREG_M(insn) VFP_SREG(insn, 0, 5)#define VFP_DREG_M(reg, insn) VFP_DREG(reg, insn, 0, 5)static inline intvfp_enabled(CPUState * env){ return ((env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30)) != 0);}/* Disassemble a VFP instruction. Returns nonzero if an error occured (ie. an undefined instruction). */static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn){ uint32_t rd, rn, rm, op, i, n, offset, delta_d, delta_m, bank_mask; int dp, veclen; if (!arm_feature(env, ARM_FEATURE_VFP)) return 1; if (!vfp_enabled(env)) { /* VFP disabled. Only allow fmxr/fmrx to/from some control regs. */ if ((insn & 0x0fe00fff) != 0x0ee00a10) return 1; rn = (insn >> 16) & 0xf; if (rn != ARM_VFP_FPSID && rn != ARM_VFP_FPEXC && rn != ARM_VFP_MVFR1 && rn != ARM_VFP_MVFR0) return 1; } dp = ((insn & 0xf00) == 0xb00); switch ((insn >> 24) & 0xf) { case 0xe: if (insn & (1 << 4)) { /* single register transfer */ rd = (insn >> 12) & 0xf; if (dp) { int size; int pass; VFP_DREG_N(rn, insn); if (insn & 0xf) return 1; if (insn & 0x00c00060 && !arm_feature(env, ARM_FEATURE_NEON)) return 1; pass = (insn >> 21) & 1; if (insn & (1 << 22)) { size = 0; offset = ((insn >> 5) & 3) * 8; } else if (insn & (1 << 5)) { size = 1; offset = (insn & (1 << 6)) ? 16 : 0; } else { size = 2; offset = 0; } if (insn & ARM_CP_RW_BIT) { /* vfp->arm */ switch (size) { case 0: NEON_GET_REG(T1, rn, pass); if (offset) gen_op_shrl_T1_im(offset); if (insn & (1 << 23)) gen_op_uxtb_T1(); else gen_op_sxtb_T1(); break; case 1: NEON_GET_REG(T1, rn, pass); if (insn & (1 << 23)) { if (offset) { gen_op_shrl_T1_im(16); } else { gen_op_uxth_T1(); } } else { if (offset) { gen_op_sarl_T1_im(16); } else { gen_op_sxth_T1(); } } break; case 2: NEON_GET_REG(T1, rn, pass); break; } gen_movl_reg_T1(s, rd); } else { /* arm->vfp */ gen_movl_T0_reg(s, rd); if (insn & (1 << 23)) { /* VDUP */ if (size == 0) { gen_op_neon_dup_u8(0); } else if (size == 1) { gen_op_neon_dup_low16(); } NEON_SET_REG(T0, rn, 0); NEON_SET_REG(T0, rn, 1); } else { /* VMOV */ switch (size) { case 0: NEON_GET_REG(T2, rn, pass); gen_op_movl_T1_im(0xff); gen_op_andl_T0_T1(); gen_op_neon_insert_elt(offset, ~(0xff << offset)); NEON_SET_REG(T2, rn, pass); break; case 1: NEON_GET_REG(T2, rn, pass); gen_op_movl_T1_im(0xffff); gen_op_andl_T0_T1(); bank_mask = offset ? 0xffff : 0xffff0000; gen_op_neon_insert_elt(offset, bank_mask); NEON_SET_REG(T2, rn, pass); break; case 2: NEON_SET_REG(T0, rn, pass); break; } } } } else { /* !dp */ if ((insn & 0x6f) != 0x00) return 1; rn = VFP_SREG_N(insn); if (insn & ARM_CP_RW_BIT) { /* vfp->arm */ if (insn & (1 << 21)) { /* system register */ rn >>= 1; switch (rn) { case ARM_VFP_FPSID: /* VFP2 allows access for FSID from userspace. VFP3 restricts all id registers to privileged accesses. */ if (IS_USER(s) && arm_feature(env, ARM_FEATURE_VFP3)) return 1; gen_op_vfp_movl_T0_xreg(rn); break; case ARM_VFP_FPEXC: if (IS_USER(s)) return 1; gen_op_vfp_movl_T0_xreg(rn); break; case ARM_VFP_FPINST: case ARM_VFP_FPINST2: /* Not present in VFP3. */ if (IS_USER(s) || arm_feature(env, ARM_FEATURE_VFP3)) return 1; gen_op_vfp_movl_T0_xreg(rn); break; case ARM_VFP_FPSCR: if (rd == 15) gen_op_vfp_movl_T0_fpscr_flags(); else gen_op_vfp_movl_T0_fpscr(); break; case ARM_VFP_MVFR0: case ARM_VFP_MVFR1: if (IS_USER(s) || !arm_feature(env, ARM_FEATURE_VFP3)) return 1; gen_op_vfp_movl_T0_xreg(rn); break; default: return 1; } } else { gen_mov_F0_vreg(0, rn); gen_op_vfp_mrs(); } if (rd == 15) { /* Set the 4 flag bits in the CPSR. */ gen_op_movl_cpsr_T0(0xf0000000); } else gen_movl_reg_T0(s, rd); } else { /* arm->vfp */ gen_movl_T0_reg(s, rd); if (insn & (1 << 21)) { rn >>= 1; /* system register */ switch (rn) { case ARM_VFP_FPSID: case ARM_VFP_MVFR0: case ARM_VFP_MVFR1: /* Writes are ignored. */ break; case ARM_VFP_FPSCR: gen_op_vfp_movl_fpscr_T0(); gen_lookup_tb(s); break; case ARM_VFP_FPEXC: if (IS_USER(s)) return 1; gen_op_vfp_movl_xreg_T0(rn); gen_lookup_tb(s); break; case ARM_VFP_FPINST: case ARM_VFP_FPINST2: gen_op_vfp_movl_xreg_T0(rn); break; default: return 1; } } else { gen_op_vfp_msr(); gen_mov_vreg_F0(0, rn); } } } } else { /* data processing */ /* The opcode is in bits 23, 21, 20 and 6. */ op = ((insn >> 20) & 8) | ((insn >> 19) & 6) | ((insn >> 6) & 1); if (dp) { if (op == 15) { /* rn is opcode */ rn = ((insn >> 15) & 0x1e) | ((insn >> 7) & 1); } else { /* rn is register number */ VFP_DREG_N(rn, insn); } if (op == 15 && (rn == 15 || rn > 17)) { /* Integer or single precision destination. */ rd = VFP_SREG_D(insn); } else { VFP_DREG_D(rd, insn); } if (op == 15 && (rn == 16 || rn == 17)) { /* Integer source. */ rm = ((insn << 1) & 0x1e) | ((insn >> 5) & 1); } else { VFP_DREG_M(rm, insn); } } else { rn = VFP_SREG_N(insn); if (op == 15 && rn == 15) { /* Double precision destination. */ VFP_DREG_D(rd, insn); } else { rd = VFP_SREG_D(insn); } rm = VFP_SREG_M(insn); } veclen = env->vfp.vec_len; if (op == 15 && rn > 3) veclen = 0; /* Shut up compiler warnings. */ delta_m = 0; delta_d = 0; bank_mask = 0; if (veclen > 0) { if (dp) bank_mask = 0xc; else bank_mask = 0x18; /* Figure out what type of vector operation this is. */ if ((rd & bank_mask) == 0) { /* scalar */ veclen = 0; } else { if (dp) delta_d = (env->vfp.vec_stride >> 1) + 1; else delta_d = env->vfp.vec_stride + 1; if ((rm & bank_mask) == 0) { /* mixed scalar/vector */ delta_m = 0; } else { /* vector */ delta_m = delta_d; } } } /* Load the initial operands. */ if (op == 15) { switch (rn) { case 16: case 17: /* Integer source */ gen_mov_F0_vreg(0, rm); break; case 8: case 9: /* Compare */ gen_mov_F0_vreg(dp, rd); gen_mov_F1_vreg(dp, rm); break; case 10: case 11: /* Compare with zero */ gen_mov_F0_vreg(dp, rd); gen_vfp_F1_ld0(dp); break; case 20: case 21: case 22: case 23: /* Source and destination the same. */ gen_mov_F0_vreg(dp, rd); break; default: /* One source operand. */ gen_mov_F0_vreg(dp, rm); break; } } else { /* Two source operands. */ gen_mov_F0_vreg(dp, rn); gen_mov_F1_vreg(dp, rm); } for (;;) { /* Perform the calculation. */ switch (op) { case 0: /* mac: fd + (fn * fm) */ gen_vfp_mul(dp); gen_mov_F1_vreg(dp, rd); gen_vfp_add(dp); break; case 1: /* nmac: fd - (fn * fm) */ gen_vfp_mul(dp); gen_vfp_neg(dp); gen_mov_F1_vreg(dp, rd); gen_vfp_add(dp); break; case 2: /* msc: -fd + (fn * fm) */ gen_vfp_mul(dp); gen_mov_F1_vreg(dp, rd); gen_vfp_sub(dp); break; case 3: /* nmsc: -fd - (fn * fm) */ gen_vfp_mul(dp); gen_mov_F1_vreg(dp, rd); gen_vfp_add(dp); gen_vfp_neg(dp); break; case 4: /* mul: fn * fm */ gen_vfp_mul(dp); break; case 5: /* nmul: -(fn * fm) */ gen_vfp_mul(dp); gen_vfp_neg(dp); break; case 6: /* add: fn + fm */ gen_vfp_add(dp); break; case 7: /* sub: fn - fm */ gen_vfp_sub(dp); break; case 8: /* div: fn / fm */ gen_vfp_div(dp); break; case 14: /* fconst */ if (!arm_feature(env, ARM_FEATURE_VFP3)) return 1; n = (insn << 12) & 0x80000000; i = ((insn >> 12) & 0x70) | (insn & 0xf); if (dp) { if (i & 0x40) i |= 0x3f80; else i |= 0x4000; n |= i << 16; } else { if (i & 0x40) i |= 0x780; else i |= 0x800; n |= i << 19; } gen_vfp_fconst(dp, n); break; case 15: /* extension space */ switch (rn) { case 0: /* cpy */ /* no-op */ break; case 1: /* abs */ gen_vfp_abs(dp);
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -