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