From 79b126e6bb0436d1130e7ea2a1d762012636cc44 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Fri, 10 Nov 2023 22:11:52 -0500 Subject: [PATCH 1/8] Add route for tracking segment register changes. --- .../Implementation/PerformImplementation.hpp | 14 ++++++++++-- InstructionSets/x86/Instruction.hpp | 5 ++++- OSBindings/Mac/Clock SignalTests/8088Tests.mm | 22 +++++++++++++------ 3 files changed, 31 insertions(+), 10 deletions(-) diff --git a/InstructionSets/x86/Implementation/PerformImplementation.hpp b/InstructionSets/x86/Implementation/PerformImplementation.hpp index 1808366e4..26b42b168 100644 --- a/InstructionSets/x86/Implementation/PerformImplementation.hpp +++ b/InstructionSets/x86/Implementation/PerformImplementation.hpp @@ -253,7 +253,12 @@ template < return; case Operation::LEA: Primitive::lea(instruction, destination_w(), context); return; - case Operation::MOV: Primitive::mov(destination_w(), source_r()); break; + case Operation::MOV: + Primitive::mov(destination_w(), source_r()); + if constexpr (std::is_same_v) { + context.registers.did_update(instruction.destination.source()); + } + break; case Operation::JO: jcc(context.flags.template condition()); return; case Operation::JNO: jcc(!context.flags.template condition()); return; @@ -319,7 +324,12 @@ template < case Operation::XLAT: Primitive::xlat(instruction, context); return; - case Operation::POP: destination_w() = Primitive::pop(context); break; + case Operation::POP: + destination_w() = Primitive::pop(context); + if constexpr (std::is_same_v) { + context.registers.did_update(instruction.destination.source()); + } + break; case Operation::PUSH: Primitive::push(source_rmw(), context); // PUSH SP modifies SP before pushing it; // hence PUSH is sometimes read-modify-write. diff --git a/InstructionSets/x86/Instruction.hpp b/InstructionSets/x86/Instruction.hpp index 589e6d330..4fc19a297 100644 --- a/InstructionSets/x86/Instruction.hpp +++ b/InstructionSets/x86/Instruction.hpp @@ -444,7 +444,7 @@ enum class Source: uint8_t { T0 = 0, T1 = 1, T2 = 2, T3 = 3, T4 = 4, T5 = 5, T6 = 6, T7 = 7, D0 = 0, D1 = 1, D2 = 2, D3 = 3, D4 = 4, D5 = 5, D6 = 6, D7 = 7, - // Selectors. + // Segment registers. ES, CS, SS, DS, FS, GS, /// @c None can be treated as a source that produces 0 when encountered; @@ -473,6 +473,9 @@ enum class Source: uint8_t { constexpr bool is_register(Source source) { return source < Source::None; } +constexpr bool is_segment_register(Source source) { + return is_register(source) && source >= Source::ES; +} enum class Repetition: uint8_t { None, RepE, RepNE, Rep, diff --git a/OSBindings/Mac/Clock SignalTests/8088Tests.mm b/OSBindings/Mac/Clock SignalTests/8088Tests.mm index 0310acab2..0bd7a64c6 100644 --- a/OSBindings/Mac/Clock SignalTests/8088Tests.mm +++ b/OSBindings/Mac/Clock SignalTests/8088Tests.mm @@ -68,6 +68,7 @@ struct Registers { uint16_t &di() { return di_; } uint16_t es_, cs_, ds_, ss_; + uint32_t es_base_, cs_base_, ds_base_, ss_base_; uint16_t ip_; uint16_t &ip() { return ip_; } @@ -77,6 +78,17 @@ struct Registers { uint16_t &ds() { return ds_; } uint16_t &ss() { return ss_; } + using Source = InstructionSet::x86::Source; + void did_update(Source segment) { + switch(segment) { + default: break; + case Source::ES: es_base_ = es_ << 4; break; + case Source::CS: cs_base_ = cs_ << 4; break; + case Source::DS: ds_base_ = ds_ << 4; break; + case Source::SS: ss_base_ = ss_ << 4; break; + } + } + bool operator ==(const Registers &rhs) const { return ax_.full == rhs.ax_.full && @@ -395,9 +407,9 @@ struct FailedExecution { NSString *path = [NSString stringWithUTF8String:TestSuiteHome]; NSSet *allowList = [NSSet setWithArray:@[ // Current execution failures, albeit all permitted: - @"D4.json.gz", // AAM - @"F6.7.json.gz", // IDIV byte - @"F7.7.json.gz", // IDIV word +// @"D4.json.gz", // AAM +// @"F6.7.json.gz", // IDIV byte +// @"F7.7.json.gz", // IDIV word ]]; NSSet *ignoreList = nil; @@ -694,10 +706,6 @@ struct FailedExecution { failure_list = &permitted_failures; } - if(failure_list == &execution_failures) { - printf("Fail: %d\n", int(decoded.second.operation())); - } - // Record a failure. FailedExecution failure; failure.instruction = decoded.second; From e61dc0466f2f0dd475e52edfb8b53d4ad3c33338 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Fri, 10 Nov 2023 22:22:32 -0500 Subject: [PATCH 2/8] Add callout for tracking segment register changes. --- .../x86/Implementation/PerformImplementation.hpp | 4 ++-- OSBindings/Mac/Clock SignalTests/8088Tests.mm | 15 +++++++++------ 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/InstructionSets/x86/Implementation/PerformImplementation.hpp b/InstructionSets/x86/Implementation/PerformImplementation.hpp index 26b42b168..a12bd65ae 100644 --- a/InstructionSets/x86/Implementation/PerformImplementation.hpp +++ b/InstructionSets/x86/Implementation/PerformImplementation.hpp @@ -256,7 +256,7 @@ template < case Operation::MOV: Primitive::mov(destination_w(), source_r()); if constexpr (std::is_same_v) { - context.registers.did_update(instruction.destination.source()); + context.registers.did_update(instruction.destination().source()); } break; @@ -327,7 +327,7 @@ template < case Operation::POP: destination_w() = Primitive::pop(context); if constexpr (std::is_same_v) { - context.registers.did_update(instruction.destination.source()); + context.registers.did_update(instruction.destination().source()); } break; case Operation::PUSH: diff --git a/OSBindings/Mac/Clock SignalTests/8088Tests.mm b/OSBindings/Mac/Clock SignalTests/8088Tests.mm index 0bd7a64c6..0efed5e3b 100644 --- a/OSBindings/Mac/Clock SignalTests/8088Tests.mm +++ b/OSBindings/Mac/Clock SignalTests/8088Tests.mm @@ -249,15 +249,13 @@ struct Memory { } uint32_t segment_base(InstructionSet::x86::Source segment) { - uint32_t physical_address; using Source = InstructionSet::x86::Source; switch(segment) { - default: physical_address = registers_.ds_; break; - case Source::ES: physical_address = registers_.es_; break; - case Source::CS: physical_address = registers_.cs_; break; - case Source::SS: physical_address = registers_.ss_; break; + default: return registers_.ds_base_; + case Source::ES: return registers_.es_base_; + case Source::CS: return registers_.cs_base_; + case Source::SS: return registers_.ss_base_; } - return physical_address << 4; } uint32_t address(InstructionSet::x86::Source segment, uint16_t offset) { @@ -556,6 +554,11 @@ struct FailedExecution { registers.ss_ = [value[@"ss"] intValue]; registers.ip_ = [value[@"ip"] intValue]; + registers.did_update(Registers::Source::ES); + registers.did_update(Registers::Source::CS); + registers.did_update(Registers::Source::DS); + registers.did_update(Registers::Source::SS); + const uint16_t flags_value = [value[@"flags"] intValue]; flags.set(flags_value); From 7abd4d9b38654b2cf8883df08b6570add3f75aff Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Fri, 10 Nov 2023 22:47:50 -0500 Subject: [PATCH 3/8] Fix AAA/AAS carry outcome. --- InstructionSets/x86/Implementation/BCD.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/InstructionSets/x86/Implementation/BCD.hpp b/InstructionSets/x86/Implementation/BCD.hpp index 26fd87056..2e6d77388 100644 --- a/InstructionSets/x86/Implementation/BCD.hpp +++ b/InstructionSets/x86/Implementation/BCD.hpp @@ -30,6 +30,8 @@ void aaas( --ax.halves.high; } context.flags.template set_from(1); + } else { + context.flags.template set_from(0); } ax.halves.low &= 0x0f; } From 2551e73be1f2e57b06662e2598aacbb5b97993d8 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Fri, 10 Nov 2023 22:54:10 -0500 Subject: [PATCH 4/8] Fully test segment registers. --- OSBindings/Mac/Clock SignalTests/8088Tests.mm | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/OSBindings/Mac/Clock SignalTests/8088Tests.mm b/OSBindings/Mac/Clock SignalTests/8088Tests.mm index 0efed5e3b..2664ef699 100644 --- a/OSBindings/Mac/Clock SignalTests/8088Tests.mm +++ b/OSBindings/Mac/Clock SignalTests/8088Tests.mm @@ -103,7 +103,11 @@ struct Registers { cs_ == rhs.cs_ && ds_ == rhs.ds_ && si_ == rhs.si_ && - ip_ == rhs.ip_; + ip_ == rhs.ip_ && + es_base_ == rhs.es_base_ && + cs_base_ == rhs.cs_base_ && + ds_base_ == rhs.ds_base_ && + ss_base_ == rhs.ss_base_; } }; struct Memory { From 19a61f867f1d5e65375228ac5395debd6c7c0a51 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Fri, 10 Nov 2023 22:56:00 -0500 Subject: [PATCH 5/8] Eliminate final misuse of 'selector'. --- OSBindings/Mac/Clock SignalTests/8088Tests.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OSBindings/Mac/Clock SignalTests/8088Tests.mm b/OSBindings/Mac/Clock SignalTests/8088Tests.mm index 2664ef699..d5a84da74 100644 --- a/OSBindings/Mac/Clock SignalTests/8088Tests.mm +++ b/OSBindings/Mac/Clock SignalTests/8088Tests.mm @@ -285,7 +285,7 @@ struct Memory { } // An additional entry point for the flow controller; on the original 8086 interrupt vectors aren't relative - // to a selector, they're just at an absolute location. + // to a segment, they're just at an absolute location. template typename InstructionSet::x86::Accessor::type access(uint32_t address, Tag tag) { if constexpr (type == AccessType::PreauthorisedRead) { From 3a782faaf304e3b8bed95bdcfdbb3f41004612cc Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Fri, 10 Nov 2023 22:58:59 -0500 Subject: [PATCH 6/8] Ensure shoutouts upon LDS, LES and any far jump/call/int. --- .../x86/Implementation/PerformImplementation.hpp | 10 ++++++++-- OSBindings/Mac/Clock SignalTests/8088Tests.mm | 1 + 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/InstructionSets/x86/Implementation/PerformImplementation.hpp b/InstructionSets/x86/Implementation/PerformImplementation.hpp index a12bd65ae..0016495bd 100644 --- a/InstructionSets/x86/Implementation/PerformImplementation.hpp +++ b/InstructionSets/x86/Implementation/PerformImplementation.hpp @@ -246,10 +246,16 @@ template < case Operation::LAHF: Primitive::lahf(context.registers.ah(), context); return; case Operation::LDS: - if constexpr (data_size == DataSize::Word) Primitive::ld(instruction, destination_w(), context); + if constexpr (data_size == DataSize::Word) { + Primitive::ld(instruction, destination_w(), context); + context.registers.did_update(Source::DS); + } return; case Operation::LES: - if constexpr (data_size == DataSize::Word) Primitive::ld(instruction, destination_w(), context); + if constexpr (data_size == DataSize::Word) { + Primitive::ld(instruction, destination_w(), context); + context.registers.did_update(Source::ES); + } return; case Operation::LEA: Primitive::lea(instruction, destination_w(), context); return; diff --git a/OSBindings/Mac/Clock SignalTests/8088Tests.mm b/OSBindings/Mac/Clock SignalTests/8088Tests.mm index d5a84da74..1272f9648 100644 --- a/OSBindings/Mac/Clock SignalTests/8088Tests.mm +++ b/OSBindings/Mac/Clock SignalTests/8088Tests.mm @@ -348,6 +348,7 @@ class FlowController { void jump(uint16_t segment, uint16_t address) { registers_.cs_ = segment; + registers_.did_update(Registers::Source::CS); registers_.ip_ = address; } From 47fc276afcf2bbae17efb3298da425cfaadb2784 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Fri, 10 Nov 2023 23:01:46 -0500 Subject: [PATCH 7/8] Add note to future self. --- OSBindings/Mac/Clock SignalTests/8088Tests.mm | 1 + 1 file changed, 1 insertion(+) diff --git a/OSBindings/Mac/Clock SignalTests/8088Tests.mm b/OSBindings/Mac/Clock SignalTests/8088Tests.mm index 1272f9648..0b6e10950 100644 --- a/OSBindings/Mac/Clock SignalTests/8088Tests.mm +++ b/OSBindings/Mac/Clock SignalTests/8088Tests.mm @@ -79,6 +79,7 @@ struct Registers { uint16_t &ss() { return ss_; } using Source = InstructionSet::x86::Source; + /// Posted by @c perform after any operation which *might* have affected a segment register. void did_update(Source segment) { switch(segment) { default: break; From 08d9cc3bd3c4fa2840c8685b87bb34ccda164ae4 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Fri, 10 Nov 2023 23:02:32 -0500 Subject: [PATCH 8/8] Restore permitted IDIV miss. --- OSBindings/Mac/Clock SignalTests/8088Tests.mm | 1 + 1 file changed, 1 insertion(+) diff --git a/OSBindings/Mac/Clock SignalTests/8088Tests.mm b/OSBindings/Mac/Clock SignalTests/8088Tests.mm index 0b6e10950..069be119c 100644 --- a/OSBindings/Mac/Clock SignalTests/8088Tests.mm +++ b/OSBindings/Mac/Clock SignalTests/8088Tests.mm @@ -703,6 +703,7 @@ struct FailedExecution { non_exception_registers.sp() = execution_support.registers.sp(); non_exception_registers.ax() = execution_support.registers.ax(); non_exception_registers.cs() = execution_support.registers.cs(); + non_exception_registers.cs_base_ = execution_support.registers.cs_base_; if(non_exception_registers == execution_support.registers) { failure_list = &permitted_failures;