From 0bd63cf00f4e3c6cb5fa8d843f89032a5b9bfd8b Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 10 Feb 2022 09:35:05 -0500 Subject: [PATCH] Introduces the easy F page instructions. --- InstructionSets/x86/Decoder.cpp | 45 ++++++++++++++++++++++++++++----- InstructionSets/x86/Decoder.hpp | 4 ++- 2 files changed, 42 insertions(+), 7 deletions(-) diff --git a/InstructionSets/x86/Decoder.cpp b/InstructionSets/x86/Decoder.cpp index 380bd8c5a..bf03357bf 100644 --- a/InstructionSets/x86/Decoder.cpp +++ b/InstructionSets/x86/Decoder.cpp @@ -81,6 +81,12 @@ std::pair Decoder::decode(const uint8_t * displacement_size_ = 2; \ operand_size_ = 1; \ +#define undefined() { \ + const auto result = std::make_pair(consumed_, Instruction()); \ + reset_parsing(); \ + return result; \ +} + while(phase_ == Phase::Instruction && source != end) { // Retain the instruction byte, in case additional decoding is deferred // to the ModRegRM byte. @@ -88,12 +94,6 @@ std::pair Decoder::decode(const uint8_t * ++source; ++consumed_; -#define undefined() { \ - const auto result = std::make_pair(consumed_, Instruction()); \ - reset_parsing(); \ - return result; \ -} - switch(instr_) { default: undefined(); @@ -112,6 +112,13 @@ std::pair Decoder::decode(const uint8_t * PartialBlock(0x08, OR); break; case 0x0e: Complete(PUSH, CS, None, 2); break; + // The 286 onwards have a further set of instructions + // prefixed with $0f. + case 0x0f: + if(model_ < Model::i80286) undefined(); + phase_ = Phase::InstructionPageF; + break; + PartialBlock(0x10, ADC); break; case 0x16: Complete(PUSH, SS, None, 2); break; case 0x17: Complete(POP, None, SS, 2); break; @@ -167,6 +174,10 @@ std::pair Decoder::decode(const uint8_t * if(model_ < Model::i80186) undefined(); MemRegReg(BOUND, Reg_MemReg, 2); break; + case 0x63: + if(model_ < Model::i80286) undefined(); + MemRegReg(ARPL, MemReg_Reg, 2); + break; case 0x6c: // INSB if(model_ < Model::i80186) undefined(); Complete(INS, None, None, 1); @@ -365,6 +376,28 @@ std::pair Decoder::decode(const uint8_t * } } + // MARK: - Additional F page of instructions. + if(phase_ == Phase::InstructionPageF && source != end) { + // Update the instruction acquired. + instr_ = 0x0f00 | *source; + ++source; + ++consumed_; + + // NB: to reach here, the instruction set must be at least + // that of an 80286. + switch(instr_) { + default: undefined(); + + case 0x02: MemRegReg(LAR, Reg_MemReg, 2); break; + case 0x03: MemRegReg(LSL, Reg_MemReg, 2); break; + case 0x06: Complete(CLTS, None, None, 1); break; + } + // TODO: 0x0f 0x00 -> LLDT/SLDT/VERR/VERW/LTR/STR + // TODO: 0x0f 0x01 -> LGDT/LIDT/SGDT/SIDT/LMSW/SMSW + // TODO: 0x0f 0x05 -> LOADALL + + } + #undef Far #undef Jump #undef MemRegReg diff --git a/InstructionSets/x86/Decoder.hpp b/InstructionSets/x86/Decoder.hpp index 4f0cdcc7b..dd0182d36 100644 --- a/InstructionSets/x86/Decoder.hpp +++ b/InstructionSets/x86/Decoder.hpp @@ -48,6 +48,8 @@ class Decoder { enum class Phase { /// Captures all prefixes and continues until an instruction byte is encountered. Instruction, + /// Having encountered a 0x0f first instruction byte, waits for the next byte fully to determine the instruction. + InstructionPageF, /// Receives a ModRegRM byte and either populates the source_ and dest_ fields appropriately /// or completes decoding of the instruction, as per the instruction format. ModRegRM, @@ -119,7 +121,7 @@ class Decoder { // Ephemeral decoding state. Operation operation_ = Operation::Invalid; - uint8_t instr_ = 0x00; // TODO: is this desired, versus loading more context into ModRegRMFormat? + uint16_t instr_ = 0x0000; // TODO: is this desired, versus loading more context into ModRegRMFormat? int consumed_ = 0, operand_bytes_ = 0; // Source and destination locations.