BX_INSF_TYPE BX_CPP_AttrRegparmN(1) BX_CPU_C::OR_EdIdM(bxInstruction_c *i) { Bit32u op1_32; bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i)); op1_32 = read_RMW_virtual_dword(i->seg(), eaddr); op1_32 |= i->Id(); write_RMW_virtual_dword(op1_32); SET_FLAGS_OSZAPC_LOGIC_32(op1_32); BX_NEXT_INSTR(i); }
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XOR_GqEqM(bxInstruction_c *i) { Bit64u op1_64, op2_64; BX_CPU_CALL_METHODR(i->ResolveModrm, (i)); op1_64 = BX_READ_64BIT_REG(i->nnn()); op2_64 = read_virtual_qword_64(i->seg(), RMAddr(i)); op1_64 ^= op2_64; /* now write result back to destination */ BX_WRITE_64BIT_REG(i->nnn(), op1_64); SET_FLAGS_OSZAPC_LOGIC_64(op1_64); }
// LES/LDS can't be called from long64 mode BX_INSF_TYPE BX_CPP_AttrRegparmN(1) BX_CPU_C::LDS_GdMp(bxInstruction_c *i) { BX_ASSERT(BX_CPU_THIS_PTR cpu_mode != BX_MODE_LONG_64); Bit32u eaddr = (Bit32u) BX_CPU_CALL_METHODR(i->ResolveModrm, (i)); Bit16u ds = read_virtual_word_32(i->seg(), (eaddr + 4) & i->asize_mask()); Bit32u reg_32 = read_virtual_dword_32(i->seg(), eaddr); load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS], ds); BX_WRITE_32BIT_REGZ(i->nnn(), reg_32); BX_NEXT_INSTR(i); }
BX_INSF_TYPE BX_CPP_AttrRegparmN(1) BX_CPU_C::XOR_EdGdM(bxInstruction_c *i) { Bit32u op1_32, op2_32; bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i)); op1_32 = read_RMW_virtual_dword(i->seg(), eaddr); op2_32 = BX_READ_32BIT_REG(i->nnn()); op1_32 ^= op2_32; write_RMW_virtual_dword(op1_32); SET_FLAGS_OSZAPC_LOGIC_32(op1_32); BX_NEXT_INSTR(i); }
void BX_CPP_AttrRegparmN(1) BX_CPU_C::POP_EdM(bxInstruction_c *i) { BX_CPU_THIS_PTR speculative_rsp = 1; BX_CPU_THIS_PTR prev_rsp = RSP; Bit32u val32 = pop_32(); // Note: there is one little weirdism here. It is possible to use // ESP in the modrm addressing. If used, the value of ESP after the // pop is used to calculate the address. BX_CPU_CALL_METHODR (i->ResolveModrm, (i)); write_virtual_dword(i->seg(), RMAddr(i), val32); BX_CPU_THIS_PTR speculative_rsp = 0; }
BX_INSF_TYPE BX_CPP_AttrRegparmN(1) BX_CPU_C::FCOM_DOUBLE_REAL(bxInstruction_c *i) { BX_CPU_THIS_PTR prepareFPU(i); int pop_stack = i->nnn() & 1, rc; RMAddr(i) = BX_CPU_CALL_METHODR(i->ResolveModrm, (i)); float64 load_reg = read_virtual_qword(i->seg(), RMAddr(i)); BX_CPU_THIS_PTR FPU_update_last_instruction(i); clear_C1(); if (IS_TAG_EMPTY(0)) { FPU_exception(FPU_EX_Stack_Underflow); setcc(FPU_SW_C0|FPU_SW_C2|FPU_SW_C3); if(BX_CPU_THIS_PTR the_i387.is_IA_masked()) { if (pop_stack) BX_CPU_THIS_PTR the_i387.FPU_pop(); } BX_NEXT_INSTR(i); } float_status_t status = FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387.get_control_word()); floatx80 a = BX_READ_FPU_REG(0); if (floatx80_is_nan(a) || floatx80_is_unsupported(a) || float64_is_nan(load_reg)) { rc = float_relation_unordered; float_raise(status, float_flag_invalid); } else { rc = floatx80_compare(a, float64_to_floatx80(load_reg, status), status); } setcc(status_word_flags_fpu_compare(rc)); if (! FPU_exception(status.float_exception_flags)) { if (pop_stack) BX_CPU_THIS_PTR the_i387.FPU_pop(); } BX_NEXT_INSTR(i); }
BX_INSF_TYPE BX_CPP_AttrRegparmN(1) BX_CPU_C::POP_EqM(bxInstruction_c *i) { RSP_SPECULATIVE; Bit64u val64 = pop_64(); // Note: there is one little weirdism here. It is possible to use // RSP in the modrm addressing. If used, the value of RSP after the // pop is used to calculate the address. bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i)); write_virtual_qword_64(i->seg(), eaddr, val64); RSP_COMMIT; BX_NEXT_INSTR(i); }
BX_INSF_TYPE BX_CPP_AttrRegparmN(1) BX_CPU_C::FIST_DWORD_INTEGER(bxInstruction_c *i) { BX_CPU_THIS_PTR prepareFPU(i); RMAddr(i) = BX_CPU_CALL_METHODR(i->ResolveModrm, (i)); FPU_update_last_instruction(i); Bit16u x87_sw = FPU_PARTIAL_STATUS; Bit32s save_reg = int32_indefinite; /* The masked response */ int pop_stack = i->nnn() & 1; clear_C1(); if (IS_TAG_EMPTY(0)) { FPU_exception(FPU_EX_Stack_Underflow); if (! BX_CPU_THIS_PTR the_i387.is_IA_masked()) BX_NEXT_INSTR(i); } else { float_status_t status = FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387.get_control_word()); save_reg = floatx80_to_int32(BX_READ_FPU_REG(0), status); if (FPU_exception(status.float_exception_flags, 1)) BX_NEXT_INSTR(i); } // store to the memory might generate an exception, in this case origial FPU_SW must be kept swap_values16u(x87_sw, FPU_PARTIAL_STATUS); write_virtual_dword(i->seg(), RMAddr(i), (Bit32u)(save_reg)); FPU_PARTIAL_STATUS = x87_sw; if (pop_stack) BX_CPU_THIS_PTR the_i387.FPU_pop(); BX_NEXT_INSTR(i); }
/* Opcode: VEX.256.66.0F.38.1A (VEX.W=0, VEX.VVV #UD) */ BX_INSF_TYPE BX_CPP_AttrRegparmN(1) BX_CPU_C::VBROADCASTF128_VdqMdq(bxInstruction_c *i) { unsigned len = i->getVL(); BxPackedAvxRegister op; BxPackedXmmRegister src; bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i)); read_virtual_dqword(i->seg(), eaddr, (Bit8u*) &src); for (unsigned n=0; n < len; n++) { op.avx64u(n*2) = src.xmm64u(0); op.avx64u(n*2+1) = src.xmm64u(1); } BX_WRITE_AVX_REGZ(i->nnn(), op, len); BX_NEXT_INSTR(i); }
BX_INSF_TYPE BX_CPP_AttrRegparmN(1) BX_CPU_C::CMPXCHG_EwGwM(bxInstruction_c *i) { bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i)); Bit16u op1_16 = read_RMW_virtual_word(i->seg(), eaddr); Bit16u diff_16 = AX - op1_16; SET_FLAGS_OSZAPC_SUB_16(AX, op1_16, diff_16); if (diff_16 == 0) { // if accumulator == dest // dest <-- src write_RMW_virtual_word(BX_READ_16BIT_REG(i->nnn())); } else { // accumulator <-- dest AX = op1_16; } BX_NEXT_INSTR(i); }
/* DF /4 */ BX_INSF_TYPE BX_CPP_AttrRegparmN(1) BX_CPU_C::FBLD_PACKED_BCD(bxInstruction_c *i) { BX_CPU_THIS_PTR prepareFPU(i); RMAddr(i) = BX_CPU_CALL_METHODR(i->ResolveModrm, (i)); Bit16u hi2 = read_virtual_word(i->seg(), (RMAddr(i) + 8) & i->asize_mask()); Bit64u lo8 = read_virtual_qword(i->seg(), RMAddr(i)); FPU_update_last_instruction(i); clear_C1(); if (! IS_TAG_EMPTY(-1)) { FPU_stack_overflow(); BX_NEXT_INSTR(i); } // convert packed BCD to 64-bit integer Bit64s scale = 1; Bit64s val64 = 0; for (int n = 0; n < 16; n++) { val64 += (lo8 & 0x0f) * scale; lo8 >>= 4; scale *= 10; } val64 += (hi2 & 0x0f) * scale; val64 += ((hi2>>4) & 0x0f) * scale * 10; floatx80 result = int64_to_floatx80(val64); if (hi2 & 0x8000) // set negative floatx80_chs(result); BX_CPU_THIS_PTR the_i387.FPU_push(); BX_WRITE_FPU_REG(result, 0); BX_NEXT_INSTR(i); }
BX_INSF_TYPE BX_CPP_AttrRegparmN(1) BX_CPU_C::CMPXCHG_EbGbM(bxInstruction_c *i) { bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i)); Bit32u op1_8 = read_RMW_virtual_byte(i->seg(), eaddr); Bit32u diff_8 = AL - op1_8; SET_FLAGS_OSZAPC_SUB_8(AL, op1_8, diff_8); if (diff_8 == 0) { // if accumulator == dest // dest <-- src Bit32u op2_8 = BX_READ_8BIT_REGx(i->nnn(), i->extend8bitL()); write_RMW_virtual_byte(op2_8); } else { // accumulator <-- dest AL = op1_8; } BX_NEXT_INSTR(i); }
BX_INSF_TYPE BX_CPP_AttrRegparmN(1) BX_CPU_C::FICOM_WORD_INTEGER(bxInstruction_c *i) { BX_CPU_THIS_PTR prepareFPU(i); int pop_stack = i->nnn() & 1; RMAddr(i) = BX_CPU_CALL_METHODR(i->ResolveModrm, (i)); Bit16s load_reg = (Bit16s) read_virtual_word(i->seg(), RMAddr(i)); BX_CPU_THIS_PTR FPU_update_last_instruction(i); clear_C1(); if (IS_TAG_EMPTY(0)) { FPU_exception(FPU_EX_Stack_Underflow); setcc(FPU_SW_C0|FPU_SW_C2|FPU_SW_C3); if(BX_CPU_THIS_PTR the_i387.is_IA_masked()) { if (pop_stack) BX_CPU_THIS_PTR the_i387.FPU_pop(); } BX_NEXT_INSTR(i); } float_status_t status = FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387.get_control_word()); int rc = floatx80_compare(BX_READ_FPU_REG(0), int32_to_floatx80((Bit32s)(load_reg)), status); setcc(status_word_flags_fpu_compare(rc)); if (! FPU_exception(status.float_exception_flags)) { if (pop_stack) BX_CPU_THIS_PTR the_i387.FPU_pop(); } BX_NEXT_INSTR(i); }
/* 0F 0F /r BB */ void BX_CPP_AttrRegparmN(1) BX_CPU_C::PSWAPD_PqQq(bxInstruction_c *i) { BX_CPU_THIS_PTR prepareMMX(); BxPackedMmxRegister result, op; /* op is a register or memory reference */ if (i->modC0()) { op = BX_READ_MMX_REG(i->rm()); } else { BX_CPU_CALL_METHODR(i->ResolveModrm, (i)); /* pointer, segment address pair */ MMXUQ(op) = read_virtual_qword(i->seg(), RMAddr(i)); } MMXUD0(result) = MMXUD1(op); MMXUD1(result) = MMXUD0(op); /* now write result back to destination */ BX_WRITE_MMX_REG(i->nnn(), result); }
/* DF /5 */ BX_INSF_TYPE BX_CPP_AttrRegparmN(1) BX_CPU_C::FILD_QWORD_INTEGER(bxInstruction_c *i) { BX_CPU_THIS_PTR prepareFPU(i); RMAddr(i) = BX_CPU_CALL_METHODR(i->ResolveModrm, (i)); Bit64s load_reg = (Bit64s) read_virtual_qword(i->seg(), RMAddr(i)); FPU_update_last_instruction(i); clear_C1(); if (! IS_TAG_EMPTY(-1)) { FPU_stack_overflow(); } else { floatx80 result = int64_to_floatx80(load_reg); BX_CPU_THIS_PTR the_i387.FPU_push(); BX_WRITE_FPU_REG(result, 0); } BX_NEXT_INSTR(i); }
BX_INSF_TYPE BX_CPP_AttrRegparmN(1) BX_CPU_C::XADD_EbGbM(bxInstruction_c *i) { /* XADD dst(r/m8), src(r8) * temp <-- src + dst | sum = op2 + op1 * src <-- dst | op2 = op1 * dst <-- tmp | op1 = sum */ bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i)); Bit32u op1 = read_RMW_virtual_byte(i->seg(), eaddr); Bit32u op2 = BX_READ_8BIT_REGx(i->nnn(), i->extend8bitL()); Bit32u sum = op1 + op2; write_RMW_virtual_byte(sum); /* and write destination into source */ BX_WRITE_8BIT_REGx(i->nnn(), i->extend8bitL(), op1); SET_FLAGS_OSZAPC_ADD_8(op1, op2, sum); BX_NEXT_INSTR(i); }
BX_INSF_TYPE BX_CPP_AttrRegparmN(1) BX_CPU_C::XADD_EwGwM(bxInstruction_c *i) { /* XADD dst(r/m), src(r) * temp <-- src + dst | sum = op2 + op1 * src <-- dst | op2 = op1 * dst <-- tmp | op1 = sum */ bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i)); Bit32u op1_16 = read_RMW_virtual_word(i->seg(), eaddr); Bit32u op2_16 = BX_READ_16BIT_REG(i->nnn()); Bit32u sum_16 = op1_16 + op2_16; write_RMW_virtual_word(sum_16); /* and write destination into source */ BX_WRITE_16BIT_REG(i->nnn(), op1_16); SET_FLAGS_OSZAPC_ADD_16(op1_16, op2_16, sum_16); BX_NEXT_INSTR(i); }
BX_INSF_TYPE BX_CPP_AttrRegparmN(1) BX_CPU_C::FLD_EXTENDED_REAL(bxInstruction_c *i) { BX_CPU_THIS_PTR prepareFPU(i); floatx80 result; RMAddr(i) = BX_CPU_CALL_METHODR(i->ResolveModrm, (i)); result.fraction = read_virtual_qword(i->seg(), RMAddr(i)); result.exp = read_virtual_word(i->seg(), (RMAddr(i)+8) & i->asize_mask()); FPU_update_last_instruction(i); clear_C1(); if (! IS_TAG_EMPTY(-1)) { FPU_stack_overflow(); } else { BX_CPU_THIS_PTR the_i387.FPU_push(); BX_WRITE_FPU_REG(result, 0); } BX_NEXT_INSTR(i); }
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_EwGwM(bxInstruction_c *i) { BX_CPU_CALL_METHODR(i->ResolveModrm, (i)); write_virtual_word(i->seg(), RMAddr(i), BX_READ_16BIT_REG(i->nnn())); }
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_EwIwM(bxInstruction_c *i) { BX_CPU_CALL_METHODR(i->ResolveModrm, (i)); write_virtual_word(i->seg(), RMAddr(i), i->Iw()); }
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LEA_GwM(bxInstruction_c *i) { BX_CPU_CALL_METHODR(i->ResolveModrm, (i)); BX_WRITE_16BIT_REG(i->nnn(), (Bit16u) RMAddr(i)); }
/* 66 0F 3A 60 */ void BX_CPP_AttrRegparmN(1) BX_CPU_C::PCMPESTRM_VdqWdqIb(bxInstruction_c *i) { #if (BX_SUPPORT_SSE >= 5) || (BX_SUPPORT_SSE >= 4 && BX_SUPPORT_SSE_EXTENSION > 0) BX_CPU_THIS_PTR prepareSSE(); BxPackedXmmRegister op1 = BX_READ_XMM_REG(i->nnn()), op2, result; Bit8u imm8 = i->Ib(); /* op2 is a register or memory reference */ if (i->modC0()) { op2 = BX_READ_XMM_REG(i->rm()); } else { BX_CPU_CALL_METHODR(i->ResolveModrm, (i)); /* pointer, segment address pair */ readVirtualDQwordAligned(i->seg(), RMAddr(i), (Bit8u *) &op2); } // compare all pairs of Ai, Bj bx_bool BoolRes[16][16]; compare_strings(BoolRes, op1, op2, imm8); unsigned len1, len2, num_elements = (imm8 & 0x1) ? 8 : 16; #if BX_SUPPORT_X86_64 if (i->os64L()) { len1 = find_eos64(RAX, imm8); len2 = find_eos64(RDX, imm8); } else #endif { len1 = find_eos32(EAX, imm8); len2 = find_eos32(EDX, imm8); } Bit16u result2 = aggregate(BoolRes, len1, len2, imm8); // As defined by imm8[6], result2 is then either stored to the least // significant bits of XMM0 (zero extended to 128 bits) or expanded // into a byte/word-mask and then stored to XMM0 if (imm8 & 0x40) { if (num_elements == 8) { for (int index = 0; index < 8; index++) result.xmm16u(index) = (result2 & (1<<index)) ? 0xffff : 0; } else { // num_elements = 16 for (int index = 0; index < 16; index++) result.xmmubyte(index) = (result2 & (1<<index)) ? 0xff : 0; } } else { result.xmm64u(1) = 0; result.xmm64u(0) = (Bit64u) result2; } Bit32u flags = 0; if (result2 != 0) flags |= EFlagsCFMask; if (len1 < num_elements) flags |= EFlagsSFMask; if (len2 < num_elements) flags |= EFlagsZFMask; if (result2 & 0x1) flags |= EFlagsOFMask; setEFlagsOSZAPC(flags); BX_WRITE_XMM_REG(0, result); /* store result XMM0 */ #else BX_INFO(("PCMPESTRM_VdqWdqIb: required SSE4.2, use --enable-sse and --enable-sse-extension options")); UndefinedOpcode(i); #endif }
/* 66 0F 3A 61 */ void BX_CPP_AttrRegparmN(1) BX_CPU_C::PCMPESTRI_VdqWdqIb(bxInstruction_c *i) { #if (BX_SUPPORT_SSE >= 5) || (BX_SUPPORT_SSE >= 4 && BX_SUPPORT_SSE_EXTENSION > 0) BX_CPU_THIS_PTR prepareSSE(); BxPackedXmmRegister op1 = BX_READ_XMM_REG(i->nnn()), op2; Bit8u imm8 = i->Ib(); /* op2 is a register or memory reference */ if (i->modC0()) { op2 = BX_READ_XMM_REG(i->rm()); } else { BX_CPU_CALL_METHODR(i->ResolveModrm, (i)); /* pointer, segment address pair */ readVirtualDQwordAligned(i->seg(), RMAddr(i), (Bit8u *) &op2); } // compare all pairs of Ai, Bj bx_bool BoolRes[16][16]; compare_strings(BoolRes, op1, op2, imm8); unsigned len1, len2, num_elements = (imm8 & 0x1) ? 8 : 16; int index; #if BX_SUPPORT_X86_64 if (i->os64L()) { len1 = find_eos64(RAX, imm8); len2 = find_eos64(RDX, imm8); } else #endif { len1 = find_eos32(EAX, imm8); len2 = find_eos32(EDX, imm8); } Bit16u result2 = aggregate(BoolRes, len1, len2, imm8); // The index of the first (or last, according to imm8[6]) set bit of result2 // is returned to ECX. If no bits are set in IntRes2, ECX is set to 16 (8) if (imm8 & 0x40) { // The index returned to ECX is of the MSB in result2 for (index=num_elements-1; index>=0; index--) if (result2 & (1<<index)) break; if (index < 0) index = num_elements; } else { // The index returned to ECX is of the LSB in result2 for (index=0; index<(int)num_elements; index++) if (result2 & (1<<index)) break; } RCX = index; Bit32u flags = 0; if (result2 != 0) flags |= EFlagsCFMask; if (len1 < num_elements) flags |= EFlagsSFMask; if (len2 < num_elements) flags |= EFlagsZFMask; if (result2 & 0x1) flags |= EFlagsOFMask; setEFlagsOSZAPC(flags); #else BX_INFO(("PCMPESTRI_VdqWdqIb: required SSE4.2, use --enable-sse and --enable-sse-extension options")); UndefinedOpcode(i); #endif }
BX_INSF_TYPE BX_CPP_AttrRegparmN(1) BX_CPU_C::FBSTP_PACKED_BCD(bxInstruction_c *i) { BX_CPU_THIS_PTR prepareFPU(i); RMAddr(i) = BX_CPU_CALL_METHODR(i->ResolveModrm, (i)); FPU_update_last_instruction(i); Bit16u x87_sw = FPU_PARTIAL_STATUS; /* * The packed BCD integer indefinite encoding (FFFFC000000000000000H) * is stored in response to a masked floating-point invalid-operation * exception. */ Bit16u save_reg_hi = 0xFFFF; Bit64u save_reg_lo = BX_CONST64(0xC000000000000000); clear_C1(); if (IS_TAG_EMPTY(0)) { FPU_exception(FPU_EX_Stack_Underflow); if (! BX_CPU_THIS_PTR the_i387.is_IA_masked()) BX_NEXT_INSTR(i); } else { float_status_t status = FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387.get_control_word()); floatx80 reg = BX_READ_FPU_REG(0); Bit64s save_val = floatx80_to_int64(reg, status); int sign = (reg.exp & 0x8000) != 0; if (sign) save_val = -save_val; if (save_val > BX_CONST64(999999999999999999)) { status.float_exception_flags = float_flag_invalid; // throw away other flags } if (! (status.float_exception_flags & float_flag_invalid)) { save_reg_hi = (sign) ? 0x8000 : 0; save_reg_lo = 0; for (int i=0; i<16; i++) { save_reg_lo += ((Bit64u)(save_val % 10)) << (4*i); save_val /= 10; } save_reg_hi += (Bit16u)(save_val % 10); save_val /= 10; save_reg_hi += (Bit16u)(save_val % 10) << 4; } /* check for fpu arithmetic exceptions */ if (FPU_exception(status.float_exception_flags, 1)) BX_NEXT_INSTR(i); } // store to the memory might generate an exception, in this case origial FPU_SW must be kept swap_values16u(x87_sw, FPU_PARTIAL_STATUS); // write packed bcd to memory write_virtual_qword(i->seg(), RMAddr(i), save_reg_lo); write_virtual_word(i->seg(), (RMAddr(i) + 8) & i->asize_mask(), save_reg_hi); FPU_PARTIAL_STATUS = x87_sw; BX_CPU_THIS_PTR the_i387.FPU_pop(); BX_NEXT_INSTR(i); }