OpcodeDispatcher: rewrite DAS

exhaustively checked against the Intel pseudocode since this is tricky:

  def intel(AL, CF, AF):
      old_AL = AL
      old_CF = CF
      CF = False

      if (AL & 0x0F) > 9 or AF:
          Borrow = AL < 6
          AL = (AL - 6) & 0xff
          CF = old_CF or Borrow
          AF = True
      else:
          AF = False

      if (old_AL > 0x99) or old_CF:
          AL = (AL - 0x60) & 0xff
          CF = True

      return (AL & 0xff, CF, AF)

  def fex(AL, CF, AF):
      AF = AF | ((AL & 0xf) > 9)
      CF = CF | (AL > 0x99)
      NewCF = CF | (AF if (AL < 6) else CF)
      AL = (AL - 6) if AF else AL
      AL = (AL - 0x60) if CF else AL
      return (AL & 0xff, NewCF, AF)

  for AL in range(256):
      for CF in [False, True]:
          for AF in [False, True]:
              ref = intel(AL, CF, AF)
              test = fex(AL, CF, AF)
              print(AL, "CF" if CF else "", "AF" if AF else "", ref, test)
              assert(ref == test)

Signed-off-by: Alyssa Rosenzweig <alyssa@rosenzweig.io>
This commit is contained in:
Alyssa Rosenzweig committed 2024-03-25 19:43:10 -04:00
1 parent e26481e3cc
commit dfe0bdd7f2
1 file changed
+18 -63
@@ -3152,75 +3152,30 @@ void OpDispatchBuilder::DAAOp(OpcodeArgs) {
void OpDispatchBuilder::DASOp(OpcodeArgs) {
CalculateDeferredFlags();
auto CF = GetRFLAG(FEXCore::X86State::RFLAG_CF_RAW_LOC);
auto AF = LoadAF();
auto AL = LoadGPRRegister(X86State::REG_RAX, 1);
auto CF = GetRFLAG(FEXCore::X86State::RFLAG_CF_RAW_LOC);
auto AF = CalculateAFForDecimal(AL);
SetRFLAG<FEXCore::X86State::RFLAG_CF_RAW_LOC>(_Constant(0));
CalculateDeferredFlags();
// CF |= (AL > 0x99);
CF = _Or(OpSize::i64Bit, CF, _Select(FEXCore::IR::COND_UGT, AL, _Constant(0x99), _Constant(1), _Constant(0)));
auto Cond = _Or(OpSize::i64Bit, AF, _Select(FEXCore::IR::COND_UGT, _And(OpSize::i64Bit, AL, _Constant(0xf)), _Constant(9), _Constant(1), _Constant(0)));
auto FalseBlock = CreateNewCodeBlockAfter(GetCurrentBlock());
auto TrueBlock = CreateNewCodeBlockAfter(FalseBlock);
auto EndBlock = CreateNewCodeBlockAfter(TrueBlock);
// NewCF = CF | (AF && (Borrow from AL - 6))
auto NewCF = _Or(OpSize::i32Bit, CF, _Select(FEXCore::IR::COND_ULT, AL, _Constant(6), AF, CF));
CalculateDeferredFlags();
CondJump(Cond, TrueBlock, FalseBlock);
SetCurrentCodeBlock(FalseBlock);
StartNewBlock();
{
SetAF(0);
Jump(EndBlock);
}
SetCurrentCodeBlock(TrueBlock);
StartNewBlock();
{
auto NewAL = _Sub(OpSize::i64Bit, AL, _Constant(0x6));
StoreGPRRegister(X86State::REG_RAX, NewAL, 1);
CalculateDeferredFlags();
auto NewCF = GetRFLAG(FEXCore::X86State::RFLAG_CF_RAW_LOC);
// XXX: I don't think this is correct. Needs Investigation.
// The `CF` variable is the original CF from the start of the operation
// The `NewCF` will be _Constant(0) stored aboved.
// So Or(CF, _Constant(0)) ill mean CF gets updated to the old value in the true case?
SetRFLAG<FEXCore::X86State::RFLAG_CF_RAW_LOC>(_Or(OpSize::i64Bit, CF, NewCF));
SetAF(1);
CalculateDeferredFlags();
Jump(EndBlock);
}
SetCurrentCodeBlock(EndBlock);
StartNewBlock();
// AL = AF ? (AL - 0x6) : AL;
AL = _Select(FEXCore::IR::COND_NEQ, AF, _Constant(0),
_Sub(OpSize::i64Bit, AL, _Constant(0x6)), AL);
Cond = _Or(OpSize::i64Bit, CF, _Select(FEXCore::IR::COND_UGT, AL, _Constant(0x99), _Constant(1), _Constant(0)));
FalseBlock = CreateNewCodeBlockAfter(GetCurrentBlock());
TrueBlock = CreateNewCodeBlockAfter(FalseBlock);
EndBlock = CreateNewCodeBlockAfter(TrueBlock);
CondJump(Cond, TrueBlock, FalseBlock);
SetCurrentCodeBlock(FalseBlock);
StartNewBlock();
{
SetRFLAG<FEXCore::X86State::RFLAG_CF_RAW_LOC>(_Constant(0));
CalculateDeferredFlags();
Jump(EndBlock);
}
SetCurrentCodeBlock(TrueBlock);
StartNewBlock();
{
AL = LoadGPRRegister(X86State::REG_RAX, 1);
auto NewAL = _Sub(OpSize::i64Bit, AL, _Constant(0x60));
StoreGPRRegister(X86State::REG_RAX, NewAL, 1);
SetRFLAG<FEXCore::X86State::RFLAG_CF_RAW_LOC>(_Constant(1));
CalculateDeferredFlags();
Jump(EndBlock);
}
SetCurrentCodeBlock(EndBlock);
StartNewBlock();
// Update Flags
AL = LoadGPRRegister(X86State::REG_RAX, 1);
SetRFLAG<FEXCore::X86State::RFLAG_SF_RAW_LOC>(_Select(FEXCore::IR::COND_UGE, _And(OpSize::i64Bit, AL, _Constant(0x80)), _Constant(0), _Constant(1), _Constant(0)));
SetRFLAG<FEXCore::X86State::RFLAG_ZF_RAW_LOC>(_Select(FEXCore::IR::COND_EQ, _And(OpSize::i64Bit, AL, _Constant(0xFF)), _Constant(0), _Constant(1), _Constant(0)));
// AL = CF ? (AL - 0x60) : AL;
AL = _Select(FEXCore::IR::COND_NEQ, CF, _Constant(0),
_Sub(OpSize::i64Bit, AL, _Constant(0x60)), AL);
// SF, ZF, PF set according to result. CF set per above. OF undefined.
StoreGPRRegister(X86State::REG_RAX, AL, 1);
SetNZ_ZeroCV(1, AL);
SetRFLAG<FEXCore::X86State::RFLAG_CF_RAW_LOC>(NewCF);
CalculatePF(AL);
FixupAF();
SetAFAndFixup(AF);
}
void OpDispatchBuilder::AAAOp(OpcodeArgs) {