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