1*04eeddc0SDimitry Andric //===-- M68kDisassembler.cpp - Disassembler for M68k ------------*- C++ -*-===// 2fe6060f1SDimitry Andric // 3fe6060f1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4fe6060f1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5fe6060f1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6fe6060f1SDimitry Andric // 7fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 8fe6060f1SDimitry Andric // 9fe6060f1SDimitry Andric // This file is part of the M68k Disassembler. 10fe6060f1SDimitry Andric // 11fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 12fe6060f1SDimitry Andric 13fe6060f1SDimitry Andric #include "M68k.h" 14fe6060f1SDimitry Andric #include "M68kRegisterInfo.h" 15fe6060f1SDimitry Andric #include "M68kSubtarget.h" 16fe6060f1SDimitry Andric #include "MCTargetDesc/M68kMCCodeEmitter.h" 17fe6060f1SDimitry Andric #include "MCTargetDesc/M68kMCTargetDesc.h" 18fe6060f1SDimitry Andric #include "TargetInfo/M68kTargetInfo.h" 19fe6060f1SDimitry Andric 20fe6060f1SDimitry Andric #include "llvm/MC/MCAsmInfo.h" 21fe6060f1SDimitry Andric #include "llvm/MC/MCContext.h" 22fe6060f1SDimitry Andric #include "llvm/MC/MCDisassembler/MCDisassembler.h" 23fe6060f1SDimitry Andric #include "llvm/MC/MCInst.h" 24349cc55cSDimitry Andric #include "llvm/MC/TargetRegistry.h" 25fe6060f1SDimitry Andric 26fe6060f1SDimitry Andric using namespace llvm; 27fe6060f1SDimitry Andric 28fe6060f1SDimitry Andric #define DEBUG_TYPE "m68k-disassembler" 29fe6060f1SDimitry Andric 30fe6060f1SDimitry Andric typedef MCDisassembler::DecodeStatus DecodeStatus; 31fe6060f1SDimitry Andric 32fe6060f1SDimitry Andric namespace { 33fe6060f1SDimitry Andric constexpr unsigned MaxInstructionWords = 11; 34fe6060f1SDimitry Andric 35fe6060f1SDimitry Andric class M68kInstructionBuffer { 36fe6060f1SDimitry Andric typedef SmallVector<uint16_t, MaxInstructionWords> BufferType; 37fe6060f1SDimitry Andric BufferType Buffer; 38fe6060f1SDimitry Andric 39fe6060f1SDimitry Andric public: 40fe6060f1SDimitry Andric M68kInstructionBuffer() {} 41fe6060f1SDimitry Andric 42fe6060f1SDimitry Andric template <typename TIt> 43fe6060f1SDimitry Andric M68kInstructionBuffer(TIt Start, TIt End) : Buffer(Start, End) {} 44fe6060f1SDimitry Andric 45fe6060f1SDimitry Andric unsigned size() const { return Buffer.size(); } 46fe6060f1SDimitry Andric 47fe6060f1SDimitry Andric BufferType::const_iterator begin() const { return Buffer.begin(); } 48fe6060f1SDimitry Andric BufferType::const_iterator end() const { return Buffer.end(); } 49fe6060f1SDimitry Andric 50fe6060f1SDimitry Andric uint16_t operator[](unsigned Index) const { 51fe6060f1SDimitry Andric assert((Index < Buffer.size()) && "tried to read out of bounds word"); 52fe6060f1SDimitry Andric return Buffer[Index]; 53fe6060f1SDimitry Andric } 54fe6060f1SDimitry Andric 55fe6060f1SDimitry Andric void truncate(unsigned NewLength) { 56fe6060f1SDimitry Andric assert((NewLength <= Buffer.size()) && 57fe6060f1SDimitry Andric "instruction buffer too short to truncate"); 58fe6060f1SDimitry Andric Buffer.resize(NewLength); 59fe6060f1SDimitry Andric } 60fe6060f1SDimitry Andric 61fe6060f1SDimitry Andric void dump() const; 62fe6060f1SDimitry Andric 63fe6060f1SDimitry Andric static M68kInstructionBuffer fill(ArrayRef<uint8_t> Bytes); 64fe6060f1SDimitry Andric }; 65fe6060f1SDimitry Andric 66fe6060f1SDimitry Andric class M68kInstructionReader { 67fe6060f1SDimitry Andric M68kInstructionBuffer Buffer; 68fe6060f1SDimitry Andric unsigned NumRead; 69fe6060f1SDimitry Andric 70fe6060f1SDimitry Andric public: 71fe6060f1SDimitry Andric M68kInstructionReader(M68kInstructionBuffer Buf) : Buffer(Buf), NumRead(0) {} 72fe6060f1SDimitry Andric 73fe6060f1SDimitry Andric unsigned size() const { return (Buffer.size() * 16) - NumRead; } 74fe6060f1SDimitry Andric 75fe6060f1SDimitry Andric uint64_t readBits(unsigned NumBits); 76fe6060f1SDimitry Andric }; 77fe6060f1SDimitry Andric 78fe6060f1SDimitry Andric struct M68kInstructionLookup { 79fe6060f1SDimitry Andric unsigned OpCode; 80fe6060f1SDimitry Andric M68kInstructionBuffer Mask; 81fe6060f1SDimitry Andric M68kInstructionBuffer Value; 82fe6060f1SDimitry Andric 83fe6060f1SDimitry Andric unsigned size() const { return Mask.size(); } 84fe6060f1SDimitry Andric 85fe6060f1SDimitry Andric // Check whether this instruction could possibly match the given bytes. 86fe6060f1SDimitry Andric bool matches(const M68kInstructionBuffer &Test) const; 87fe6060f1SDimitry Andric void dump() const; 88fe6060f1SDimitry Andric }; 89fe6060f1SDimitry Andric 90fe6060f1SDimitry Andric class M68kInstructionLookupBuilder { 91fe6060f1SDimitry Andric std::array<uint16_t, MaxInstructionWords> Mask; 92fe6060f1SDimitry Andric std::array<uint16_t, MaxInstructionWords> Value; 93fe6060f1SDimitry Andric unsigned NumWritten; 94fe6060f1SDimitry Andric 95fe6060f1SDimitry Andric public: 96fe6060f1SDimitry Andric M68kInstructionLookupBuilder() : NumWritten(0) { 97fe6060f1SDimitry Andric Mask.fill(0); 98fe6060f1SDimitry Andric Value.fill(0); 99fe6060f1SDimitry Andric } 100fe6060f1SDimitry Andric 101fe6060f1SDimitry Andric unsigned numWords() const { 102fe6060f1SDimitry Andric assert(!(NumWritten & 0xf) && "instructions must be whole words"); 103fe6060f1SDimitry Andric return NumWritten >> 4; 104fe6060f1SDimitry Andric } 105fe6060f1SDimitry Andric 106fe6060f1SDimitry Andric bool isValid() const; 107fe6060f1SDimitry Andric M68kInstructionLookup build(unsigned OpCode); 108fe6060f1SDimitry Andric void addBits(unsigned N, uint64_t Bits); 109fe6060f1SDimitry Andric void skipBits(unsigned N); 110fe6060f1SDimitry Andric }; 111fe6060f1SDimitry Andric 112fe6060f1SDimitry Andric /// A disassembler class for M68k. 113fe6060f1SDimitry Andric class M68kDisassembler : public MCDisassembler { 114fe6060f1SDimitry Andric MCInstrInfo *MCII; 115fe6060f1SDimitry Andric std::vector<M68kInstructionLookup> Lookups; 116fe6060f1SDimitry Andric 117fe6060f1SDimitry Andric public: 118fe6060f1SDimitry Andric M68kDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx, 119fe6060f1SDimitry Andric MCInstrInfo *MCII) 120fe6060f1SDimitry Andric : MCDisassembler(STI, Ctx), MCII(MCII) { 121fe6060f1SDimitry Andric buildBeadTable(); 122fe6060f1SDimitry Andric } 123fe6060f1SDimitry Andric virtual ~M68kDisassembler() {} 124fe6060f1SDimitry Andric 125fe6060f1SDimitry Andric void buildBeadTable(); 126fe6060f1SDimitry Andric DecodeStatus getInstruction(MCInst &Instr, uint64_t &Size, 127fe6060f1SDimitry Andric ArrayRef<uint8_t> Bytes, uint64_t Address, 128fe6060f1SDimitry Andric raw_ostream &CStream) const override; 129fe6060f1SDimitry Andric void decodeReg(MCInst &Instr, unsigned int Bead, 130fe6060f1SDimitry Andric M68kInstructionReader &Reader, unsigned &Scratch) const; 131fe6060f1SDimitry Andric void decodeImm(MCInst &Instr, unsigned int Bead, 132fe6060f1SDimitry Andric M68kInstructionReader &Reader, unsigned &Scratch) const; 133fe6060f1SDimitry Andric unsigned int getRegOperandIndex(MCInst &Instr, unsigned int Bead) const; 134fe6060f1SDimitry Andric unsigned int getImmOperandIndex(MCInst &Instr, unsigned int Bead) const; 135fe6060f1SDimitry Andric }; 136fe6060f1SDimitry Andric } // namespace 137fe6060f1SDimitry Andric 138fe6060f1SDimitry Andric static unsigned RegisterDecode[] = { 139fe6060f1SDimitry Andric M68k::A0, M68k::A1, M68k::A2, M68k::A3, M68k::A4, M68k::A5, 140fe6060f1SDimitry Andric M68k::A6, M68k::SP, M68k::D0, M68k::D1, M68k::D2, M68k::D3, 141fe6060f1SDimitry Andric M68k::D4, M68k::D5, M68k::D6, M68k::D7, 142fe6060f1SDimitry Andric }; 143fe6060f1SDimitry Andric 144fe6060f1SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 145fe6060f1SDimitry Andric LLVM_DUMP_METHOD 146fe6060f1SDimitry Andric void M68kInstructionBuffer::dump() const { 147fe6060f1SDimitry Andric for (auto Word : Buffer) { 148fe6060f1SDimitry Andric for (unsigned B = 0; B < 16; ++B) { 149fe6060f1SDimitry Andric uint16_t Bit = (1 << (16 - B - 1)); 150fe6060f1SDimitry Andric unsigned IsClear = !(Word & Bit); 151fe6060f1SDimitry Andric 152fe6060f1SDimitry Andric if (B == 8) 153fe6060f1SDimitry Andric dbgs() << " "; 154fe6060f1SDimitry Andric 155fe6060f1SDimitry Andric char Ch = IsClear ? '0' : '1'; 156fe6060f1SDimitry Andric dbgs() << Ch; 157fe6060f1SDimitry Andric } 158fe6060f1SDimitry Andric 159fe6060f1SDimitry Andric dbgs() << " "; 160fe6060f1SDimitry Andric } 161fe6060f1SDimitry Andric 162fe6060f1SDimitry Andric dbgs() << "\n"; 163fe6060f1SDimitry Andric } 164fe6060f1SDimitry Andric #endif 165fe6060f1SDimitry Andric 166fe6060f1SDimitry Andric M68kInstructionBuffer M68kInstructionBuffer::fill(ArrayRef<uint8_t> Bytes) { 167fe6060f1SDimitry Andric SmallVector<uint16_t, MaxInstructionWords> Buffer; 168fe6060f1SDimitry Andric Buffer.resize(std::min(Bytes.size() / 2, Buffer.max_size())); 169fe6060f1SDimitry Andric 170fe6060f1SDimitry Andric for (unsigned I = 0, E = Buffer.size(); I < E; ++I) { 171fe6060f1SDimitry Andric unsigned Offset = I * 2; 172fe6060f1SDimitry Andric uint64_t Hi = Bytes[Offset]; 173fe6060f1SDimitry Andric uint64_t Lo = Bytes[Offset + 1]; 174fe6060f1SDimitry Andric uint64_t Word = (Hi << 8) | Lo; 175fe6060f1SDimitry Andric Buffer[I] = Word; 176fe6060f1SDimitry Andric 177fe6060f1SDimitry Andric LLVM_DEBUG( 178fe6060f1SDimitry Andric errs() << format("Read word %x (%d)\n", (unsigned)Word, Buffer.size())); 179fe6060f1SDimitry Andric } 180fe6060f1SDimitry Andric 181fe6060f1SDimitry Andric return M68kInstructionBuffer(Buffer.begin(), Buffer.end()); 182fe6060f1SDimitry Andric } 183fe6060f1SDimitry Andric 184fe6060f1SDimitry Andric uint64_t M68kInstructionReader::readBits(unsigned NumBits) { 185fe6060f1SDimitry Andric assert((size() >= NumBits) && "not enough bits to read"); 186fe6060f1SDimitry Andric 187fe6060f1SDimitry Andric // We have to read the bits in 16-bit chunks because we read them as 188fe6060f1SDimitry Andric // 16-bit words but they're actually written in big-endian. If a read 189fe6060f1SDimitry Andric // crosses a word boundary we have to be careful. 190fe6060f1SDimitry Andric 191fe6060f1SDimitry Andric uint64_t Value = 0; 192fe6060f1SDimitry Andric unsigned BitsRead = 0; 193fe6060f1SDimitry Andric 194fe6060f1SDimitry Andric while (BitsRead < NumBits) { 195fe6060f1SDimitry Andric unsigned AvailableThisWord = 16 - (NumRead & 0xf); 196fe6060f1SDimitry Andric unsigned ToRead = std::min(NumBits, AvailableThisWord); 197fe6060f1SDimitry Andric 198fe6060f1SDimitry Andric unsigned WordIndex = NumRead >> 4; 199fe6060f1SDimitry Andric uint64_t ThisWord = Buffer[WordIndex] >> (NumRead & 0xf); 200fe6060f1SDimitry Andric uint64_t Mask = (1 << ToRead) - 1; 201fe6060f1SDimitry Andric Value |= (ThisWord & Mask) << BitsRead; 202fe6060f1SDimitry Andric NumRead += ToRead; 203fe6060f1SDimitry Andric BitsRead += ToRead; 204fe6060f1SDimitry Andric } 205fe6060f1SDimitry Andric return Value; 206fe6060f1SDimitry Andric } 207fe6060f1SDimitry Andric 208fe6060f1SDimitry Andric bool M68kInstructionLookup::matches(const M68kInstructionBuffer &Test) const { 209fe6060f1SDimitry Andric if (Test.size() < Value.size()) 210fe6060f1SDimitry Andric return false; 211fe6060f1SDimitry Andric 212fe6060f1SDimitry Andric for (unsigned I = 0, E = Value.size(); I < E; ++I) { 213fe6060f1SDimitry Andric uint16_t Have = Test[I]; 214fe6060f1SDimitry Andric uint16_t Need = Value[I]; 215fe6060f1SDimitry Andric uint16_t WordMask = Mask[I]; 216fe6060f1SDimitry Andric 217fe6060f1SDimitry Andric if ((Have & WordMask) != Need) 218fe6060f1SDimitry Andric return false; 219fe6060f1SDimitry Andric } 220fe6060f1SDimitry Andric 221fe6060f1SDimitry Andric return true; 222fe6060f1SDimitry Andric } 223fe6060f1SDimitry Andric 224fe6060f1SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 225fe6060f1SDimitry Andric LLVM_DUMP_METHOD 226fe6060f1SDimitry Andric void M68kInstructionLookup::dump() const { 227fe6060f1SDimitry Andric dbgs() << "M68kInstructionLookup " << OpCode << " "; 228fe6060f1SDimitry Andric 229fe6060f1SDimitry Andric for (unsigned I = 0, E = Mask.size(); I < E; ++I) { 230fe6060f1SDimitry Andric uint16_t WordMask = Mask[I]; 231fe6060f1SDimitry Andric uint16_t WordValue = Value[I]; 232fe6060f1SDimitry Andric 233fe6060f1SDimitry Andric for (unsigned B = 0; B < 16; ++B) { 234fe6060f1SDimitry Andric uint16_t Bit = (1 << (15 - B)); 235fe6060f1SDimitry Andric unsigned IsMasked = !(WordMask & Bit); 236fe6060f1SDimitry Andric unsigned IsClear = !(WordValue & Bit); 237fe6060f1SDimitry Andric 238fe6060f1SDimitry Andric if (B == 8) 239fe6060f1SDimitry Andric dbgs() << " "; 240fe6060f1SDimitry Andric 241fe6060f1SDimitry Andric char Ch = IsMasked ? '?' : (IsClear ? '0' : '1'); 242fe6060f1SDimitry Andric dbgs() << Ch; 243fe6060f1SDimitry Andric } 244fe6060f1SDimitry Andric 245fe6060f1SDimitry Andric dbgs() << " "; 246fe6060f1SDimitry Andric } 247fe6060f1SDimitry Andric 248fe6060f1SDimitry Andric dbgs() << "\n"; 249fe6060f1SDimitry Andric } 250fe6060f1SDimitry Andric #endif 251fe6060f1SDimitry Andric 252fe6060f1SDimitry Andric bool M68kInstructionLookupBuilder::isValid() const { 253fe6060f1SDimitry Andric for (unsigned I = 0, E = numWords(); I < E; ++I) 254fe6060f1SDimitry Andric if (Mask[I]) 255fe6060f1SDimitry Andric return true; 256fe6060f1SDimitry Andric 257fe6060f1SDimitry Andric return false; 258fe6060f1SDimitry Andric } 259fe6060f1SDimitry Andric 260fe6060f1SDimitry Andric M68kInstructionLookup M68kInstructionLookupBuilder::build(unsigned OpCode) { 261fe6060f1SDimitry Andric unsigned NumWords = numWords(); 262fe6060f1SDimitry Andric M68kInstructionBuffer MaskBuffer(Mask.begin(), Mask.begin() + NumWords); 263fe6060f1SDimitry Andric M68kInstructionBuffer ValueBuffer(Value.begin(), Value.begin() + NumWords); 264fe6060f1SDimitry Andric M68kInstructionLookup Ret; 265fe6060f1SDimitry Andric Ret.OpCode = OpCode; 266fe6060f1SDimitry Andric Ret.Mask = MaskBuffer; 267fe6060f1SDimitry Andric Ret.Value = ValueBuffer; 268fe6060f1SDimitry Andric return Ret; 269fe6060f1SDimitry Andric } 270fe6060f1SDimitry Andric 271fe6060f1SDimitry Andric void M68kInstructionLookupBuilder::addBits(unsigned N, uint64_t Bits) { 272fe6060f1SDimitry Andric while (N > 0) { 273fe6060f1SDimitry Andric unsigned WordIndex = NumWritten >> 4; 274fe6060f1SDimitry Andric unsigned WordOffset = NumWritten & 0xf; 275fe6060f1SDimitry Andric unsigned AvailableThisWord = 16 - WordOffset; 276fe6060f1SDimitry Andric unsigned ToWrite = std::min(AvailableThisWord, N); 277fe6060f1SDimitry Andric 278fe6060f1SDimitry Andric uint16_t WordMask = (1 << ToWrite) - 1; 279fe6060f1SDimitry Andric uint16_t BitsToWrite = Bits & WordMask; 280fe6060f1SDimitry Andric 281fe6060f1SDimitry Andric Value[WordIndex] |= (BitsToWrite << WordOffset); 282fe6060f1SDimitry Andric Mask[WordIndex] |= (WordMask << WordOffset); 283fe6060f1SDimitry Andric 284fe6060f1SDimitry Andric Bits >>= ToWrite; 285fe6060f1SDimitry Andric N -= ToWrite; 286fe6060f1SDimitry Andric NumWritten += ToWrite; 287fe6060f1SDimitry Andric } 288fe6060f1SDimitry Andric } 289fe6060f1SDimitry Andric 290fe6060f1SDimitry Andric void M68kInstructionLookupBuilder::skipBits(unsigned N) { NumWritten += N; } 291fe6060f1SDimitry Andric 292fe6060f1SDimitry Andric // This is a bit of a hack: we can't generate this table at table-gen time 293fe6060f1SDimitry Andric // because some of the definitions are in our platform. 294fe6060f1SDimitry Andric void M68kDisassembler::buildBeadTable() { 295fe6060f1SDimitry Andric const unsigned NumInstr = M68k::INSTRUCTION_LIST_END; 296fe6060f1SDimitry Andric Lookups.reserve(NumInstr); 297fe6060f1SDimitry Andric 298fe6060f1SDimitry Andric for (unsigned I = 0; I < NumInstr; ++I) { 299fe6060f1SDimitry Andric M68kInstructionLookupBuilder Builder; 300fe6060f1SDimitry Andric 301fe6060f1SDimitry Andric for (const uint8_t *PartPtr = M68k::getMCInstrBeads(I); *PartPtr; 302fe6060f1SDimitry Andric ++PartPtr) { 303fe6060f1SDimitry Andric uint8_t Bead = *PartPtr; 304fe6060f1SDimitry Andric unsigned Ext = Bead >> 4; 305fe6060f1SDimitry Andric unsigned Op = Bead & 0xf; 306fe6060f1SDimitry Andric 307fe6060f1SDimitry Andric switch (Op) { 308fe6060f1SDimitry Andric case M68kBeads::Ctrl: 309fe6060f1SDimitry Andric // Term will have already been skipped by the loop. 310fe6060f1SDimitry Andric assert((Ext == M68kBeads::Ignore) && "unexpected command bead"); 311fe6060f1SDimitry Andric break; 312fe6060f1SDimitry Andric 313fe6060f1SDimitry Andric case M68kBeads::Bits1: 314fe6060f1SDimitry Andric Builder.addBits(1, Ext); 315fe6060f1SDimitry Andric break; 316fe6060f1SDimitry Andric 317fe6060f1SDimitry Andric case M68kBeads::Bits2: 318fe6060f1SDimitry Andric Builder.addBits(2, Ext); 319fe6060f1SDimitry Andric break; 320fe6060f1SDimitry Andric 321fe6060f1SDimitry Andric case M68kBeads::Bits3: 322fe6060f1SDimitry Andric Builder.addBits(3, Ext); 323fe6060f1SDimitry Andric break; 324fe6060f1SDimitry Andric 325fe6060f1SDimitry Andric case M68kBeads::Bits4: 326fe6060f1SDimitry Andric Builder.addBits(4, Ext); 327fe6060f1SDimitry Andric break; 328fe6060f1SDimitry Andric 329fe6060f1SDimitry Andric case M68kBeads::DAReg: 330fe6060f1SDimitry Andric case M68kBeads::DA: 331fe6060f1SDimitry Andric case M68kBeads::DReg: 332fe6060f1SDimitry Andric case M68kBeads::Reg: 333fe6060f1SDimitry Andric if (Op != M68kBeads::DA) 334fe6060f1SDimitry Andric Builder.skipBits(3); 335fe6060f1SDimitry Andric 336fe6060f1SDimitry Andric if (Op != M68kBeads::Reg && Op != M68kBeads::DReg) 337fe6060f1SDimitry Andric Builder.skipBits(1); 338fe6060f1SDimitry Andric 339fe6060f1SDimitry Andric break; 340fe6060f1SDimitry Andric 341fe6060f1SDimitry Andric case M68kBeads::Disp8: 342fe6060f1SDimitry Andric Builder.skipBits(8); 343fe6060f1SDimitry Andric break; 344fe6060f1SDimitry Andric 345fe6060f1SDimitry Andric case M68kBeads::Imm8: 346fe6060f1SDimitry Andric case M68kBeads::Imm16: 347fe6060f1SDimitry Andric Builder.skipBits(16); 348fe6060f1SDimitry Andric break; 349fe6060f1SDimitry Andric 350fe6060f1SDimitry Andric case M68kBeads::Imm32: 351fe6060f1SDimitry Andric Builder.skipBits(32); 352fe6060f1SDimitry Andric break; 353fe6060f1SDimitry Andric 354fe6060f1SDimitry Andric case M68kBeads::Imm3: 355fe6060f1SDimitry Andric Builder.skipBits(3); 356fe6060f1SDimitry Andric break; 357fe6060f1SDimitry Andric 358fe6060f1SDimitry Andric default: 359fe6060f1SDimitry Andric llvm_unreachable("unhandled bead type"); 360fe6060f1SDimitry Andric } 361fe6060f1SDimitry Andric } 362fe6060f1SDimitry Andric 363fe6060f1SDimitry Andric // Ignore instructions which are unmatchable (usually pseudo instructions). 364fe6060f1SDimitry Andric if (!Builder.isValid()) 365fe6060f1SDimitry Andric continue; 366fe6060f1SDimitry Andric 367fe6060f1SDimitry Andric Lookups.push_back(Builder.build(I)); 368fe6060f1SDimitry Andric } 369fe6060f1SDimitry Andric } 370fe6060f1SDimitry Andric 371fe6060f1SDimitry Andric unsigned M68kDisassembler::getRegOperandIndex(MCInst &Instr, 372fe6060f1SDimitry Andric unsigned Bead) const { 373fe6060f1SDimitry Andric unsigned Ext = Bead >> 4; 374fe6060f1SDimitry Andric 375fe6060f1SDimitry Andric const MCInstrDesc &Desc = MCII->get(Instr.getOpcode()); 376fe6060f1SDimitry Andric auto MIOpIdx = M68k::getLogicalOperandIdx(Instr.getOpcode(), Ext & 7); 377fe6060f1SDimitry Andric 378fe6060f1SDimitry Andric if (M68kII::hasMultiMIOperands(Instr.getOpcode(), Ext & 7)) { 379fe6060f1SDimitry Andric bool IsPCRel = Desc.OpInfo[MIOpIdx].OperandType == MCOI::OPERAND_PCREL; 380fe6060f1SDimitry Andric if (IsPCRel) 381fe6060f1SDimitry Andric MIOpIdx += M68k::PCRelIndex; 382fe6060f1SDimitry Andric else if (Ext & 8) 383fe6060f1SDimitry Andric MIOpIdx += M68k::MemIndex; 384fe6060f1SDimitry Andric else 385fe6060f1SDimitry Andric MIOpIdx += M68k::MemBase; 386fe6060f1SDimitry Andric } 387fe6060f1SDimitry Andric 388fe6060f1SDimitry Andric return MIOpIdx; 389fe6060f1SDimitry Andric } 390fe6060f1SDimitry Andric 391fe6060f1SDimitry Andric unsigned M68kDisassembler::getImmOperandIndex(MCInst &Instr, 392fe6060f1SDimitry Andric unsigned Bead) const { 393fe6060f1SDimitry Andric unsigned Ext = Bead >> 4; 394fe6060f1SDimitry Andric 395fe6060f1SDimitry Andric const MCInstrDesc &Desc = MCII->get(Instr.getOpcode()); 396fe6060f1SDimitry Andric auto MIOpIdx = M68k::getLogicalOperandIdx(Instr.getOpcode(), Ext & 7); 397fe6060f1SDimitry Andric 398fe6060f1SDimitry Andric if (M68kII::hasMultiMIOperands(Instr.getOpcode(), Ext & 7)) { 399fe6060f1SDimitry Andric bool IsPCRel = Desc.OpInfo[MIOpIdx].OperandType == MCOI::OPERAND_PCREL; 400fe6060f1SDimitry Andric if (IsPCRel) 401fe6060f1SDimitry Andric MIOpIdx += M68k::PCRelDisp; 402fe6060f1SDimitry Andric else if (Ext & 8) 403fe6060f1SDimitry Andric MIOpIdx += M68k::MemOuter; 404fe6060f1SDimitry Andric else 405fe6060f1SDimitry Andric MIOpIdx += M68k::MemDisp; 406fe6060f1SDimitry Andric } 407fe6060f1SDimitry Andric 408fe6060f1SDimitry Andric return MIOpIdx; 409fe6060f1SDimitry Andric } 410fe6060f1SDimitry Andric 411fe6060f1SDimitry Andric void M68kDisassembler::decodeReg(MCInst &Instr, unsigned Bead, 412fe6060f1SDimitry Andric M68kInstructionReader &Reader, 413fe6060f1SDimitry Andric unsigned &Scratch) const { 414fe6060f1SDimitry Andric unsigned Op = Bead & 0xf; 415fe6060f1SDimitry Andric LLVM_DEBUG(errs() << format("decodeReg %x\n", Bead)); 416fe6060f1SDimitry Andric 417fe6060f1SDimitry Andric if (Op != M68kBeads::DA) 418fe6060f1SDimitry Andric Scratch = (Scratch & ~7) | Reader.readBits(3); 419fe6060f1SDimitry Andric 420fe6060f1SDimitry Andric if (Op != M68kBeads::Reg) { 421fe6060f1SDimitry Andric bool DA = (Op != M68kBeads::DReg) && Reader.readBits(1); 422fe6060f1SDimitry Andric if (!DA) 423fe6060f1SDimitry Andric Scratch |= 8; 424fe6060f1SDimitry Andric else 425fe6060f1SDimitry Andric Scratch &= ~8; 426fe6060f1SDimitry Andric } 427fe6060f1SDimitry Andric } 428fe6060f1SDimitry Andric 429fe6060f1SDimitry Andric void M68kDisassembler::decodeImm(MCInst &Instr, unsigned Bead, 430fe6060f1SDimitry Andric M68kInstructionReader &Reader, 431fe6060f1SDimitry Andric unsigned &Scratch) const { 432fe6060f1SDimitry Andric unsigned Op = Bead & 0xf; 433fe6060f1SDimitry Andric LLVM_DEBUG(errs() << format("decodeImm %x\n", Bead)); 434fe6060f1SDimitry Andric 435fe6060f1SDimitry Andric unsigned NumToRead; 436fe6060f1SDimitry Andric switch (Op) { 437fe6060f1SDimitry Andric case M68kBeads::Disp8: 438fe6060f1SDimitry Andric NumToRead = 8; 439fe6060f1SDimitry Andric break; 440fe6060f1SDimitry Andric case M68kBeads::Imm8: 441fe6060f1SDimitry Andric case M68kBeads::Imm16: 442fe6060f1SDimitry Andric NumToRead = 16; 443fe6060f1SDimitry Andric break; 444fe6060f1SDimitry Andric case M68kBeads::Imm32: 445fe6060f1SDimitry Andric NumToRead = 32; 446fe6060f1SDimitry Andric break; 447fe6060f1SDimitry Andric case M68kBeads::Imm3: 448fe6060f1SDimitry Andric NumToRead = 3; 449fe6060f1SDimitry Andric break; 450fe6060f1SDimitry Andric default: 451fe6060f1SDimitry Andric llvm_unreachable("invalid imm"); 452fe6060f1SDimitry Andric } 453fe6060f1SDimitry Andric 454349cc55cSDimitry Andric Scratch = (NumToRead < 32) ? (Scratch << NumToRead) : 0; 455349cc55cSDimitry Andric Scratch |= Reader.readBits(NumToRead); 456fe6060f1SDimitry Andric } 457fe6060f1SDimitry Andric 458fe6060f1SDimitry Andric DecodeStatus M68kDisassembler::getInstruction(MCInst &Instr, uint64_t &Size, 459fe6060f1SDimitry Andric ArrayRef<uint8_t> Bytes, 460fe6060f1SDimitry Andric uint64_t Address, 461fe6060f1SDimitry Andric raw_ostream &CStream) const { 462fe6060f1SDimitry Andric // Read and shift the input (fetch as much as we can for now). 463fe6060f1SDimitry Andric auto Buffer = M68kInstructionBuffer::fill(Bytes); 464fe6060f1SDimitry Andric if (Buffer.size() == 0) 465fe6060f1SDimitry Andric return Fail; 466fe6060f1SDimitry Andric 467fe6060f1SDimitry Andric // Check through our lookup table. 468fe6060f1SDimitry Andric bool Found = false; 469fe6060f1SDimitry Andric for (unsigned I = 0, E = Lookups.size(); I < E; ++I) { 470fe6060f1SDimitry Andric const M68kInstructionLookup &Lookup = Lookups[I]; 471fe6060f1SDimitry Andric if (!Lookup.matches(Buffer)) 472fe6060f1SDimitry Andric continue; 473fe6060f1SDimitry Andric 474fe6060f1SDimitry Andric Found = true; 475fe6060f1SDimitry Andric Size = Lookup.size() * 2; 476fe6060f1SDimitry Andric Buffer.truncate(Lookup.size()); 477fe6060f1SDimitry Andric Instr.setOpcode(Lookup.OpCode); 478fe6060f1SDimitry Andric LLVM_DEBUG(errs() << "decoding instruction " << MCII->getName(Lookup.OpCode) 479fe6060f1SDimitry Andric << "\n"); 480fe6060f1SDimitry Andric break; 481fe6060f1SDimitry Andric } 482fe6060f1SDimitry Andric 483fe6060f1SDimitry Andric if (!Found) 484fe6060f1SDimitry Andric return Fail; 485fe6060f1SDimitry Andric 486fe6060f1SDimitry Andric M68kInstructionReader Reader(Buffer); 487fe6060f1SDimitry Andric const MCInstrDesc &Desc = MCII->get(Instr.getOpcode()); 488fe6060f1SDimitry Andric unsigned NumOperands = Desc.NumOperands; 489fe6060f1SDimitry Andric 490fe6060f1SDimitry Andric // Now use the beads to decode the operands. 491fe6060f1SDimitry Andric enum class OperandType { 492fe6060f1SDimitry Andric Invalid, 493fe6060f1SDimitry Andric Reg, 494fe6060f1SDimitry Andric Imm, 495fe6060f1SDimitry Andric }; 496fe6060f1SDimitry Andric 497fe6060f1SDimitry Andric SmallVector<OperandType, 6> OpType(NumOperands, OperandType::Invalid); 498fe6060f1SDimitry Andric SmallVector<unsigned, 6> Scratch(NumOperands, 0); 499fe6060f1SDimitry Andric for (const uint8_t *PartPtr = M68k::getMCInstrBeads(Instr.getOpcode()); 500fe6060f1SDimitry Andric *PartPtr; ++PartPtr) { 501fe6060f1SDimitry Andric uint8_t Bead = *PartPtr; 502fe6060f1SDimitry Andric unsigned Ext = Bead >> 4; 503fe6060f1SDimitry Andric unsigned Op = Bead & 0xf; 504fe6060f1SDimitry Andric unsigned MIOpIdx; 505fe6060f1SDimitry Andric 506fe6060f1SDimitry Andric switch (Op) { 507fe6060f1SDimitry Andric case M68kBeads::Ctrl: 508fe6060f1SDimitry Andric // Term will have already been skipped by the loop. 509fe6060f1SDimitry Andric assert((Ext == M68kBeads::Ignore) && "unexpected command bead"); 510fe6060f1SDimitry Andric break; 511fe6060f1SDimitry Andric 512fe6060f1SDimitry Andric // These bits are constant - if we're here we've already matched them. 513fe6060f1SDimitry Andric case M68kBeads::Bits1: 514fe6060f1SDimitry Andric Reader.readBits(1); 515fe6060f1SDimitry Andric break; 516fe6060f1SDimitry Andric case M68kBeads::Bits2: 517fe6060f1SDimitry Andric Reader.readBits(2); 518fe6060f1SDimitry Andric break; 519fe6060f1SDimitry Andric case M68kBeads::Bits3: 520fe6060f1SDimitry Andric Reader.readBits(3); 521fe6060f1SDimitry Andric break; 522fe6060f1SDimitry Andric case M68kBeads::Bits4: 523fe6060f1SDimitry Andric Reader.readBits(4); 524fe6060f1SDimitry Andric break; 525fe6060f1SDimitry Andric 526fe6060f1SDimitry Andric case M68kBeads::DAReg: 527fe6060f1SDimitry Andric case M68kBeads::DA: 528fe6060f1SDimitry Andric case M68kBeads::DReg: 529fe6060f1SDimitry Andric case M68kBeads::Reg: 530fe6060f1SDimitry Andric MIOpIdx = getRegOperandIndex(Instr, Bead); 531fe6060f1SDimitry Andric assert(((OpType[MIOpIdx] == OperandType::Invalid) || 532fe6060f1SDimitry Andric (OpType[MIOpIdx] == OperandType::Reg)) && 533fe6060f1SDimitry Andric "operands cannot change type"); 534fe6060f1SDimitry Andric OpType[MIOpIdx] = OperandType::Reg; 535fe6060f1SDimitry Andric decodeReg(Instr, Bead, Reader, Scratch[MIOpIdx]); 536fe6060f1SDimitry Andric break; 537fe6060f1SDimitry Andric 538fe6060f1SDimitry Andric case M68kBeads::Disp8: 539fe6060f1SDimitry Andric case M68kBeads::Imm8: 540fe6060f1SDimitry Andric case M68kBeads::Imm16: 541fe6060f1SDimitry Andric case M68kBeads::Imm32: 542fe6060f1SDimitry Andric case M68kBeads::Imm3: 543fe6060f1SDimitry Andric MIOpIdx = getImmOperandIndex(Instr, Bead); 544fe6060f1SDimitry Andric assert(((OpType[MIOpIdx] == OperandType::Invalid) || 545fe6060f1SDimitry Andric (OpType[MIOpIdx] == OperandType::Imm)) && 546fe6060f1SDimitry Andric "operands cannot change type"); 547fe6060f1SDimitry Andric OpType[MIOpIdx] = OperandType::Imm; 548fe6060f1SDimitry Andric decodeImm(Instr, Bead, Reader, Scratch[MIOpIdx]); 549fe6060f1SDimitry Andric break; 550fe6060f1SDimitry Andric 551fe6060f1SDimitry Andric default: 552fe6060f1SDimitry Andric llvm_unreachable("unhandled bead type"); 553fe6060f1SDimitry Andric } 554fe6060f1SDimitry Andric } 555fe6060f1SDimitry Andric 556fe6060f1SDimitry Andric // Copy constrained operands. 557fe6060f1SDimitry Andric for (unsigned DstMIOpIdx = 0; DstMIOpIdx < NumOperands; ++DstMIOpIdx) { 558fe6060f1SDimitry Andric int TiedTo = Desc.getOperandConstraint(DstMIOpIdx, MCOI::TIED_TO); 559fe6060f1SDimitry Andric if (TiedTo < 0) 560fe6060f1SDimitry Andric continue; 561fe6060f1SDimitry Andric 562fe6060f1SDimitry Andric unsigned SrcMIOpIdx = TiedTo; 563fe6060f1SDimitry Andric 564fe6060f1SDimitry Andric unsigned OpCount = 0; 565fe6060f1SDimitry Andric for (unsigned I = 0;; ++I) { 566fe6060f1SDimitry Andric unsigned Offset = M68k::getLogicalOperandIdx(Instr.getOpcode(), I); 567fe6060f1SDimitry Andric assert(Offset <= SrcMIOpIdx && "missing logical operand"); 568fe6060f1SDimitry Andric if (Offset == SrcMIOpIdx) { 569fe6060f1SDimitry Andric OpCount = M68k::getLogicalOperandSize(Instr.getOpcode(), I); 570fe6060f1SDimitry Andric break; 571fe6060f1SDimitry Andric } 572fe6060f1SDimitry Andric } 573fe6060f1SDimitry Andric assert(OpCount != 0 && "operand count not found"); 574fe6060f1SDimitry Andric 575fe6060f1SDimitry Andric for (unsigned I = 0; I < OpCount; ++I) { 576fe6060f1SDimitry Andric assert(OpType[DstMIOpIdx + I] == OperandType::Invalid && 577fe6060f1SDimitry Andric "tried to stomp over operand whilst applying constraints"); 578fe6060f1SDimitry Andric OpType[DstMIOpIdx + I] = OpType[SrcMIOpIdx + I]; 579fe6060f1SDimitry Andric Scratch[DstMIOpIdx + I] = Scratch[SrcMIOpIdx + I]; 580fe6060f1SDimitry Andric } 581fe6060f1SDimitry Andric } 582fe6060f1SDimitry Andric 583fe6060f1SDimitry Andric // Create the operands from our scratch space. 584fe6060f1SDimitry Andric for (unsigned O = 0; O < NumOperands; ++O) { 585fe6060f1SDimitry Andric switch (OpType[O]) { 586fe6060f1SDimitry Andric case OperandType::Invalid: 587fe6060f1SDimitry Andric assert(false && "operand not parsed"); 588fe6060f1SDimitry Andric 589fe6060f1SDimitry Andric case OperandType::Imm: 590fe6060f1SDimitry Andric Instr.addOperand(MCOperand::createImm(Scratch[O])); 591fe6060f1SDimitry Andric break; 592fe6060f1SDimitry Andric 593fe6060f1SDimitry Andric case OperandType::Reg: 594fe6060f1SDimitry Andric Instr.addOperand(MCOperand::createReg(RegisterDecode[Scratch[O]])); 595fe6060f1SDimitry Andric break; 596fe6060f1SDimitry Andric } 597fe6060f1SDimitry Andric } 598fe6060f1SDimitry Andric 599fe6060f1SDimitry Andric assert((Reader.size() == 0) && "wrong number of bits consumed"); 600fe6060f1SDimitry Andric return Success; 601fe6060f1SDimitry Andric } 602fe6060f1SDimitry Andric 603fe6060f1SDimitry Andric static MCDisassembler *createM68kDisassembler(const Target &T, 604fe6060f1SDimitry Andric const MCSubtargetInfo &STI, 605fe6060f1SDimitry Andric MCContext &Ctx) { 606fe6060f1SDimitry Andric return new M68kDisassembler(STI, Ctx, T.createMCInstrInfo()); 607fe6060f1SDimitry Andric } 608fe6060f1SDimitry Andric 609fe6060f1SDimitry Andric extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeM68kDisassembler() { 610fe6060f1SDimitry Andric // Register the disassembler. 611fe6060f1SDimitry Andric TargetRegistry::RegisterMCDisassembler(getTheM68kTarget(), 612fe6060f1SDimitry Andric createM68kDisassembler); 613fe6060f1SDimitry Andric } 614