From ac826f90c372f7014e1a2408a249ed9e667e4bb1 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 14 Nov 2023 10:56:00 -0500 Subject: [PATCH] Formalise a separate manager of segments. --- .../Implementation/PerformImplementation.hpp | 32 +++++-- InstructionSets/x86/Implementation/Stack.hpp | 82 ++++++++-------- OSBindings/Mac/Clock SignalTests/8088Tests.mm | 95 ++++++++++++------- 3 files changed, 125 insertions(+), 84 deletions(-) diff --git a/InstructionSets/x86/Implementation/PerformImplementation.hpp b/InstructionSets/x86/Implementation/PerformImplementation.hpp index 999aafe3f..988c9b774 100644 --- a/InstructionSets/x86/Implementation/PerformImplementation.hpp +++ b/InstructionSets/x86/Implementation/PerformImplementation.hpp @@ -256,13 +256,13 @@ template < case Operation::LDS: if constexpr (data_size == DataSize::Word) { Primitive::ld(instruction, destination_w(), context); - context.registers.did_update(Source::DS); + context.segments.did_update(Source::DS); } return; case Operation::LES: if constexpr (data_size == DataSize::Word) { Primitive::ld(instruction, destination_w(), context); - context.registers.did_update(Source::ES); + context.segments.did_update(Source::ES); } return; @@ -270,7 +270,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.segments.did_update(instruction.destination().source()); } break; @@ -341,7 +341,7 @@ template < case Operation::POP: destination_w() = Primitive::pop(context); if constexpr (std::is_same_v) { - context.registers.did_update(instruction.destination().source()); + context.segments.did_update(instruction.destination().source()); } break; case Operation::PUSH: @@ -349,10 +349,26 @@ template < // hence PUSH is sometimes read-modify-write. break; - case Operation::POPF: Primitive::popf(context); return; - case Operation::PUSHF: Primitive::pushf(context); return; - case Operation::POPA: Primitive::popa(context); return; - case Operation::PUSHA: Primitive::pusha(context); return; + case Operation::POPF: + if constexpr (std::is_same_v || std::is_same_v) { + Primitive::popf(context); + } + return; + case Operation::PUSHF: + if constexpr (std::is_same_v || std::is_same_v) { + Primitive::pushf(context); + } + return; + case Operation::POPA: + if constexpr (std::is_same_v || std::is_same_v) { + Primitive::popa(context); + } + return; + case Operation::PUSHA: + if constexpr (std::is_same_v || std::is_same_v) { + Primitive::pusha(context); + } + return; case Operation::CMPS: Primitive::cmps(instruction, eCX(), eSI(), eDI(), context); diff --git a/InstructionSets/x86/Implementation/Stack.hpp b/InstructionSets/x86/Implementation/Stack.hpp index d3d44dbc2..760ac6d9a 100644 --- a/InstructionSets/x86/Implementation/Stack.hpp +++ b/InstructionSets/x86/Implementation/Stack.hpp @@ -95,27 +95,25 @@ template void popa( ContextT &context ) { - if constexpr (!std::is_same_v) { - context.memory.preauthorise_stack_read(sizeof(IntT) * 8); - if constexpr (std::is_same_v) { - context.registers.edi() = pop(context); - context.registers.esi() = pop(context); - context.registers.ebp() = pop(context); - context.registers.esp() += 4; - context.registers.ebx() = pop(context); - context.registers.edx() = pop(context); - context.registers.ecx() = pop(context); - context.registers.eax() = pop(context); - } else { - context.registers.di() = pop(context); - context.registers.si() = pop(context); - context.registers.bp() = pop(context); - context.registers.sp() += 2; - context.registers.bx() = pop(context); - context.registers.dx() = pop(context); - context.registers.cx() = pop(context); - context.registers.ax() = pop(context); - } + context.memory.preauthorise_stack_read(sizeof(IntT) * 8); + if constexpr (std::is_same_v) { + context.registers.edi() = pop(context); + context.registers.esi() = pop(context); + context.registers.ebp() = pop(context); + context.registers.esp() += 4; + context.registers.ebx() = pop(context); + context.registers.edx() = pop(context); + context.registers.ecx() = pop(context); + context.registers.eax() = pop(context); + } else { + context.registers.di() = pop(context); + context.registers.si() = pop(context); + context.registers.bp() = pop(context); + context.registers.sp() += 2; + context.registers.bx() = pop(context); + context.registers.dx() = pop(context); + context.registers.cx() = pop(context); + context.registers.ax() = pop(context); } } @@ -123,28 +121,26 @@ template void pusha( ContextT &context ) { - if constexpr (!std::is_same_v) { - context.memory.preauthorise_stack_read(sizeof(IntT) * 8); - IntT initial_sp = context.registers.sp(); - if constexpr (std::is_same_v) { - push(context.registers.eax(), context); - push(context.registers.ecx(), context); - push(context.registers.edx(), context); - push(context.registers.ebx(), context); - push(initial_sp, context); - push(context.registers.ebp(), context); - push(context.registers.esi(), context); - push(context.registers.esi(), context); - } else { - push(context.registers.ax(), context); - push(context.registers.cx(), context); - push(context.registers.dx(), context); - push(context.registers.bx(), context); - push(initial_sp, context); - push(context.registers.bp(), context); - push(context.registers.si(), context); - push(context.registers.si(), context); - } + context.memory.preauthorise_stack_read(sizeof(IntT) * 8); + IntT initial_sp = context.registers.sp(); + if constexpr (std::is_same_v) { + push(context.registers.eax(), context); + push(context.registers.ecx(), context); + push(context.registers.edx(), context); + push(context.registers.ebx(), context); + push(initial_sp, context); + push(context.registers.ebp(), context); + push(context.registers.esi(), context); + push(context.registers.esi(), context); + } else { + push(context.registers.ax(), context); + push(context.registers.cx(), context); + push(context.registers.dx(), context); + push(context.registers.bx(), context); + push(initial_sp, context); + push(context.registers.bp(), context); + push(context.registers.si(), context); + push(context.registers.si(), context); } } diff --git a/OSBindings/Mac/Clock SignalTests/8088Tests.mm b/OSBindings/Mac/Clock SignalTests/8088Tests.mm index 069be119c..35841e1b5 100644 --- a/OSBindings/Mac/Clock SignalTests/8088Tests.mm +++ b/OSBindings/Mac/Clock SignalTests/8088Tests.mm @@ -68,7 +68,6 @@ 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_; } @@ -78,17 +77,10 @@ struct Registers { uint16_t &ds() { return ds_; } 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; - 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; - } - } + const uint16_t es() const { return es_; } + const uint16_t cs() const { return cs_; } + const uint16_t ds() const { return ds_; } + const uint16_t ss() const { return ss_; } bool operator ==(const Registers &rhs) const { return @@ -104,19 +96,52 @@ struct Registers { cs_ == rhs.cs_ && ds_ == rhs.ds_ && si_ == rhs.si_ && - ip_ == rhs.ip_ && - es_base_ == rhs.es_base_ && - cs_base_ == rhs.cs_base_ && - ds_base_ == rhs.ds_base_ && - ss_base_ == rhs.ss_base_; + ip_ == rhs.ip_; } }; +class Segments { + public: + Segments(const Registers ®isters) : registers_(registers) {} + + 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; + case Source::ES: es_base_ = registers_.es() << 4; break; + case Source::CS: cs_base_ = registers_.cs() << 4; break; + case Source::DS: ds_base_ = registers_.ds() << 4; break; + case Source::SS: ss_base_ = registers_.ss() << 4; break; + } + } + + void reset() { + did_update(Source::ES); + did_update(Source::CS); + did_update(Source::DS); + did_update(Source::SS); + } + + uint32_t es_base_, cs_base_, ds_base_, ss_base_; + + bool operator ==(const Segments &rhs) const { + return + es_base_ != rhs.es_base_ && + cs_base_ != rhs.cs_base_ && + ds_base_ != rhs.ds_base_ && + ss_base_ != rhs.ss_base_; + } + + private: + const Registers ®isters_; +}; struct Memory { public: using AccessType = InstructionSet::x86::AccessType; // Constructor. - Memory(Registers ®isters) : registers_(registers) { + Memory(Registers ®isters, const Segments &segments) : registers_(registers), segments_(segments) { memory.resize(1024*1024); } @@ -237,6 +262,7 @@ struct Memory { std::unordered_map tags; std::vector memory; const Registers ®isters_; + const Segments &segments_; void preauthorise(uint32_t address) { preauthorisations.insert(address); @@ -256,10 +282,10 @@ struct Memory { uint32_t segment_base(InstructionSet::x86::Source segment) { using Source = InstructionSet::x86::Source; switch(segment) { - 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_; + default: return segments_.ds_base_; + case Source::ES: return segments_.es_base_; + case Source::CS: return segments_.cs_base_; + case Source::SS: return segments_.ss_base_; } } @@ -339,8 +365,8 @@ struct IO { }; class FlowController { public: - FlowController(Memory &memory, Registers ®isters, Flags &flags) : - memory_(memory), registers_(registers), flags_(flags) {} + FlowController(Memory &memory, Registers ®isters, Segments &segments, Flags &flags) : + memory_(memory), registers_(registers), segments_(segments), flags_(flags) {} // Requirements for perform. void jump(uint16_t address) { @@ -349,7 +375,7 @@ class FlowController { void jump(uint16_t segment, uint16_t address) { registers_.cs_ = segment; - registers_.did_update(Registers::Source::CS); + segments_.did_update(Segments::Source::CS); registers_.ip_ = address; } @@ -371,6 +397,7 @@ class FlowController { private: Memory &memory_; Registers ®isters_; + Segments &segments_; Flags &flags_; bool should_repeat_ = false; }; @@ -378,12 +405,16 @@ class FlowController { struct ExecutionSupport { Flags flags; Registers registers; + Segments segments; Memory memory; FlowController flow_controller; IO io; static constexpr auto model = InstructionSet::x86::Model::i8086; - ExecutionSupport(): memory(registers), flow_controller(memory, registers, flags) {} + ExecutionSupport(): + memory(registers, segments), + segments(registers), + flow_controller(memory, registers, segments, flags) {} void clear() { memory.clear(); @@ -560,11 +591,6 @@ 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); @@ -610,6 +636,7 @@ struct FailedExecution { [self populate:initial_registers flags:initial_flags value:initial_state[@"regs"]]; execution_support.flags = initial_flags; execution_support.registers = initial_registers; + execution_support.segments.reset(); // Execute instruction. // @@ -657,8 +684,11 @@ struct FailedExecution { break; } + Segments intended_segments(intended_registers); [self populate:intended_registers flags:intended_flags value:final_state[@"regs"]]; - const bool registersEqual = intended_registers == execution_support.registers; + intended_segments.reset(); + + const bool registersEqual = intended_registers == execution_support.registers && intended_segments == execution_support.segments; const bool flagsEqual = (intended_flags.get() & flags_mask) == (execution_support.flags.get() & flags_mask); // Exit if no issues were found. @@ -703,7 +733,6 @@ 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;