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: |
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 | |
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 |
62 | LLVMInitializeMSP430Disassembler() { |
63 | TargetRegistry::RegisterMCDisassembler(T&: getTheMSP430Target(), |
64 | Fn: 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 | |
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(Op: 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 | |
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(Op: 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 | |
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(Op: MCOperand::createImm(Val: Imm)); |
126 | return MCDisassembler::Success; |
127 | } |
128 | |
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, 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 | |
143 | enum AddrMode { |
144 | amInvalid = 0, |
145 | amRegister, |
146 | amIndexed, |
147 | amIndirect, |
148 | amIndirectPost, |
149 | amSymbolic, |
150 | amImmediate, |
151 | amAbsolute, |
152 | amConstant |
153 | }; |
154 | |
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 | |
182 | static 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 | |
188 | static 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 | |
194 | static 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 | |
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 | |
230 | 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(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 | |
285 | 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(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 | |
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 | |
340 | 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(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 | |
361 | 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(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 | |