diff --git a/InstructionSets/x86/Implementation/PerformImplementation.hpp b/InstructionSets/x86/Implementation/PerformImplementation.hpp index a5c427c22..ebabf7c1e 100644 --- a/InstructionSets/x86/Implementation/PerformImplementation.hpp +++ b/InstructionSets/x86/Implementation/PerformImplementation.hpp @@ -200,6 +200,88 @@ void add(IntT &destination, IntT source, Status &status) { } +template +typename DataSizeType::type *resolve(InstructionT &instruction, DataPointer source, RegistersT ®isters, MemoryT &memory) { + // Rules: + // + // * if this is a memory access, set target_address and break; + // * otherwise return the appropriate value. + uint32_t address; + switch(source.source()) { + case Source::eAX: + // Slightly contorted if chain here and below: + // + // (i) does the `constexpr` version of a `switch`; and + // (i) ensures .eax() etc aren't called on @c registers for 16-bit processors, so they need not implement 32-bit storage. + if constexpr (is_32bit(model) && data_size == DataSize::DWord) { return ®isters.eax(); } + else if constexpr (data_size == DataSize::Word) { return ®isters.ax(); } + else if constexpr (data_size == DataSize::Byte) { return ®isters.al(); } + else { return nullptr; } + case Source::eCX: + if constexpr (is_32bit(model) && data_size == DataSize::DWord) { return ®isters.ecx(); } + else if constexpr (data_size == DataSize::Word) { return ®isters.cx(); } + else if constexpr (data_size == DataSize::Byte) { return ®isters.cl(); } + else { return nullptr; } + case Source::eDX: + if constexpr (is_32bit(model) && data_size == DataSize::DWord) { return ®isters.edx(); } + else if constexpr (data_size == DataSize::Word) { return ®isters.dx(); } + else if constexpr (data_size == DataSize::Byte) { return ®isters.dl(); } + else if constexpr (data_size == DataSize::DWord) { return nullptr; } + case Source::eBX: + if constexpr (is_32bit(model) && data_size == DataSize::DWord) { return ®isters.ebx(); } + else if constexpr (data_size == DataSize::Word) { return ®isters.bx(); } + else if constexpr (data_size == DataSize::Byte) { return ®isters.bl(); } + else if constexpr (data_size == DataSize::DWord) { return nullptr; } + case Source::eSPorAH: + if constexpr (is_32bit(model) && data_size == DataSize::DWord) { return ®isters.esp(); } + else if constexpr (data_size == DataSize::Word) { return ®isters.sp(); } + else if constexpr (data_size == DataSize::Byte) { return ®isters.ah(); } + else { return nullptr; } + case Source::eBPorCH: + if constexpr (is_32bit(model) && data_size == DataSize::DWord) { return ®isters.ebp(); } + else if constexpr (data_size == DataSize::Word) { return ®isters.bp(); } + else if constexpr (data_size == DataSize::Byte) { return ®isters.ch(); } + else { return nullptr; } + case Source::eSIorDH: + if constexpr (is_32bit(model) && data_size == DataSize::DWord) { return ®isters.esi(); } + else if constexpr (data_size == DataSize::Word) { return ®isters.si(); } + else if constexpr (data_size == DataSize::Byte) { return ®isters.dh(); } + else { return nullptr; } + case Source::eDIorBH: + if constexpr (is_32bit(model) && data_size == DataSize::DWord) { return ®isters.edi(); } + else if constexpr (data_size == DataSize::Word) { return ®isters.di(); } + else if constexpr (data_size == DataSize::Byte) { return ®isters.bh(); } + else { return nullptr; } + + case Source::ES: if constexpr (data_size == DataSize::Word) return ®isters.es(); else return nullptr; + case Source::CS: if constexpr (data_size == DataSize::Word) return ®isters.cs(); else return nullptr; + case Source::SS: if constexpr (data_size == DataSize::Word) return ®isters.ss(); else return nullptr; + case Source::DS: if constexpr (data_size == DataSize::Word) return ®isters.ds(); else return nullptr; + + // 16-bit models don't have FS and GS. + case Source::FS: if constexpr (is_32bit(model) && data_size == DataSize::Word) return ®isters.fs(); else return nullptr; + case Source::GS: if constexpr (is_32bit(model) && data_size == DataSize::Word) return ®isters.gs(); else return nullptr; + + case Source::Immediate: // TODO (here the use of a pointer falls down?) + + case Source::None: return nullptr; + + case Source::Indirect: // TODO + + case Source::IndirectNoBase: // TODO + + case Source::DirectAddress: + address = instruction.offset(); + break; + } + + // If execution has reached here then a memory fetch is required. + // Do it and exit. + const Source segment = source.segment(instruction.segment_override()); + using IntT = typename DataSizeType::type; + return &memory.template access(segment, address); +}; + template < Model model, DataSize data_size, @@ -219,85 +301,9 @@ template < using IntT = typename DataSizeType::type; using AddressT = typename AddressT::type; - IntT zero = 0; - auto data = [&](DataPointer source) -> IntT& { - // Rules: - // - // * if this is a memory access, set target_address and break; - // * otherwise return the appropriate value. - AddressT address; - switch(source.source()) { - case Source::eAX: - if constexpr (is_32bit(model) && data_size == DataSize::DWord) { return registers.eax(); } - else if constexpr (data_size == DataSize::DWord) { return zero; } - else if constexpr (data_size == DataSize::Word) { return registers.ax(); } - else { return registers.al(); } - case Source::eCX: - if constexpr (is_32bit(model) && data_size == DataSize::DWord) { return registers.ecx(); } - else if constexpr (data_size == DataSize::DWord) { return zero; } - else if constexpr (data_size == DataSize::Word) { return registers.cx(); } - else { return registers.cl(); } - case Source::eDX: - if constexpr (is_32bit(model) && data_size == DataSize::DWord) { return registers.edx(); } - else if constexpr (data_size == DataSize::DWord) { return zero; } - else if constexpr (data_size == DataSize::Word) { return registers.dx(); } - else { return registers.dl(); } - case Source::eBX: - if constexpr (is_32bit(model) && data_size == DataSize::DWord) { return registers.ebx(); } - else if constexpr (data_size == DataSize::DWord) { return zero; } - else if constexpr (data_size == DataSize::Word) { return registers.bx(); } - else { return registers.bl(); } - case Source::eSPorAH: - if constexpr (is_32bit(model) && data_size == DataSize::DWord) { return registers.esp(); } - else if constexpr (data_size == DataSize::DWord) { return zero; } - else if constexpr (data_size == DataSize::Word) { return registers.sp(); } - else { return registers.ah(); } - case Source::eBPorCH: - if constexpr (is_32bit(model) && data_size == DataSize::DWord) { return registers.ebp(); } - else if constexpr (data_size == DataSize::DWord) { return zero; } - else if constexpr (data_size == DataSize::Word) { return registers.bp(); } - else { return registers.ch(); } - case Source::eSIorDH: - if constexpr (is_32bit(model) && data_size == DataSize::DWord) { return registers.esi(); } - else if constexpr (data_size == DataSize::DWord) { return zero; } - else if constexpr (data_size == DataSize::Word) { return registers.si(); } - else { return registers.dh(); } - case Source::eDIorBH: - if constexpr (is_32bit(model) && data_size == DataSize::DWord) { return registers.edi(); } - else if constexpr (data_size == DataSize::DWord) { return zero; } - else if constexpr (data_size == DataSize::Word) { return registers.di(); } - else { return registers.bh(); } - - // TODO: the below. - default: -// case Source::ES: return registers.es(); -// case Source::CS: return registers.cs(); -// case Source::SS: return registers.ss(); -// case Source::DS: return registers.ds(); -// case Source::FS: return registers.fs(); -// case Source::GS: return registers.gs(); - - case Source::Immediate: // TODO (here the use of a reference falls down?) - - case Source::None: return zero; - - case Source::Indirect: // TODO - case Source::IndirectNoBase: // TODO - - case Source::DirectAddress: - address = instruction.offset(); - break; - } - - // If execution has reached here then a memory fetch is required. - // Do it and exit. - const Source segment = source.segment(instruction.segment_override()); - return memory.template access(segment, address); - }; - // Establish source() and destination() shorthand to fetch data if necessary. - auto source = [&]() -> IntT& { return data(instruction.source()); }; - auto destination = [&]() -> IntT& { return data(instruction.destination()); }; + auto source = [&]() -> IntT& { return *resolve(instruction, instruction.source(), registers, memory); }; + auto destination = [&]() -> IntT& { return *resolve(instruction, instruction.destination(), registers, memory); }; // Guide to the below: // diff --git a/OSBindings/Mac/Clock SignalTests/8088Tests.mm b/OSBindings/Mac/Clock SignalTests/8088Tests.mm index 3b4e5f3f2..fc747e0c4 100644 --- a/OSBindings/Mac/Clock SignalTests/8088Tests.mm +++ b/OSBindings/Mac/Clock SignalTests/8088Tests.mm @@ -66,6 +66,16 @@ struct Registers { uint16_t es_, cs_, ds_, ss_; uint16_t ip_; + uint16_t &es() { return es_; } + uint16_t &cs() { return cs_; } + uint16_t &ds() { return ds_; } + uint16_t &ss() { return ss_; } + +// uint32_t zero_ = 0; +// template IntT &zero() { +// return static_cast(zero); +// } + bool operator ==(const Registers &rhs) const { return ax_.full == rhs.ax_.full && @@ -210,17 +220,17 @@ struct FailedExecution { NSString *path = [NSString stringWithUTF8String:TestSuiteHome]; NSSet *allowList = [NSSet setWithArray:@[ // ADC - @"10.json.gz", @"11.json.gz", @"12.json.gz", @"13.json.gz", @"14.json.gz", @"15.json.gz", +// @"10.json.gz", @"11.json.gz", @"12.json.gz", @"13.json.gz", @"14.json.gz", @"15.json.gz", // TO add: 80/2, 81/2, 83/2 // ADD - @"00.json.gz", @"01.json.gz", @"02.json.gz", @"03.json.gz", @"04.json.gz", @"05.json.gz", + @"00.json.gz", //@"01.json.gz", @"02.json.gz", @"03.json.gz", @"04.json.gz", @"05.json.gz", // TO add: 80/0, 81/0, 83/0 - @"37.json.gz", // AAA - @"3F.json.gz", // AAS - @"D4.json.gz", // AAM - @"D5.json.gz", // AAD +// @"37.json.gz", // AAA +// @"3F.json.gz", // AAS +// @"D4.json.gz", // AAM +// @"D5.json.gz", // AAD ]]; NSSet *ignoreList = nil;