예제 #1
0
파일: logical32.cpp 프로젝트: iver6/BA
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);
}
예제 #2
0
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);
}
예제 #3
0
파일: segment_ctrl.cpp 프로젝트: iver6/BA
// 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);
}
예제 #4
0
파일: logical32.cpp 프로젝트: iver6/BA
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);
}
예제 #5
0
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;
}
예제 #6
0
파일: fpu_compare.cpp 프로젝트: iver6/BA
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);
}
예제 #7
0
파일: stack64.cpp 프로젝트: iver6/BA
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);
}
예제 #8
0
파일: fpu_load_store.cpp 프로젝트: iver6/BA
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);
}
예제 #9
0
파일: avx.cpp 프로젝트: iver6/BA
/* 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);
}
예제 #10
0
파일: arith16.cpp 프로젝트: iver6/BA
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);
}
예제 #11
0
파일: fpu_load_store.cpp 프로젝트: iver6/BA
/* 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);
}
예제 #12
0
파일: arith8.cpp 프로젝트: iver6/BA
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);
}
예제 #13
0
파일: fpu_compare.cpp 프로젝트: iver6/BA
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);
}
예제 #14
0
파일: 3dnow.cpp 프로젝트: hack477/bochs4wii
/* 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);
}
예제 #15
0
파일: fpu_load_store.cpp 프로젝트: iver6/BA
/* 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);
}
예제 #16
0
파일: arith8.cpp 프로젝트: iver6/BA
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);
}
예제 #17
0
파일: arith16.cpp 프로젝트: iver6/BA
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);
}
예제 #18
0
파일: fpu_load_store.cpp 프로젝트: iver6/BA
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);
}
예제 #19
0
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()));
}
예제 #20
0
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());
}
예제 #21
0
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));
}
예제 #22
0
/* 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
}
예제 #23
0
/* 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
}
예제 #24
0
파일: fpu_load_store.cpp 프로젝트: iver6/BA
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);
}