mirror of
https://github.com/TomHarte/CLK.git
synced 2025-04-09 00:37:27 +00:00
Merge pull request #1200 from TomHarte/MoreDAA
Correct 8086 DAA and DAS; unify those and AAA/AAS.
This commit is contained in:
commit
bf179e8933
@ -15,34 +15,21 @@
|
||||
|
||||
namespace InstructionSet::x86::Primitive {
|
||||
|
||||
template <typename ContextT>
|
||||
void aaa(
|
||||
/// If @c add is @c true, performs an AAA; otherwise perfoms an AAS.
|
||||
template <bool add, typename ContextT>
|
||||
void aaas(
|
||||
CPU::RegisterPair16 &ax,
|
||||
ContextT &context
|
||||
) { // P. 313
|
||||
/*
|
||||
IF ((AL AND 0FH) > 9) OR (AF = 1)
|
||||
THEN
|
||||
AL ← (AL + 6);
|
||||
AH ← AH + 1;
|
||||
AF ← 1;
|
||||
CF ← 1;
|
||||
ELSE
|
||||
AF ← 0;
|
||||
CF ← 0;
|
||||
FI;
|
||||
AL ← AL AND 0FH;
|
||||
*/
|
||||
/*
|
||||
The AF and CF flags are set to 1 if the adjustment results in a decimal carry;
|
||||
otherwise they are cleared to 0. The OF, SF, ZF, and PF flags are undefined.
|
||||
*/
|
||||
) {
|
||||
if((ax.halves.low & 0x0f) > 9 || context.flags.template flag<Flag::AuxiliaryCarry>()) {
|
||||
ax.halves.low += 6;
|
||||
++ax.halves.high;
|
||||
if constexpr (add) {
|
||||
ax.halves.low += 6;
|
||||
++ax.halves.high;
|
||||
} else {
|
||||
ax.halves.low -= 6;
|
||||
--ax.halves.high;
|
||||
}
|
||||
context.flags.template set_from<Flag::Carry, Flag::AuxiliaryCarry>(1);
|
||||
} else {
|
||||
context.flags.template set_from<Flag::Carry, Flag::AuxiliaryCarry>(0);
|
||||
}
|
||||
ax.halves.low &= 0x0f;
|
||||
}
|
||||
@ -96,143 +83,27 @@ void aam(
|
||||
context.flags.template set_from<uint8_t, Flag::Zero, Flag::Sign, Flag::ParityOdd>(ax.halves.low);
|
||||
}
|
||||
|
||||
template <typename ContextT>
|
||||
void aas(
|
||||
CPU::RegisterPair16 &ax,
|
||||
ContextT &context
|
||||
) {
|
||||
/*
|
||||
IF ((AL AND 0FH) > 9) OR (AF = 1)
|
||||
THEN
|
||||
AL ← AL – 6;
|
||||
AH ← AH – 1;
|
||||
AF ← 1;
|
||||
CF ← 1;
|
||||
ELSE
|
||||
CF ← 0;
|
||||
AF ← 0;
|
||||
FI;
|
||||
AL ← AL AND 0FH;
|
||||
*/
|
||||
/*
|
||||
The AF and CF flags are set to 1 if there is a decimal borrow;
|
||||
otherwise, they are cleared to 0. The OF, SF, ZF, and PF flags are undefined.
|
||||
*/
|
||||
if((ax.halves.low & 0x0f) > 9 || context.flags.template flag<Flag::AuxiliaryCarry>()) {
|
||||
ax.halves.low -= 6;
|
||||
--ax.halves.high;
|
||||
context.flags.template set_from<Flag::Carry, Flag::AuxiliaryCarry>(1);
|
||||
} else {
|
||||
context.flags.template set_from<Flag::Carry, Flag::AuxiliaryCarry>(0);
|
||||
}
|
||||
ax.halves.low &= 0x0f;
|
||||
}
|
||||
|
||||
template <typename ContextT>
|
||||
void daa(
|
||||
/// If @c add is @c true, performs a DAA; otherwise perfoms a DAS.
|
||||
template <bool add, typename ContextT>
|
||||
void daas(
|
||||
uint8_t &al,
|
||||
ContextT &context
|
||||
) {
|
||||
/*
|
||||
(as modified by https://www.felixcloutier.com/x86/daa ...)
|
||||
|
||||
old_AL ← AL;
|
||||
old_CF ← CF;
|
||||
CF ← 0;
|
||||
|
||||
IF (((AL AND 0FH) > 9) or AF = 1)
|
||||
THEN
|
||||
AL ← AL + 6;
|
||||
CF ← old_CF OR CarryFromLastAddition; (* CF OR carry from AL ← AL + 6 *)
|
||||
AF ← 1;
|
||||
ELSE
|
||||
AF ← 0;
|
||||
FI;
|
||||
IF ((old_AL > 99H) or old_CF = 1)
|
||||
THEN
|
||||
AL ← AL + 60H;
|
||||
CF ← 1;
|
||||
ELSE
|
||||
CF ← 0;
|
||||
FI;
|
||||
*/
|
||||
/*
|
||||
The CF and AF flags are set if the adjustment of the value results in a
|
||||
decimal carry in either digit of the result (see the “Operation” section above).
|
||||
The SF, ZF, and PF flags are set according to the result. The OF flag is undefined.
|
||||
*/
|
||||
const uint8_t old_al = al;
|
||||
const auto old_carry = context.flags.template flag<Flag::Carry>();
|
||||
context.flags.template set_from<Flag::Carry>(0);
|
||||
bool top_exceeded_threshold;
|
||||
if constexpr (ContextT::model == Model::i8086) {
|
||||
top_exceeded_threshold = al > (context.flags.template flag<Flag::AuxiliaryCarry>() ? 0x9f : 0x99);
|
||||
} else {
|
||||
top_exceeded_threshold = al > 0x99;
|
||||
}
|
||||
|
||||
if((al & 0x0f) > 0x09 || context.flags.template flag<Flag::AuxiliaryCarry>()) {
|
||||
context.flags.template set_from<Flag::Carry>(old_carry | (al > 0xf9));
|
||||
al += 0x06;
|
||||
if constexpr (add) al += 0x06; else al -= 0x06;
|
||||
context.flags.template set_from<Flag::AuxiliaryCarry>(1);
|
||||
} else {
|
||||
context.flags.template set_from<Flag::AuxiliaryCarry>(0);
|
||||
}
|
||||
|
||||
if(old_al > 0x99 || old_carry) {
|
||||
al += 0x60;
|
||||
if(top_exceeded_threshold || context.flags.template flag<Flag::Carry>()) {
|
||||
if constexpr (add) al += 0x60; else al -= 0x60;
|
||||
context.flags.template set_from<Flag::Carry>(1);
|
||||
} else {
|
||||
context.flags.template set_from<Flag::Carry>(0);
|
||||
}
|
||||
|
||||
context.flags.template set_from<uint8_t, Flag::Zero, Flag::Sign, Flag::ParityOdd>(al);
|
||||
}
|
||||
|
||||
template <typename ContextT>
|
||||
void das(
|
||||
uint8_t &al,
|
||||
ContextT &context
|
||||
) {
|
||||
/*
|
||||
(as modified by https://www.felixcloutier.com/x86/daa ...)
|
||||
|
||||
old_AL ← AL;
|
||||
old_CF ← CF;
|
||||
CF ← 0;
|
||||
|
||||
IF (((AL AND 0FH) > 9) or AF = 1)
|
||||
THEN
|
||||
AL ← AL - 6;
|
||||
CF ← old_CF OR CarryFromLastAddition; (* CF OR borrow from AL ← AL - 6 *)
|
||||
AF ← 1;
|
||||
ELSE
|
||||
AF ← 0;
|
||||
FI;
|
||||
IF ((old_AL > 99H) or old_CF = 1)
|
||||
THEN
|
||||
AL ← AL - 60H;
|
||||
CF ← 1;
|
||||
ELSE
|
||||
CF ← 0;
|
||||
FI;
|
||||
*/
|
||||
/*
|
||||
The CF and AF flags are set if the adjustment of the value results in a
|
||||
decimal carry in either digit of the result (see the “Operation” section above).
|
||||
The SF, ZF, and PF flags are set according to the result. The OF flag is undefined.
|
||||
*/
|
||||
const uint8_t old_al = al;
|
||||
const auto old_carry = context.flags.template flag<Flag::Carry>();
|
||||
context.flags.template set_from<Flag::Carry>(0);
|
||||
|
||||
if((al & 0x0f) > 0x09 || context.flags.template flag<Flag::AuxiliaryCarry>()) {
|
||||
context.flags.template set_from<Flag::Carry>(old_carry | (al < 0x06));
|
||||
al -= 0x06;
|
||||
context.flags.template set_from<Flag::AuxiliaryCarry>(1);
|
||||
} else {
|
||||
context.flags.template set_from<Flag::AuxiliaryCarry>(0);
|
||||
}
|
||||
|
||||
if(old_al > 0x99 || old_carry) {
|
||||
al -= 0x60;
|
||||
context.flags.template set_from<Flag::Carry>(1);
|
||||
} else {
|
||||
context.flags.template set_from<Flag::Carry>(0);
|
||||
}
|
||||
|
||||
context.flags.template set_from<uint8_t, Flag::Zero, Flag::Sign, Flag::ParityOdd>(al);
|
||||
|
@ -175,12 +175,12 @@ template <
|
||||
case Operation::ESC:
|
||||
case Operation::NOP: return;
|
||||
|
||||
case Operation::AAA: Primitive::aaa(context.registers.axp(), context); return;
|
||||
case Operation::AAD: Primitive::aad(context.registers.axp(), instruction.operand(), context); return;
|
||||
case Operation::AAM: Primitive::aam(context.registers.axp(), instruction.operand(), context); return;
|
||||
case Operation::AAS: Primitive::aas(context.registers.axp(), context); return;
|
||||
case Operation::DAA: Primitive::daa(context.registers.al(), context); return;
|
||||
case Operation::DAS: Primitive::das(context.registers.al(), context); return;
|
||||
case Operation::AAD: Primitive::aad(context.registers.axp(), instruction.operand(), context); return;
|
||||
case Operation::AAA: Primitive::aaas<true>(context.registers.axp(), context); return;
|
||||
case Operation::AAS: Primitive::aaas<false>(context.registers.axp(), context); return;
|
||||
case Operation::DAA: Primitive::daas<true>(context.registers.al(), context); return;
|
||||
case Operation::DAS: Primitive::daas<false>(context.registers.al(), context); return;
|
||||
|
||||
case Operation::CBW: Primitive::cbw(pair_low()); return;
|
||||
case Operation::CWD: Primitive::cwd(pair_high(), pair_low()); return;
|
||||
|
@ -394,8 +394,6 @@ struct FailedExecution {
|
||||
NSString *path = [NSString stringWithUTF8String:TestSuiteHome];
|
||||
NSSet *allowList = [NSSet setWithArray:@[
|
||||
// Current execution failures:
|
||||
// @"27.json.gz", // DAA
|
||||
// @"2F.json.gz", // DAS
|
||||
// @"D4.json.gz", // AAM
|
||||
// @"F6.7.json.gz", // IDIV
|
||||
// @"F7.7.json.gz", // IDIV
|
||||
@ -459,8 +457,6 @@ struct FailedExecution {
|
||||
return hexInstruction;
|
||||
};
|
||||
|
||||
EACCES;
|
||||
|
||||
const auto decoded = decoder.decode(data.data(), data.size());
|
||||
const bool sizeMatched = decoded.first == data.size();
|
||||
if(assert) {
|
||||
@ -748,10 +744,9 @@ struct FailedExecution {
|
||||
}
|
||||
|
||||
// Lock in current failure rate.
|
||||
XCTAssertLessThanOrEqual(execution_failures.size(), 4138);
|
||||
XCTAssertLessThanOrEqual(execution_failures.size(), 4009);
|
||||
|
||||
// Current accepted failures:
|
||||
// * 65 instances of DAA with invalid BCD input, and 64 of DAS;
|
||||
// * 2484 instances of LEA from a register, which officially has undefined results;
|
||||
// * 42 instances of AAM 00h for which I can't figure out what to do with flags; and
|
||||
// * 1486 instances of IDIV, most either with a rep or repne that on the 8086 specifically negatives the result,
|
||||
|
Loading…
x
Reference in New Issue
Block a user