From 8a8c044976be1c16360fd9b62df21edf51ae7c7e Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Fri, 28 Oct 2022 13:36:40 -0400 Subject: [PATCH] Support up to 15 extension words on a Preinstruction; use that to describe PACK/UNPK. TODO: reconcile when to use that field versus the ExtensionWord operand. Probably only when operands are full? --- InstructionSets/M68k/Decoder.cpp | 33 ++++++++++++++++++---------- InstructionSets/M68k/Decoder.hpp | 3 ++- InstructionSets/M68k/Instruction.cpp | 3 +++ InstructionSets/M68k/Instruction.hpp | 25 ++++++++++----------- 4 files changed, 37 insertions(+), 27 deletions(-) diff --git a/InstructionSets/M68k/Decoder.cpp b/InstructionSets/M68k/Decoder.cpp index 4b5f58fd5..73df81fce 100644 --- a/InstructionSets/M68k/Decoder.cpp +++ b/InstructionSets/M68k/Decoder.cpp @@ -564,9 +564,10 @@ template ::OpT op> uint32_t Predecoder::invali Dn | Ind | d16An | d8AnXn | XXXw | XXXl | d16PC | d8PCXn >::value; - case OpT(Operation::PACK): - return ~OneOperandMask< - Imm + case OpT(Operation::PACK): case OpT(Operation::UNPK): + return ~TwoOperandMask< + Dn | PreDec, + Dn | PreDec >::value; } @@ -578,7 +579,8 @@ template template ::OpT op, bool validate> Preinstruction Predecoder::validated( AddressingMode op1_mode, int op1_reg, AddressingMode op2_mode, int op2_reg, - Condition condition + Condition condition, + int additional_extension_words ) { constexpr auto operation = Predecoder::operation(op); @@ -588,7 +590,7 @@ template ::OpT op, bool validate> Preinstruction Pred op1_mode, op1_reg, op2_mode, op2_reg, requires_supervisor(operation), - requires_extension_word(operation), + additional_extension_words, operand_size(operation), condition); } @@ -602,7 +604,7 @@ template ::OpT op, bool validate> Preinstruction Pred op1_mode, op1_reg, op2_mode, op2_reg, requires_supervisor(operation), - requires_extension_word(operation), + additional_extension_words, operand_size(operation), condition); } @@ -1135,17 +1137,23 @@ template ::OpT op, bool validate> Preinstruction Pred } // - // MARK: PACK + // MARK: PACK, UNPK // - // b0–b2: a register number; - // b3: address/data register selection — if address registers, then this is predec; - // b9–b11: an additional register number. + // b9–b11: Rx (destination) + // b0–b2: Ry (source) + // b3: 1 => operation is memory-to-memory; 0 => register-to-register. // This instruction is also followed by a 16-bit adjustment extension. // case OpT(Operation::PACK): - // TODO; need to square the wheel on a prima-facie three operands. - return Preinstruction(); + case OpT(Operation::UNPK): { + const auto addressing_mode = (instruction & 8) ? + AddressingMode::AddressRegisterIndirectWithPredecrement : AddressingMode::DataRegisterDirect; + return validated( + addressing_mode, ea_register, + addressing_mode, data_register, + Condition::True, 1); + } // // MARK: DIVl @@ -1547,6 +1555,7 @@ Preinstruction Predecoder::decode8(uint16_t instruction) { switch(instruction & 0x1f0) { case 0x100: Decode(Op::SBCD); // 4-171 (p275) case 0x140: DecodeReq(model >= Model::M68020, Op::PACK); // 4-157 (p261) + case 0x180: DecodeReq(model >= Model::M68020, Op::UNPK); // 4-196 (p300) default: break; } diff --git a/InstructionSets/M68k/Decoder.hpp b/InstructionSets/M68k/Decoder.hpp index 47815c2b0..d54cdabfd 100644 --- a/InstructionSets/M68k/Decoder.hpp +++ b/InstructionSets/M68k/Decoder.hpp @@ -66,7 +66,8 @@ template class Predecoder { template Preinstruction validated( AddressingMode op1_mode = AddressingMode::None, int op1_reg = 0, AddressingMode op2_mode = AddressingMode::None, int op2_reg = 0, - Condition condition = Condition::True + Condition condition = Condition::True, + int further_extension_words = 0 ); template uint32_t invalid_operands(); diff --git a/InstructionSets/M68k/Instruction.cpp b/InstructionSets/M68k/Instruction.cpp index 352926ca8..641cfa17b 100644 --- a/InstructionSets/M68k/Instruction.cpp +++ b/InstructionSets/M68k/Instruction.cpp @@ -294,6 +294,9 @@ std::string Preinstruction::to_string(int opcode) const { if(!operand1.empty()) result += std::string(" ") + operand1; if(!operand2.empty()) result += std::string(", ") + operand2; + const int extension_words = additional_extension_words(); + if(extension_words) result += std::string(" [+") + std::to_string(extension_words) + "]"; + return result; } diff --git a/InstructionSets/M68k/Instruction.hpp b/InstructionSets/M68k/Instruction.hpp index e08d1727e..bf323bf71 100644 --- a/InstructionSets/M68k/Instruction.hpp +++ b/InstructionSets/M68k/Instruction.hpp @@ -215,16 +215,6 @@ constexpr bool requires_supervisor(Operation op) { } } -inline constexpr bool requires_extension_word(Operation op) { - switch(op) { - case Operation::PACK: - return true; - - default: - return false; - } -} - enum class DataSize { Byte = 0, Word = 1, @@ -426,6 +416,10 @@ class Preinstruction { bool requires_further_extension() const { return flags_ & Flags::RequiresFurtherExtension; } + /// @returns The number of additional extension words required, beyond those encoded as operands. + int additional_extension_words() const { + return flags_ & Flags::RequiresFurtherExtension ? (flags_ & Flags::ConditionMask) >> Flags::ConditionShift : 0; + } /// @returns The @c DataSize used for operands of this instruction, i.e. byte, word or longword. DataSize operand_size() const { return DataSize((flags_ & Flags::SizeMask) >> Flags::SizeShift); @@ -448,7 +442,7 @@ class Preinstruction { AddressingMode op1_mode, int op1_reg, AddressingMode op2_mode, int op2_reg, bool is_supervisor, - bool requires_further_extension, + int extension_words, DataSize size, Condition condition) : operation(operation) { @@ -456,8 +450,9 @@ class Preinstruction { operands_[1] = uint8_t((uint8_t(op2_mode) << 3) | op2_reg); flags_ = uint8_t( (is_supervisor ? Flags::IsSupervisor : 0x00) | - (requires_further_extension ? Flags::RequiresFurtherExtension : 0x00) | + (extension_words ? Flags::RequiresFurtherExtension : 0x00) | (int(condition) << Flags::ConditionShift) | + (extension_words << Flags::ConditionShift) | (int(size) << Flags::SizeShift) ); } @@ -468,8 +463,10 @@ class Preinstruction { static constexpr uint8_t ConditionMask = 0b0011'1100; static constexpr uint8_t SizeMask = 0b0000'0011; - static constexpr int ConditionShift = 2; - static constexpr int SizeShift = 0; + static constexpr int IsSupervisorShift = 7; + static constexpr int RequiresFurtherExtensionShift = 6; + static constexpr int ConditionShift = 2; + static constexpr int SizeShift = 0; }; Preinstruction() {}