1//===-- MSP430Disassembler.cpp - Disassembler for MSP430 ------------------===//
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 implements the MSP430Disassembler class.
10//
11//===----------------------------------------------------------------------===//
12
13#include "MCTargetDesc/MSP430MCTargetDesc.h"
14#include "MSP430.h"
15#include "TargetInfo/MSP430TargetInfo.h"
16#include "llvm/MC/MCContext.h"
17#include "llvm/MC/MCDecoderOps.h"
18#include "llvm/MC/MCDisassembler/MCDisassembler.h"
19#include "llvm/MC/MCInst.h"
20#include "llvm/MC/MCSubtargetInfo.h"
21#include "llvm/MC/TargetRegistry.h"
22#include "llvm/Support/Compiler.h"
23#include "llvm/Support/Endian.h"
24
25using namespace llvm;
26
27#define DEBUG_TYPE "msp430-disassembler"
28
29typedef MCDisassembler::DecodeStatus DecodeStatus;
30
31namespace {
32class MSP430Disassembler : public MCDisassembler {
33 DecodeStatus getInstructionI(MCInst &MI, uint64_t &Size,
34 ArrayRef<uint8_t> Bytes, uint64_t Address,
35 raw_ostream &CStream) const;
36
37 DecodeStatus getInstructionII(MCInst &MI, uint64_t &Size,
38 ArrayRef<uint8_t> Bytes, uint64_t Address,
39 raw_ostream &CStream) const;
40
41 DecodeStatus getInstructionCJ(MCInst &MI, uint64_t &Size,
42 ArrayRef<uint8_t> Bytes, uint64_t Address,
43 raw_ostream &CStream) const;
44
45public:
46 MSP430Disassembler(const MCSubtargetInfo &STI, MCContext &Ctx)
47 : MCDisassembler(STI, Ctx) {}
48
49 DecodeStatus getInstruction(MCInst &MI, uint64_t &Size,
50 ArrayRef<uint8_t> Bytes, uint64_t Address,
51 raw_ostream &CStream) const override;
52};
53} // end anonymous namespace
54
55static MCDisassembler *createMSP430Disassembler(const Target &T,
56 const MCSubtargetInfo &STI,
57 MCContext &Ctx) {
58 return new MSP430Disassembler(STI, Ctx);
59}
60
61extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void
62LLVMInitializeMSP430Disassembler() {
63 TargetRegistry::RegisterMCDisassembler(T&: getTheMSP430Target(),
64 Fn: createMSP430Disassembler);
65}
66
67static const unsigned GR8DecoderTable[] = {
68 MSP430::PCB, MSP430::SPB, MSP430::SRB, MSP430::CGB,
69 MSP430::R4B, MSP430::R5B, MSP430::R6B, MSP430::R7B,
70 MSP430::R8B, MSP430::R9B, MSP430::R10B, MSP430::R11B,
71 MSP430::R12B, MSP430::R13B, MSP430::R14B, MSP430::R15B
72};
73
74static DecodeStatus DecodeGR8RegisterClass(MCInst &MI, uint64_t RegNo,
75 uint64_t Address,
76 const MCDisassembler *Decoder) {
77 if (RegNo > 15)
78 return MCDisassembler::Fail;
79
80 unsigned Reg = GR8DecoderTable[RegNo];
81 MI.addOperand(Op: MCOperand::createReg(Reg));
82 return MCDisassembler::Success;
83}
84
85static const unsigned GR16DecoderTable[] = {
86 MSP430::PC, MSP430::SP, MSP430::SR, MSP430::CG,
87 MSP430::R4, MSP430::R5, MSP430::R6, MSP430::R7,
88 MSP430::R8, MSP430::R9, MSP430::R10, MSP430::R11,
89 MSP430::R12, MSP430::R13, MSP430::R14, MSP430::R15
90};
91
92static DecodeStatus DecodeGR16RegisterClass(MCInst &MI, uint64_t RegNo,
93 uint64_t Address,
94 const MCDisassembler *Decoder) {
95 if (RegNo > 15)
96 return MCDisassembler::Fail;
97
98 unsigned Reg = GR16DecoderTable[RegNo];
99 MI.addOperand(Op: MCOperand::createReg(Reg));
100 return MCDisassembler::Success;
101}
102
103static DecodeStatus DecodeCGImm(MCInst &MI, uint64_t Bits, uint64_t Address,
104 const MCDisassembler *Decoder);
105
106static DecodeStatus DecodeMemOperand(MCInst &MI, uint64_t Bits,
107 uint64_t Address,
108 const MCDisassembler *Decoder);
109
110#include "MSP430GenDisassemblerTables.inc"
111
112static DecodeStatus DecodeCGImm(MCInst &MI, uint64_t Bits, uint64_t Address,
113 const MCDisassembler *Decoder) {
114 int64_t Imm;
115 switch (Bits) {
116 default:
117 llvm_unreachable("Invalid immediate value");
118 case 0x22: Imm = 4; break;
119 case 0x32: Imm = 8; break;
120 case 0x03: Imm = 0; break;
121 case 0x13: Imm = 1; break;
122 case 0x23: Imm = 2; break;
123 case 0x33: Imm = -1; break;
124 }
125 MI.addOperand(Op: MCOperand::createImm(Val: Imm));
126 return MCDisassembler::Success;
127}
128
129static DecodeStatus DecodeMemOperand(MCInst &MI, uint64_t Bits,
130 uint64_t Address,
131 const MCDisassembler *Decoder) {
132 unsigned Reg = Bits & 15;
133 unsigned Imm = Bits >> 4;
134
135 if (DecodeGR16RegisterClass(MI, RegNo: Reg, Address, Decoder) !=
136 MCDisassembler::Success)
137 return MCDisassembler::Fail;
138
139 MI.addOperand(Op: MCOperand::createImm(Val: (int16_t)Imm));
140 return MCDisassembler::Success;
141}
142
143enum AddrMode {
144 amInvalid = 0,
145 amRegister,
146 amIndexed,
147 amIndirect,
148 amIndirectPost,
149 amSymbolic,
150 amImmediate,
151 amAbsolute,
152 amConstant
153};
154
155static AddrMode DecodeSrcAddrMode(unsigned Rs, unsigned As) {
156 switch (Rs) {
157 case 0:
158 if (As == 1) return amSymbolic;
159 if (As == 2) return amInvalid;
160 if (As == 3) return amImmediate;
161 break;
162 case 2:
163 if (As == 1) return amAbsolute;
164 if (As == 2) return amConstant;
165 if (As == 3) return amConstant;
166 break;
167 case 3:
168 return amConstant;
169 default:
170 break;
171 }
172 switch (As) {
173 case 0: return amRegister;
174 case 1: return amIndexed;
175 case 2: return amIndirect;
176 case 3: return amIndirectPost;
177 default:
178 llvm_unreachable("As out of range");
179 }
180}
181
182static AddrMode DecodeSrcAddrModeI(unsigned Insn) {
183 unsigned Rs = fieldFromInstruction(insn: Insn, startBit: 8, numBits: 4);
184 unsigned As = fieldFromInstruction(insn: Insn, startBit: 4, numBits: 2);
185 return DecodeSrcAddrMode(Rs, As);
186}
187
188static AddrMode DecodeSrcAddrModeII(unsigned Insn) {
189 unsigned Rs = fieldFromInstruction(insn: Insn, startBit: 0, numBits: 4);
190 unsigned As = fieldFromInstruction(insn: Insn, startBit: 4, numBits: 2);
191 return DecodeSrcAddrMode(Rs, As);
192}
193
194static AddrMode DecodeDstAddrMode(unsigned Insn) {
195 unsigned Rd = fieldFromInstruction(insn: Insn, startBit: 0, numBits: 4);
196 unsigned Ad = fieldFromInstruction(insn: Insn, startBit: 7, numBits: 1);
197 switch (Rd) {
198 case 0: return Ad ? amSymbolic : amRegister;
199 case 2: return Ad ? amAbsolute : amRegister;
200 default:
201 break;
202 }
203 return Ad ? amIndexed : amRegister;
204}
205
206static const uint8_t *getDecoderTable(AddrMode SrcAM, unsigned Words) {
207 assert(0 < Words && Words < 4 && "Incorrect number of words");
208 switch (SrcAM) {
209 default:
210 llvm_unreachable("Invalid addressing mode");
211 case amRegister:
212 assert(Words < 3 && "Incorrect number of words");
213 return Words == 2 ? DecoderTableAlpha32 : DecoderTableAlpha16;
214 case amConstant:
215 assert(Words < 3 && "Incorrect number of words");
216 return Words == 2 ? DecoderTableBeta32 : DecoderTableBeta16;
217 case amIndexed:
218 case amSymbolic:
219 case amImmediate:
220 case amAbsolute:
221 assert(Words > 1 && "Incorrect number of words");
222 return Words == 2 ? DecoderTableGamma32 : DecoderTableGamma48;
223 case amIndirect:
224 case amIndirectPost:
225 assert(Words < 3 && "Incorrect number of words");
226 return Words == 2 ? DecoderTableDelta32 : DecoderTableDelta16;
227 }
228}
229
230DecodeStatus MSP430Disassembler::getInstructionI(MCInst &MI, uint64_t &Size,
231 ArrayRef<uint8_t> Bytes,
232 uint64_t Address,
233 raw_ostream &CStream) const {
234 uint64_t Insn = support::endian::read16le(P: Bytes.data());
235 AddrMode SrcAM = DecodeSrcAddrModeI(Insn);
236 AddrMode DstAM = DecodeDstAddrMode(Insn);
237 if (SrcAM == amInvalid || DstAM == amInvalid) {
238 Size = 2; // skip one word and let disassembler to try further
239 return MCDisassembler::Fail;
240 }
241
242 unsigned Words = 1;
243 switch (SrcAM) {
244 case amIndexed:
245 case amSymbolic:
246 case amImmediate:
247 case amAbsolute:
248 if (Bytes.size() < (Words + 1) * 2) {
249 Size = 2;
250 return DecodeStatus::Fail;
251 }
252 Insn |= (uint64_t)support::endian::read16le(P: Bytes.data() + 2) << 16;
253 ++Words;
254 break;
255 default:
256 break;
257 }
258 switch (DstAM) {
259 case amIndexed:
260 case amSymbolic:
261 case amAbsolute:
262 if (Bytes.size() < (Words + 1) * 2) {
263 Size = 2;
264 return DecodeStatus::Fail;
265 }
266 Insn |= (uint64_t)support::endian::read16le(P: Bytes.data() + Words * 2)
267 << (Words * 16);
268 ++Words;
269 break;
270 default:
271 break;
272 }
273
274 DecodeStatus Result = decodeInstruction(DecodeTable: getDecoderTable(SrcAM, Words), MI,
275 insn: Insn, Address, DisAsm: this, STI);
276 if (Result != MCDisassembler::Fail) {
277 Size = Words * 2;
278 return Result;
279 }
280
281 Size = 2;
282 return DecodeStatus::Fail;
283}
284
285DecodeStatus MSP430Disassembler::getInstructionII(MCInst &MI, uint64_t &Size,
286 ArrayRef<uint8_t> Bytes,
287 uint64_t Address,
288 raw_ostream &CStream) const {
289 uint64_t Insn = support::endian::read16le(P: Bytes.data());
290 AddrMode SrcAM = DecodeSrcAddrModeII(Insn);
291 if (SrcAM == amInvalid) {
292 Size = 2; // skip one word and let disassembler to try further
293 return MCDisassembler::Fail;
294 }
295
296 unsigned Words = 1;
297 switch (SrcAM) {
298 case amIndexed:
299 case amSymbolic:
300 case amImmediate:
301 case amAbsolute:
302 if (Bytes.size() < (Words + 1) * 2) {
303 Size = 2;
304 return DecodeStatus::Fail;
305 }
306 Insn |= (uint64_t)support::endian::read16le(P: Bytes.data() + 2) << 16;
307 ++Words;
308 break;
309 default:
310 break;
311 }
312
313 const uint8_t *DecoderTable = Words == 2 ? DecoderTable32 : DecoderTable16;
314 DecodeStatus Result = decodeInstruction(DecodeTable: DecoderTable, MI, insn: Insn, Address,
315 DisAsm: this, STI);
316 if (Result != MCDisassembler::Fail) {
317 Size = Words * 2;
318 return Result;
319 }
320
321 Size = 2;
322 return DecodeStatus::Fail;
323}
324
325static MSP430CC::CondCodes getCondCode(unsigned Cond) {
326 switch (Cond) {
327 case 0: return MSP430CC::COND_NE;
328 case 1: return MSP430CC::COND_E;
329 case 2: return MSP430CC::COND_LO;
330 case 3: return MSP430CC::COND_HS;
331 case 4: return MSP430CC::COND_N;
332 case 5: return MSP430CC::COND_GE;
333 case 6: return MSP430CC::COND_L;
334 case 7: return MSP430CC::COND_NONE;
335 default:
336 llvm_unreachable("Cond out of range");
337 }
338}
339
340DecodeStatus MSP430Disassembler::getInstructionCJ(MCInst &MI, uint64_t &Size,
341 ArrayRef<uint8_t> Bytes,
342 uint64_t Address,
343 raw_ostream &CStream) const {
344 uint64_t Insn = support::endian::read16le(P: Bytes.data());
345 unsigned Cond = fieldFromInstruction(insn: Insn, startBit: 10, numBits: 3);
346 unsigned Offset = fieldFromInstruction(insn: Insn, startBit: 0, numBits: 10);
347
348 MI.addOperand(Op: MCOperand::createImm(Val: SignExtend32(X: Offset, B: 10)));
349
350 if (Cond == 7)
351 MI.setOpcode(MSP430::JMP);
352 else {
353 MI.setOpcode(MSP430::JCC);
354 MI.addOperand(Op: MCOperand::createImm(Val: getCondCode(Cond)));
355 }
356
357 Size = 2;
358 return DecodeStatus::Success;
359}
360
361DecodeStatus MSP430Disassembler::getInstruction(MCInst &MI, uint64_t &Size,
362 ArrayRef<uint8_t> Bytes,
363 uint64_t Address,
364 raw_ostream &CStream) const {
365 if (Bytes.size() < 2) {
366 Size = 0;
367 return MCDisassembler::Fail;
368 }
369
370 uint64_t Insn = support::endian::read16le(P: Bytes.data());
371 unsigned Opc = fieldFromInstruction(insn: Insn, startBit: 13, numBits: 3);
372 switch (Opc) {
373 case 0:
374 return getInstructionII(MI, Size, Bytes, Address, CStream);
375 case 1:
376 return getInstructionCJ(MI, Size, Bytes, Address, CStream);
377 default:
378 return getInstructionI(MI, Size, Bytes, Address, CStream);
379 }
380}
381