diff --git a/InstructionSets/x86/Decoder.cpp b/InstructionSets/x86/Decoder.cpp index 48f9fe77a..380bd8c5a 100644 --- a/InstructionSets/x86/Decoder.cpp +++ b/InstructionSets/x86/Decoder.cpp @@ -15,7 +15,7 @@ using namespace InstructionSet::x86; // Only 8086 is suppoted for now. -Decoder::Decoder(Model) {} +Decoder::Decoder(Model model) : model_(model) {} std::pair Decoder::decode(const uint8_t *source, size_t length) { const uint8_t *const end = source + length; @@ -74,6 +74,13 @@ std::pair Decoder::decode(const uint8_t * phase_ = Phase::DisplacementOrOperand; \ operand_size_ = 4; \ +/// Handles ENTER — a fixed three-byte operation. +#define Displacement16Operand8(op) \ + operation_ = Operation::op; \ + phase_ = Phase::DisplacementOrOperand; \ + displacement_size_ = 2; \ + operand_size_ = 1; \ + while(phase_ == Phase::Instruction && source != end) { // Retain the instruction byte, in case additional decoding is deferred // to the ModRegRM byte. @@ -81,12 +88,14 @@ 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: { - const auto result = std::make_pair(consumed_, Instruction()); - reset_parsing(); - return result; - } + default: undefined(); #define PartialBlock(start, operation) \ case start + 0x00: MemRegReg(operation, MemReg_Reg, 1); break; \ @@ -146,7 +155,34 @@ std::pair Decoder::decode(const uint8_t * #undef RegisterBlock - // 0x60–0x6f: not used. + case 0x60: + if(model_ < Model::i80186) undefined(); + Complete(PUSHA, None, None, 2); + break; + case 0x61: + if(model_ < Model::i80186) undefined(); + Complete(POPA, None, None, 2); + break; + case 0x62: + if(model_ < Model::i80186) undefined(); + MemRegReg(BOUND, Reg_MemReg, 2); + break; + case 0x6c: // INSB + if(model_ < Model::i80186) undefined(); + Complete(INS, None, None, 1); + break; + case 0x6d: // INSW + if(model_ < Model::i80186) undefined(); + Complete(INS, None, None, 2); + break; + case 0x6e: // OUTSB + if(model_ < Model::i80186) undefined(); + Complete(OUTS, None, None, 1); + break; + case 0x6f: // OUTSW + if(model_ < Model::i80186) undefined(); + Complete(OUTS, None, None, 2); + break; case 0x70: Jump(JO); break; case 0x71: Jump(JNO); break; @@ -243,6 +279,15 @@ std::pair Decoder::decode(const uint8_t * case 0xc6: MemRegReg(MOV, MemRegMOV, 1); break; case 0xc7: MemRegReg(MOV, MemRegMOV, 2); break; + case 0xc8: + if(model_ < Model::i80186) undefined(); + Displacement16Operand8(ENTER); + break; + case 0xc9: + if(model_ < Model::i80186) undefined(); + Complete(LEAVE, None, None, 0); + break; + case 0xca: RegData(RETF, None, 2); break; case 0xcb: Complete(RETF, None, None, 4); break; diff --git a/InstructionSets/x86/Decoder.hpp b/InstructionSets/x86/Decoder.hpp index fe2879b22..4f0cdcc7b 100644 --- a/InstructionSets/x86/Decoder.hpp +++ b/InstructionSets/x86/Decoder.hpp @@ -19,6 +19,9 @@ namespace x86 { enum class Model { i8086, + i80186, + i80286, + i80386, }; /*! @@ -40,6 +43,8 @@ class Decoder { std::pair decode(const uint8_t *source, size_t length); private: + const Model model_; + enum class Phase { /// Captures all prefixes and continues until an instruction byte is encountered. Instruction, diff --git a/InstructionSets/x86/Instruction.hpp b/InstructionSets/x86/Instruction.hpp index 135422d2d..2531daf84 100644 --- a/InstructionSets/x86/Instruction.hpp +++ b/InstructionSets/x86/Instruction.hpp @@ -208,21 +208,19 @@ enum class Operation: uint8_t { /// Create stack frame. ENTER, - /// Procedure exit. + /// Procedure exit; copies BP to SP, then pops a new BP from the stack. LEAVE, - /// Inputs a byte from a port, incrementing or decrementing the destination. - INSB, - /// Inputs a word from a port, incrementing or decrementingthe destination. - INSW, - /// Outputs a byte to a port, incrementing or decrementing the destination. - OUTSB, - /// Outputs a word to a port, incrementing or decrementing the destination. - OUTSW, + /// Inputs from a port, incrementing or decrementing the destination. + INS, + /// Outputs to a port, incrementing or decrementing the destination. + OUTS, - /// Pushes all general purpose registers to the stack. + /// Pushes all general purpose registers to the stack, in the order: + /// AX, CX, DX, BX, [original] SP, BP, SI, DI. PUSHA, - /// Pops all general purpose registers from the stack. + /// Pops all general purpose registers from the stack, in the reverse of + /// the PUSHA order, i.e. DI, SI, BP, [final] SP, BX, DX, CX, AX. POPA, //