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
25 using namespace llvm;
26
27 #define DEBUG_TYPE "msp430-disassembler"
28
29 typedef MCDisassembler::DecodeStatus DecodeStatus;
30
31 namespace {
32 class 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
45 public:
MSP430Disassembler(const MCSubtargetInfo & STI,MCContext & Ctx)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
createMSP430Disassembler(const Target & T,const MCSubtargetInfo & STI,MCContext & Ctx)55 static MCDisassembler *createMSP430Disassembler(const Target &T,
56 const MCSubtargetInfo &STI,
57 MCContext &Ctx) {
58 return new MSP430Disassembler(STI, Ctx);
59 }
60
61 extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void
LLVMInitializeMSP430Disassembler()62 LLVMInitializeMSP430Disassembler() {
63 TargetRegistry::RegisterMCDisassembler(getTheMSP430Target(),
64 createMSP430Disassembler);
65 }
66
67 static 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
DecodeGR8RegisterClass(MCInst & MI,uint64_t RegNo,uint64_t Address,const MCDisassembler * Decoder)74 static 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(MCOperand::createReg(Reg));
82 return MCDisassembler::Success;
83 }
84
85 static 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
DecodeGR16RegisterClass(MCInst & MI,uint64_t RegNo,uint64_t Address,const MCDisassembler * Decoder)92 static 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(MCOperand::createReg(Reg));
100 return MCDisassembler::Success;
101 }
102
103 static DecodeStatus DecodeCGImm(MCInst &MI, uint64_t Bits, uint64_t Address,
104 const MCDisassembler *Decoder);
105
106 static DecodeStatus DecodeMemOperand(MCInst &MI, uint64_t Bits,
107 uint64_t Address,
108 const MCDisassembler *Decoder);
109
110 #include "MSP430GenDisassemblerTables.inc"
111
DecodeCGImm(MCInst & MI,uint64_t Bits,uint64_t Address,const MCDisassembler * Decoder)112 static 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(MCOperand::createImm(Imm));
126 return MCDisassembler::Success;
127 }
128
DecodeMemOperand(MCInst & MI,uint64_t Bits,uint64_t Address,const MCDisassembler * Decoder)129 static 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, Reg, Address, Decoder) !=
136 MCDisassembler::Success)
137 return MCDisassembler::Fail;
138
139 MI.addOperand(MCOperand::createImm((int16_t)Imm));
140 return MCDisassembler::Success;
141 }
142
143 enum AddrMode {
144 amInvalid = 0,
145 amRegister,
146 amIndexed,
147 amIndirect,
148 amIndirectPost,
149 amSymbolic,
150 amImmediate,
151 amAbsolute,
152 amConstant
153 };
154
DecodeSrcAddrMode(unsigned Rs,unsigned As)155 static 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
DecodeSrcAddrModeI(unsigned Insn)182 static AddrMode DecodeSrcAddrModeI(unsigned Insn) {
183 unsigned Rs = fieldFromInstruction(Insn, 8, 4);
184 unsigned As = fieldFromInstruction(Insn, 4, 2);
185 return DecodeSrcAddrMode(Rs, As);
186 }
187
DecodeSrcAddrModeII(unsigned Insn)188 static AddrMode DecodeSrcAddrModeII(unsigned Insn) {
189 unsigned Rs = fieldFromInstruction(Insn, 0, 4);
190 unsigned As = fieldFromInstruction(Insn, 4, 2);
191 return DecodeSrcAddrMode(Rs, As);
192 }
193
DecodeDstAddrMode(unsigned Insn)194 static AddrMode DecodeDstAddrMode(unsigned Insn) {
195 unsigned Rd = fieldFromInstruction(Insn, 0, 4);
196 unsigned Ad = fieldFromInstruction(Insn, 7, 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
getDecoderTable(AddrMode SrcAM,unsigned Words)206 static 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
getInstructionI(MCInst & MI,uint64_t & Size,ArrayRef<uint8_t> Bytes,uint64_t Address,raw_ostream & CStream) const230 DecodeStatus 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(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(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(Bytes.data() + Words * 2)
267 << (Words * 16);
268 ++Words;
269 break;
270 default:
271 break;
272 }
273
274 DecodeStatus Result = decodeInstruction(getDecoderTable(SrcAM, Words), MI,
275 Insn, Address, 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
getInstructionII(MCInst & MI,uint64_t & Size,ArrayRef<uint8_t> Bytes,uint64_t Address,raw_ostream & CStream) const285 DecodeStatus 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(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(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(DecoderTable, MI, Insn, Address,
315 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
getCondCode(unsigned Cond)325 static 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
getInstructionCJ(MCInst & MI,uint64_t & Size,ArrayRef<uint8_t> Bytes,uint64_t Address,raw_ostream & CStream) const340 DecodeStatus 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(Bytes.data());
345 unsigned Cond = fieldFromInstruction(Insn, 10, 3);
346 unsigned Offset = fieldFromInstruction(Insn, 0, 10);
347
348 MI.addOperand(MCOperand::createImm(SignExtend32(Offset, 10)));
349
350 if (Cond == 7)
351 MI.setOpcode(MSP430::JMP);
352 else {
353 MI.setOpcode(MSP430::JCC);
354 MI.addOperand(MCOperand::createImm(getCondCode(Cond)));
355 }
356
357 Size = 2;
358 return DecodeStatus::Success;
359 }
360
getInstruction(MCInst & MI,uint64_t & Size,ArrayRef<uint8_t> Bytes,uint64_t Address,raw_ostream & CStream) const361 DecodeStatus 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(Bytes.data());
371 unsigned Opc = fieldFromInstruction(Insn, 13, 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