From dfe0bdd7f2da46f80047bb2011c0270c92513505 Mon Sep 17 00:00:00 2001 From: Alyssa Rosenzweig Date: Mon, 25 Mar 2024 19:14:08 -0400 Subject: [PATCH] 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 --- .../Interface/Core/OpcodeDispatcher.cpp | 81 +++++-------------- 1 file changed, 18 insertions(+), 63 deletions(-) diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp b/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp index 183cd5121..bcd40404a 100644 --- a/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp +++ b/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp @@ -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(_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(_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(_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(_Constant(1)); - CalculateDeferredFlags(); - Jump(EndBlock); - } - SetCurrentCodeBlock(EndBlock); - StartNewBlock(); - // Update Flags - AL = LoadGPRRegister(X86State::REG_RAX, 1); - SetRFLAG(_Select(FEXCore::IR::COND_UGE, _And(OpSize::i64Bit, AL, _Constant(0x80)), _Constant(0), _Constant(1), _Constant(0))); - SetRFLAG(_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(NewCF); CalculatePF(AL); - FixupAF(); + SetAFAndFixup(AF); } void OpDispatchBuilder::AAAOp(OpcodeArgs) {