From 502b9d20230446f7fa60e617a92f30b294ad1572 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 8 Nov 2023 22:06:58 -0500 Subject: [PATCH 1/6] Simplify implementation of DAA. --- InstructionSets/x86/Implementation/BCD.hpp | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/InstructionSets/x86/Implementation/BCD.hpp b/InstructionSets/x86/Implementation/BCD.hpp index f8de9e6fd..1d86e865a 100644 --- a/InstructionSets/x86/Implementation/BCD.hpp +++ b/InstructionSets/x86/Implementation/BCD.hpp @@ -162,22 +162,15 @@ void daa( 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(); - context.flags.template set_from(0); if((al & 0x0f) > 0x09 || context.flags.template flag()) { - context.flags.template set_from(old_carry | (al > 0xf9)); al += 0x06; context.flags.template set_from(1); - } else { - context.flags.template set_from(0); } - if(old_al > 0x99 || old_carry) { + if(old_al > 0x99 || context.flags.template flag()) { al += 0x60; context.flags.template set_from(1); - } else { - context.flags.template set_from(0); } context.flags.template set_from(al); From 38933aa079dbec9ea7358e3a64a9b9ff42240a46 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 8 Nov 2023 22:16:12 -0500 Subject: [PATCH 2/6] Bring fully into 8086 conformance. --- InstructionSets/x86/Implementation/BCD.hpp | 37 ++++------------------ 1 file changed, 7 insertions(+), 30 deletions(-) diff --git a/InstructionSets/x86/Implementation/BCD.hpp b/InstructionSets/x86/Implementation/BCD.hpp index 1d86e865a..876cd813e 100644 --- a/InstructionSets/x86/Implementation/BCD.hpp +++ b/InstructionSets/x86/Implementation/BCD.hpp @@ -133,42 +133,19 @@ void daa( 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; + bool top_exceeded_threshold; + if constexpr (ContextT::model == Model::i8086) { + top_exceeded_threshold = al > (context.flags.template flag() ? 0x9f : 0x99); + } else { + top_exceeded_threshold = al > 0x99; + } if((al & 0x0f) > 0x09 || context.flags.template flag()) { al += 0x06; context.flags.template set_from(1); } - if(old_al > 0x99 || context.flags.template flag()) { + if(top_exceeded_threshold || context.flags.template flag()) { al += 0x60; context.flags.template set_from(1); } From 6b666bc92a6fd7ff4e485658a4514a90f50ef3ab Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 8 Nov 2023 22:19:51 -0500 Subject: [PATCH 3/6] Simplify DAS. --- InstructionSets/x86/Implementation/BCD.hpp | 38 ++-------------------- 1 file changed, 2 insertions(+), 36 deletions(-) diff --git a/InstructionSets/x86/Implementation/BCD.hpp b/InstructionSets/x86/Implementation/BCD.hpp index 876cd813e..2ea8e37db 100644 --- a/InstructionSets/x86/Implementation/BCD.hpp +++ b/InstructionSets/x86/Implementation/BCD.hpp @@ -158,56 +158,22 @@ 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(); - context.flags.template set_from(0); if((al & 0x0f) > 0x09 || context.flags.template flag()) { - context.flags.template set_from(old_carry | (al < 0x06)); al -= 0x06; context.flags.template set_from(1); - } else { - context.flags.template set_from(0); } - if(old_al > 0x99 || old_carry) { + if(old_al > 0x99 || context.flags.template flag()) { al -= 0x60; context.flags.template set_from(1); - } else { - context.flags.template set_from(0); } context.flags.template set_from(al); } + } #endif /* BCD_h */ From 8d2a2bcf4af0ac7a8fe82dd78475a1c679e56834 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 8 Nov 2023 22:26:48 -0500 Subject: [PATCH 4/6] Unify DAA and DAS. --- InstructionSets/x86/Implementation/BCD.hpp | 95 ++++++++----------- .../Implementation/PerformImplementation.hpp | 4 +- OSBindings/Mac/Clock SignalTests/8088Tests.mm | 11 +-- 3 files changed, 45 insertions(+), 65 deletions(-) diff --git a/InstructionSets/x86/Implementation/BCD.hpp b/InstructionSets/x86/Implementation/BCD.hpp index 2ea8e37db..97519cc6a 100644 --- a/InstructionSets/x86/Implementation/BCD.hpp +++ b/InstructionSets/x86/Implementation/BCD.hpp @@ -47,6 +47,39 @@ void aaa( ax.halves.low &= 0x0f; } + +template +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()) { + ax.halves.low -= 6; + --ax.halves.high; + context.flags.template set_from(1); + } else { + context.flags.template set_from(0); + } + ax.halves.low &= 0x0f; +} + template void aad( CPU::RegisterPair16 &ax, @@ -96,40 +129,9 @@ void aam( context.flags.template set_from(ax.halves.low); } -template -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()) { - ax.halves.low -= 6; - --ax.halves.high; - context.flags.template set_from(1); - } else { - context.flags.template set_from(0); - } - ax.halves.low &= 0x0f; -} - -template -void daa( +/// If @c add is @c true, performs a DAA; otherwise perfoms a DAS. +template +void daas( uint8_t &al, ContextT &context ) { @@ -141,39 +143,18 @@ void daa( } if((al & 0x0f) > 0x09 || context.flags.template flag()) { - al += 0x06; + if constexpr (add) al += 0x06; else al -= 0x06; context.flags.template set_from(1); } if(top_exceeded_threshold || context.flags.template flag()) { - al += 0x60; + if constexpr (add) al += 0x60; else al -= 0x60; context.flags.template set_from(1); } context.flags.template set_from(al); } -template -void das( - uint8_t &al, - ContextT &context -) { - const uint8_t old_al = al; - - if((al & 0x0f) > 0x09 || context.flags.template flag()) { - al -= 0x06; - context.flags.template set_from(1); - } - - if(old_al > 0x99 || context.flags.template flag()) { - al -= 0x60; - context.flags.template set_from(1); - } - - context.flags.template set_from(al); -} - - } #endif /* BCD_h */ diff --git a/InstructionSets/x86/Implementation/PerformImplementation.hpp b/InstructionSets/x86/Implementation/PerformImplementation.hpp index 1090d4a17..6a13c2254 100644 --- a/InstructionSets/x86/Implementation/PerformImplementation.hpp +++ b/InstructionSets/x86/Implementation/PerformImplementation.hpp @@ -179,8 +179,8 @@ template < 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::DAA: Primitive::daas(context.registers.al(), context); return; + case Operation::DAS: Primitive::daas(context.registers.al(), context); return; case Operation::CBW: Primitive::cbw(pair_low()); return; case Operation::CWD: Primitive::cwd(pair_high(), pair_low()); return; diff --git a/OSBindings/Mac/Clock SignalTests/8088Tests.mm b/OSBindings/Mac/Clock SignalTests/8088Tests.mm index 2c96678b7..ec08966ab 100644 --- a/OSBindings/Mac/Clock SignalTests/8088Tests.mm +++ b/OSBindings/Mac/Clock SignalTests/8088Tests.mm @@ -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) { @@ -576,6 +572,10 @@ struct FailedExecution { execution_support.clear(); + if([test[@"test_hash"] isEqualTo:@"503062cab62a583b2884554dfd332d01ab4cc7355b49a1b0523fcbf3e22777a4"]) { + printf(""); + } + const uint16_t flags_mask = metadata[@"flags-mask"] ? [metadata[@"flags-mask"] intValue] : 0xffff; NSDictionary *const initial_state = test[@"initial"]; NSDictionary *const final_state = test[@"final"]; @@ -748,10 +748,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, From 5f1ea6c04cd438b13144c264a402e55f1baf203d Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 8 Nov 2023 22:30:39 -0500 Subject: [PATCH 5/6] Unify AAA and AAS. --- InstructionSets/x86/Implementation/BCD.hpp | 66 +++---------------- .../Implementation/PerformImplementation.hpp | 6 +- 2 files changed, 13 insertions(+), 59 deletions(-) diff --git a/InstructionSets/x86/Implementation/BCD.hpp b/InstructionSets/x86/Implementation/BCD.hpp index 97519cc6a..26fd87056 100644 --- a/InstructionSets/x86/Implementation/BCD.hpp +++ b/InstructionSets/x86/Implementation/BCD.hpp @@ -15,67 +15,21 @@ namespace InstructionSet::x86::Primitive { -template -void aaa( - 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()) { - ax.halves.low += 6; - ++ax.halves.high; - context.flags.template set_from(1); - } else { - context.flags.template set_from(0); - } - ax.halves.low &= 0x0f; -} - - -template -void aas( +/// If @c add is @c true, performs an AAA; otherwise perfoms an AAS. +template +void aaas( 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()) { - 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(1); - } else { - context.flags.template set_from(0); } ax.halves.low &= 0x0f; } diff --git a/InstructionSets/x86/Implementation/PerformImplementation.hpp b/InstructionSets/x86/Implementation/PerformImplementation.hpp index 6a13c2254..a28073a1b 100644 --- a/InstructionSets/x86/Implementation/PerformImplementation.hpp +++ b/InstructionSets/x86/Implementation/PerformImplementation.hpp @@ -175,10 +175,10 @@ 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::AAD: Primitive::aad(context.registers.axp(), instruction.operand(), context); return; + case Operation::AAA: Primitive::aaas(context.registers.axp(), context); return; + case Operation::AAS: Primitive::aaas(context.registers.axp(), context); return; case Operation::DAA: Primitive::daas(context.registers.al(), context); return; case Operation::DAS: Primitive::daas(context.registers.al(), context); return; From 9e61d3e8cf85f46dd8885b53d7d588afb7aea355 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 8 Nov 2023 22:38:52 -0500 Subject: [PATCH 6/6] Combine AAA and AAS. --- OSBindings/Mac/Clock SignalTests/8088Tests.mm | 4 ---- 1 file changed, 4 deletions(-) diff --git a/OSBindings/Mac/Clock SignalTests/8088Tests.mm b/OSBindings/Mac/Clock SignalTests/8088Tests.mm index ec08966ab..0cf44421f 100644 --- a/OSBindings/Mac/Clock SignalTests/8088Tests.mm +++ b/OSBindings/Mac/Clock SignalTests/8088Tests.mm @@ -572,10 +572,6 @@ struct FailedExecution { execution_support.clear(); - if([test[@"test_hash"] isEqualTo:@"503062cab62a583b2884554dfd332d01ab4cc7355b49a1b0523fcbf3e22777a4"]) { - printf(""); - } - const uint16_t flags_mask = metadata[@"flags-mask"] ? [metadata[@"flags-mask"] intValue] : 0xffff; NSDictionary *const initial_state = test[@"initial"]; NSDictionary *const final_state = test[@"final"];