1 //===- M68kDisassembler.cpp - Disassembler for M68k -------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 // This file is part of the M68k Disassembler.
11 //===----------------------------------------------------------------------===//
14 #include "M68kRegisterInfo.h"
15 #include "M68kSubtarget.h"
16 #include "MCTargetDesc/M68kMCCodeEmitter.h"
17 #include "MCTargetDesc/M68kMCTargetDesc.h"
18 #include "TargetInfo/M68kTargetInfo.h"
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/Support/TargetRegistry.h"
28 #define DEBUG_TYPE "m68k-disassembler"
30 typedef MCDisassembler::DecodeStatus DecodeStatus
;
33 constexpr unsigned MaxInstructionWords
= 11;
35 class M68kInstructionBuffer
{
36 typedef SmallVector
<uint16_t, MaxInstructionWords
> BufferType
;
40 M68kInstructionBuffer() {}
42 template <typename TIt
>
43 M68kInstructionBuffer(TIt Start
, TIt End
) : Buffer(Start
, End
) {}
45 unsigned size() const { return Buffer
.size(); }
47 BufferType::const_iterator
begin() const { return Buffer
.begin(); }
48 BufferType::const_iterator
end() const { return Buffer
.end(); }
50 uint16_t operator[](unsigned Index
) const {
51 assert((Index
< Buffer
.size()) && "tried to read out of bounds word");
55 void truncate(unsigned NewLength
) {
56 assert((NewLength
<= Buffer
.size()) &&
57 "instruction buffer too short to truncate");
58 Buffer
.resize(NewLength
);
63 static M68kInstructionBuffer
fill(ArrayRef
<uint8_t> Bytes
);
66 class M68kInstructionReader
{
67 M68kInstructionBuffer Buffer
;
71 M68kInstructionReader(M68kInstructionBuffer Buf
) : Buffer(Buf
), NumRead(0) {}
73 unsigned size() const { return (Buffer
.size() * 16) - NumRead
; }
75 uint64_t readBits(unsigned NumBits
);
78 struct M68kInstructionLookup
{
80 M68kInstructionBuffer Mask
;
81 M68kInstructionBuffer Value
;
83 unsigned size() const { return Mask
.size(); }
85 // Check whether this instruction could possibly match the given bytes.
86 bool matches(const M68kInstructionBuffer
&Test
) const;
90 class M68kInstructionLookupBuilder
{
91 std::array
<uint16_t, MaxInstructionWords
> Mask
;
92 std::array
<uint16_t, MaxInstructionWords
> Value
;
96 M68kInstructionLookupBuilder() : NumWritten(0) {
101 unsigned numWords() const {
102 assert(!(NumWritten
& 0xf) && "instructions must be whole words");
103 return NumWritten
>> 4;
106 bool isValid() const;
107 M68kInstructionLookup
build(unsigned OpCode
);
108 void addBits(unsigned N
, uint64_t Bits
);
109 void skipBits(unsigned N
);
112 /// A disassembler class for M68k.
113 class M68kDisassembler
: public MCDisassembler
{
115 std::vector
<M68kInstructionLookup
> Lookups
;
118 M68kDisassembler(const MCSubtargetInfo
&STI
, MCContext
&Ctx
,
120 : MCDisassembler(STI
, Ctx
), MCII(MCII
) {
123 virtual ~M68kDisassembler() {}
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;
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
,
144 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
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
);
155 char Ch
= IsClear
? '0' : '1';
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()));
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
;
178 errs() << format("Read word %x (%d)\n", (unsigned)Word
, Buffer
.size()));
181 return M68kInstructionBuffer(Buffer
.begin(), Buffer
.end());
184 uint64_t M68kInstructionReader::readBits(unsigned NumBits
) {
185 assert((size() >= NumBits
) && "not enough bits to read");
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.
192 unsigned BitsRead
= 0;
194 while (BitsRead
< NumBits
) {
195 unsigned AvailableThisWord
= 16 - (NumRead
& 0xf);
196 unsigned ToRead
= std::min(NumBits
, AvailableThisWord
);
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
;
208 bool M68kInstructionLookup::matches(const M68kInstructionBuffer
&Test
) const {
209 if (Test
.size() < Value
.size())
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
];
217 if ((Have
& WordMask
) != Need
)
224 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
226 void M68kInstructionLookup::dump() const {
227 dbgs() << "M68kInstructionLookup " << OpCode
<< " ";
229 for (unsigned I
= 0, E
= Mask
.size(); I
< E
; ++I
) {
230 uint16_t WordMask
= Mask
[I
];
231 uint16_t WordValue
= Value
[I
];
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
);
241 char Ch
= IsMasked
? '?' : (IsClear
? '0' : '1');
252 bool M68kInstructionLookupBuilder::isValid() const {
253 for (unsigned I
= 0, E
= numWords(); I
< E
; ++I
)
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
;
266 Ret
.Mask
= MaskBuffer
;
267 Ret
.Value
= ValueBuffer
;
271 void M68kInstructionLookupBuilder::addBits(unsigned N
, uint64_t Bits
) {
273 unsigned WordIndex
= NumWritten
>> 4;
274 unsigned WordOffset
= NumWritten
& 0xf;
275 unsigned AvailableThisWord
= 16 - WordOffset
;
276 unsigned ToWrite
= std::min(AvailableThisWord
, N
);
278 uint16_t WordMask
= (1 << ToWrite
) - 1;
279 uint16_t BitsToWrite
= Bits
& WordMask
;
281 Value
[WordIndex
] |= (BitsToWrite
<< WordOffset
);
282 Mask
[WordIndex
] |= (WordMask
<< WordOffset
);
286 NumWritten
+= ToWrite
;
290 void M68kInstructionLookupBuilder::skipBits(unsigned N
) { NumWritten
+= N
; }
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
);
298 for (unsigned I
= 0; I
< NumInstr
; ++I
) {
299 M68kInstructionLookupBuilder Builder
;
301 for (const uint8_t *PartPtr
= M68k::getMCInstrBeads(I
); *PartPtr
;
303 uint8_t Bead
= *PartPtr
;
304 unsigned Ext
= Bead
>> 4;
305 unsigned Op
= Bead
& 0xf;
308 case M68kBeads::Ctrl
:
309 // Term will have already been skipped by the loop.
310 assert((Ext
== M68kBeads::Ignore
) && "unexpected command bead");
313 case M68kBeads::Bits1
:
314 Builder
.addBits(1, Ext
);
317 case M68kBeads::Bits2
:
318 Builder
.addBits(2, Ext
);
321 case M68kBeads::Bits3
:
322 Builder
.addBits(3, Ext
);
325 case M68kBeads::Bits4
:
326 Builder
.addBits(4, Ext
);
329 case M68kBeads::DAReg
:
331 case M68kBeads::DReg
:
333 if (Op
!= M68kBeads::DA
)
336 if (Op
!= M68kBeads::Reg
&& Op
!= M68kBeads::DReg
)
341 case M68kBeads::Disp8
:
345 case M68kBeads::Imm8
:
346 case M68kBeads::Imm16
:
347 Builder
.skipBits(16);
350 case M68kBeads::Imm32
:
351 Builder
.skipBits(32);
354 case M68kBeads::Imm3
:
359 llvm_unreachable("unhandled bead type");
363 // Ignore instructions which are unmatchable (usually pseudo instructions).
364 if (!Builder
.isValid())
367 Lookups
.push_back(Builder
.build(I
));
371 unsigned M68kDisassembler::getRegOperandIndex(MCInst
&Instr
,
372 unsigned Bead
) const {
373 unsigned Ext
= Bead
>> 4;
375 const MCInstrDesc
&Desc
= MCII
->get(Instr
.getOpcode());
376 auto MIOpIdx
= M68k::getLogicalOperandIdx(Instr
.getOpcode(), Ext
& 7);
378 if (M68kII::hasMultiMIOperands(Instr
.getOpcode(), Ext
& 7)) {
379 bool IsPCRel
= Desc
.OpInfo
[MIOpIdx
].OperandType
== MCOI::OPERAND_PCREL
;
381 MIOpIdx
+= M68k::PCRelIndex
;
383 MIOpIdx
+= M68k::MemIndex
;
385 MIOpIdx
+= M68k::MemBase
;
391 unsigned M68kDisassembler::getImmOperandIndex(MCInst
&Instr
,
392 unsigned Bead
) const {
393 unsigned Ext
= Bead
>> 4;
395 const MCInstrDesc
&Desc
= MCII
->get(Instr
.getOpcode());
396 auto MIOpIdx
= M68k::getLogicalOperandIdx(Instr
.getOpcode(), Ext
& 7);
398 if (M68kII::hasMultiMIOperands(Instr
.getOpcode(), Ext
& 7)) {
399 bool IsPCRel
= Desc
.OpInfo
[MIOpIdx
].OperandType
== MCOI::OPERAND_PCREL
;
401 MIOpIdx
+= M68k::PCRelDisp
;
403 MIOpIdx
+= M68k::MemOuter
;
405 MIOpIdx
+= M68k::MemDisp
;
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
));
417 if (Op
!= M68kBeads::DA
)
418 Scratch
= (Scratch
& ~7) | Reader
.readBits(3);
420 if (Op
!= M68kBeads::Reg
) {
421 bool DA
= (Op
!= M68kBeads::DReg
) && Reader
.readBits(1);
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
));
437 case M68kBeads::Disp8
:
440 case M68kBeads::Imm8
:
441 case M68kBeads::Imm16
:
444 case M68kBeads::Imm32
:
447 case M68kBeads::Imm3
:
451 llvm_unreachable("invalid imm");
454 Scratch
= (Scratch
<< NumToRead
) | Reader
.readBits(NumToRead
);
457 DecodeStatus
M68kDisassembler::getInstruction(MCInst
&Instr
, uint64_t &Size
,
458 ArrayRef
<uint8_t> Bytes
,
460 raw_ostream
&CStream
) const {
461 // Read and shift the input (fetch as much as we can for now).
462 auto Buffer
= M68kInstructionBuffer::fill(Bytes
);
463 if (Buffer
.size() == 0)
466 // Check through our lookup table.
468 for (unsigned I
= 0, E
= Lookups
.size(); I
< E
; ++I
) {
469 const M68kInstructionLookup
&Lookup
= Lookups
[I
];
470 if (!Lookup
.matches(Buffer
))
474 Size
= Lookup
.size() * 2;
475 Buffer
.truncate(Lookup
.size());
476 Instr
.setOpcode(Lookup
.OpCode
);
477 LLVM_DEBUG(errs() << "decoding instruction " << MCII
->getName(Lookup
.OpCode
)
485 M68kInstructionReader
Reader(Buffer
);
486 const MCInstrDesc
&Desc
= MCII
->get(Instr
.getOpcode());
487 unsigned NumOperands
= Desc
.NumOperands
;
489 // Now use the beads to decode the operands.
490 enum class OperandType
{
496 SmallVector
<OperandType
, 6> OpType(NumOperands
, OperandType::Invalid
);
497 SmallVector
<unsigned, 6> Scratch(NumOperands
, 0);
498 for (const uint8_t *PartPtr
= M68k::getMCInstrBeads(Instr
.getOpcode());
499 *PartPtr
; ++PartPtr
) {
500 uint8_t Bead
= *PartPtr
;
501 unsigned Ext
= Bead
>> 4;
502 unsigned Op
= Bead
& 0xf;
506 case M68kBeads::Ctrl
:
507 // Term will have already been skipped by the loop.
508 assert((Ext
== M68kBeads::Ignore
) && "unexpected command bead");
511 // These bits are constant - if we're here we've already matched them.
512 case M68kBeads::Bits1
:
515 case M68kBeads::Bits2
:
518 case M68kBeads::Bits3
:
521 case M68kBeads::Bits4
:
525 case M68kBeads::DAReg
:
527 case M68kBeads::DReg
:
529 MIOpIdx
= getRegOperandIndex(Instr
, Bead
);
530 assert(((OpType
[MIOpIdx
] == OperandType::Invalid
) ||
531 (OpType
[MIOpIdx
] == OperandType::Reg
)) &&
532 "operands cannot change type");
533 OpType
[MIOpIdx
] = OperandType::Reg
;
534 decodeReg(Instr
, Bead
, Reader
, Scratch
[MIOpIdx
]);
537 case M68kBeads::Disp8
:
538 case M68kBeads::Imm8
:
539 case M68kBeads::Imm16
:
540 case M68kBeads::Imm32
:
541 case M68kBeads::Imm3
:
542 MIOpIdx
= getImmOperandIndex(Instr
, Bead
);
543 assert(((OpType
[MIOpIdx
] == OperandType::Invalid
) ||
544 (OpType
[MIOpIdx
] == OperandType::Imm
)) &&
545 "operands cannot change type");
546 OpType
[MIOpIdx
] = OperandType::Imm
;
547 decodeImm(Instr
, Bead
, Reader
, Scratch
[MIOpIdx
]);
551 llvm_unreachable("unhandled bead type");
555 // Copy constrained operands.
556 for (unsigned DstMIOpIdx
= 0; DstMIOpIdx
< NumOperands
; ++DstMIOpIdx
) {
557 int TiedTo
= Desc
.getOperandConstraint(DstMIOpIdx
, MCOI::TIED_TO
);
561 unsigned SrcMIOpIdx
= TiedTo
;
563 unsigned OpCount
= 0;
564 for (unsigned I
= 0;; ++I
) {
565 unsigned Offset
= M68k::getLogicalOperandIdx(Instr
.getOpcode(), I
);
566 assert(Offset
<= SrcMIOpIdx
&& "missing logical operand");
567 if (Offset
== SrcMIOpIdx
) {
568 OpCount
= M68k::getLogicalOperandSize(Instr
.getOpcode(), I
);
572 assert(OpCount
!= 0 && "operand count not found");
574 for (unsigned I
= 0; I
< OpCount
; ++I
) {
575 assert(OpType
[DstMIOpIdx
+ I
] == OperandType::Invalid
&&
576 "tried to stomp over operand whilst applying constraints");
577 OpType
[DstMIOpIdx
+ I
] = OpType
[SrcMIOpIdx
+ I
];
578 Scratch
[DstMIOpIdx
+ I
] = Scratch
[SrcMIOpIdx
+ I
];
582 // Create the operands from our scratch space.
583 for (unsigned O
= 0; O
< NumOperands
; ++O
) {
585 case OperandType::Invalid
:
586 assert(false && "operand not parsed");
588 case OperandType::Imm
:
589 Instr
.addOperand(MCOperand::createImm(Scratch
[O
]));
592 case OperandType::Reg
:
593 Instr
.addOperand(MCOperand::createReg(RegisterDecode
[Scratch
[O
]]));
598 assert((Reader
.size() == 0) && "wrong number of bits consumed");
602 static MCDisassembler
*createM68kDisassembler(const Target
&T
,
603 const MCSubtargetInfo
&STI
,
605 return new M68kDisassembler(STI
, Ctx
, T
.createMCInstrInfo());
608 extern "C" LLVM_EXTERNAL_VISIBILITY
void LLVMInitializeM68kDisassembler() {
609 // Register the disassembler.
610 TargetRegistry::RegisterMCDisassembler(getTheM68kTarget(),
611 createM68kDisassembler
);