xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/M68k/Disassembler/M68kDisassembler.cpp (revision 349cc55c9796c4596a5b9904cd3281af295f878f)
1fe6060f1SDimitry 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"
24*349cc55cSDimitry 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 
454*349cc55cSDimitry Andric   Scratch = (NumToRead < 32) ? (Scratch << NumToRead) : 0;
455*349cc55cSDimitry 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