diff --git a/InstructionSets/x86/Implementation/PerformImplementation.hpp b/InstructionSets/x86/Implementation/PerformImplementation.hpp index e7db1e792..0a736e6a9 100644 --- a/InstructionSets/x86/Implementation/PerformImplementation.hpp +++ b/InstructionSets/x86/Implementation/PerformImplementation.hpp @@ -189,13 +189,13 @@ IntT *resolve( namespace Primitive { -// The below takes a reference in order properly to handle PUSH SP, which should place the value of SP after the -// push onto the stack. +// The below takes a reference in order properly to handle PUSH SP, +// which should place the value of SP after the push onto the stack. template -void push(IntT value, ContextT &context) { +void push(IntT &value, ContextT &context) { context.registers.sp_ -= sizeof(IntT); context.memory.template access( - InstructionSet::x86::Source::SS, + Source::SS, context.registers.sp_) = value; context.memory.template write_back(); } @@ -203,7 +203,7 @@ void push(IntT value, ContextT &context) { template IntT pop(ContextT &context) { const auto value = context.memory.template access( - InstructionSet::x86::Source::SS, + Source::SS, context.registers.sp_); context.registers.sp_ += sizeof(IntT); return value; @@ -597,7 +597,7 @@ void div(IntT &destination_high, IntT &destination_low, IntT source, ContextT &c The CF, OF, SF, ZF, AF, and PF flags are undefined. */ if(!source) { - InstructionSet::x86::interrupt(Interrupt::DivideError, context); + interrupt(Interrupt::DivideError, context); return; } @@ -869,12 +869,14 @@ void call_far(InstructionT &instruction, ContextT &context) { } context.memory.preauthorise_read(source_segment, source_address, sizeof(uint16_t) * 2); - push(context.registers.cs(), context); - push(context.registers.ip(), context); - const uint16_t offset = context.memory.template access(source_segment, source_address); source_address += 2; const uint16_t segment = context.memory.template access(source_segment, source_address); + + // At least on an 8086, the stack writes occur after the target address read. + push(context.registers.cs(), context); + push(context.registers.ip(), context); + context.flow_controller.jump(segment, offset); } @@ -899,6 +901,7 @@ void jump_far(InstructionT &instruction, ContextT &context) { } const Source source_segment = instruction.data_segment(); + context.memory.preauthorise_read(source_segment, source_address, sizeof(uint16_t) * 2); const uint16_t offset = context.memory.template access(source_segment, source_address); source_address += 2; @@ -1919,7 +1922,8 @@ template < const uint16_t ip = context.memory.template access(address); const uint16_t cs = context.memory.template access(address + 2); - Primitive::push(context.status.get(), context); + auto flags = context.status.get(); + Primitive::push(flags, context); context.status.template set_from(0); // Push CS and IP. diff --git a/OSBindings/Mac/Clock SignalTests/8088Tests.mm b/OSBindings/Mac/Clock SignalTests/8088Tests.mm index 7507ae9f7..b3ceacae7 100644 --- a/OSBindings/Mac/Clock SignalTests/8088Tests.mm +++ b/OSBindings/Mac/Clock SignalTests/8088Tests.mm @@ -109,8 +109,6 @@ struct Memory { Seeded, AccessExpected, Accessed, - FlagsL, - FlagsH }; std::unordered_map tags; @@ -239,25 +237,7 @@ class FlowController { FlowController(Memory &memory, Registers ®isters, Status &status) : memory_(memory), registers_(registers), status_(status) {} - void interrupt(int index) { - // TODO: reauthorise and possibly double fault? - const uint16_t address = static_cast(index) << 2; - const uint16_t new_ip = memory_.access(address, Memory::Tag::Accessed); - const uint16_t new_cs = memory_.access(address + 2, Memory::Tag::Accessed); - - push(status_.get(), true); - - using Flag = InstructionSet::x86::Flag; - status_.set_from(0); - - // Push CS and IP. - push(registers_.cs_); - push(registers_.ip_); - - registers_.cs_ = new_cs; - registers_.ip_ = new_ip; - } - + // Requirements for perform. void jump(uint16_t address) { registers_.ip_ = address; } @@ -270,12 +250,14 @@ class FlowController { void halt() {} void wait() {} - void begin_instruction() { - should_repeat_ = false; - } void repeat_last() { should_repeat_ = true; } + + // Other actions. + void begin_instruction() { + should_repeat_ = false; + } bool should_repeat() const { return should_repeat_; } @@ -285,23 +267,6 @@ class FlowController { Registers ®isters_; Status &status_; bool should_repeat_ = false; - - void push(uint16_t value, bool is_flags = false) { - // Perform the push in two steps because it's possible for SP to underflow, and so that FlagsL and - // FlagsH can be set separately. - --registers_.sp_; - memory_.access( - InstructionSet::x86::Source::SS, - registers_.sp_, - is_flags ? Memory::Tag::FlagsH : Memory::Tag::Accessed - ) = value >> 8; - --registers_.sp_; - memory_.access( - InstructionSet::x86::Source::SS, - registers_.sp_, - is_flags ? Memory::Tag::FlagsL : Memory::Tag::Accessed - ) = value & 0xff; - } }; struct ExecutionSupport { @@ -556,21 +521,31 @@ struct FailedExecution { InstructionSet::x86::Status intended_status; bool ramEqual = true; + int mask_position = 0; for(NSArray *ram in final_state[@"ram"]) { const uint32_t address = [ram[0] intValue]; - uint8_t mask = 0xff; - if(const auto tag = execution_support.memory.tags.find(address); tag != execution_support.memory.tags.end()) { - switch(tag->second) { - default: break; - case Memory::Tag::FlagsH: mask = flags_mask >> 8; break; - case Memory::Tag::FlagsL: mask = flags_mask & 0xff; break; - } + if((mask_position != 1) && execution_support.memory.memory[address] == [ram[1] intValue]) { + continue; } - if((execution_support.memory.memory[address] & mask) != ([ram[1] intValue] & mask)) { - ramEqual = false; + // Consider whether this apparent mismatch might be because flags have been written to memory; + // allow only one use of the [16-bit] mask per test. + bool matched_with_mask = false; + while(mask_position < 2) { + const uint8_t mask = mask_position ? (flags_mask >> 8) : (flags_mask & 0xff); + ++mask_position; + if((execution_support.memory.memory[address] & mask) == ([ram[1] intValue] & mask)) { + matched_with_mask = true; + break; + } } + if(matched_with_mask) { + continue; + } + + ramEqual = false; + break; } [self populate:intended_registers status:intended_status value:final_state[@"regs"]];