summaryrefslogtreecommitdiff
path: root/lib/Target/MSP430/Disassembler/MSP430Disassembler.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2019-01-19 10:01:25 +0000
committerDimitry Andric <dim@FreeBSD.org>2019-01-19 10:01:25 +0000
commitd8e91e46262bc44006913e6796843909f1ac7bcd (patch)
tree7d0c143d9b38190e0fa0180805389da22cd834c5 /lib/Target/MSP430/Disassembler/MSP430Disassembler.cpp
parentb7eb8e35e481a74962664b63dfb09483b200209a (diff)
Notes
Diffstat (limited to 'lib/Target/MSP430/Disassembler/MSP430Disassembler.cpp')
-rw-r--r--lib/Target/MSP430/Disassembler/MSP430Disassembler.cpp387
1 files changed, 387 insertions, 0 deletions
diff --git a/lib/Target/MSP430/Disassembler/MSP430Disassembler.cpp b/lib/Target/MSP430/Disassembler/MSP430Disassembler.cpp
new file mode 100644
index 000000000000..e5da130f9bbb
--- /dev/null
+++ b/lib/Target/MSP430/Disassembler/MSP430Disassembler.cpp
@@ -0,0 +1,387 @@
+//===-- MSP430Disassembler.cpp - Disassembler for MSP430 ------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the MSP430Disassembler class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MSP430.h"
+#include "MCTargetDesc/MSP430MCTargetDesc.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCDisassembler/MCDisassembler.h"
+#include "llvm/MC/MCFixedLenDisassembler.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/TargetRegistry.h"
+
+using namespace llvm;
+
+#define DEBUG_TYPE "msp430-disassembler"
+
+typedef MCDisassembler::DecodeStatus DecodeStatus;
+
+namespace {
+class MSP430Disassembler : public MCDisassembler {
+ DecodeStatus getInstructionI(MCInst &MI, uint64_t &Size,
+ ArrayRef<uint8_t> Bytes, uint64_t Address,
+ raw_ostream &VStream,
+ raw_ostream &CStream) const;
+
+ DecodeStatus getInstructionII(MCInst &MI, uint64_t &Size,
+ ArrayRef<uint8_t> Bytes, uint64_t Address,
+ raw_ostream &VStream,
+ raw_ostream &CStream) const;
+
+ DecodeStatus getInstructionCJ(MCInst &MI, uint64_t &Size,
+ ArrayRef<uint8_t> Bytes, uint64_t Address,
+ raw_ostream &VStream,
+ raw_ostream &CStream) const;
+
+public:
+ MSP430Disassembler(const MCSubtargetInfo &STI, MCContext &Ctx)
+ : MCDisassembler(STI, Ctx) {}
+
+ DecodeStatus getInstruction(MCInst &MI, uint64_t &Size,
+ ArrayRef<uint8_t> Bytes, uint64_t Address,
+ raw_ostream &VStream,
+ raw_ostream &CStream) const override;
+};
+} // end anonymous namespace
+
+static MCDisassembler *createMSP430Disassembler(const Target &T,
+ const MCSubtargetInfo &STI,
+ MCContext &Ctx) {
+ return new MSP430Disassembler(STI, Ctx);
+}
+
+extern "C" void LLVMInitializeMSP430Disassembler() {
+ TargetRegistry::RegisterMCDisassembler(getTheMSP430Target(),
+ createMSP430Disassembler);
+}
+
+static const unsigned GR8DecoderTable[] = {
+ MSP430::PCB, MSP430::SPB, MSP430::SRB, MSP430::CGB,
+ MSP430::FPB, MSP430::R5B, MSP430::R6B, MSP430::R7B,
+ MSP430::R8B, MSP430::R9B, MSP430::R10B, MSP430::R11B,
+ MSP430::R12B, MSP430::R13B, MSP430::R14B, MSP430::R15B
+};
+
+static DecodeStatus DecodeGR8RegisterClass(MCInst &MI, uint64_t RegNo,
+ uint64_t Address,
+ const void *Decoder) {
+ if (RegNo > 15)
+ return MCDisassembler::Fail;
+
+ unsigned Reg = GR8DecoderTable[RegNo];
+ MI.addOperand(MCOperand::createReg(Reg));
+ return MCDisassembler::Success;
+}
+
+static const unsigned GR16DecoderTable[] = {
+ MSP430::PC, MSP430::SP, MSP430::SR, MSP430::CG,
+ MSP430::FP, MSP430::R5, MSP430::R6, MSP430::R7,
+ MSP430::R8, MSP430::R9, MSP430::R10, MSP430::R11,
+ MSP430::R12, MSP430::R13, MSP430::R14, MSP430::R15
+};
+
+static DecodeStatus DecodeGR16RegisterClass(MCInst &MI, uint64_t RegNo,
+ uint64_t Address,
+ const void *Decoder) {
+ if (RegNo > 15)
+ return MCDisassembler::Fail;
+
+ unsigned Reg = GR16DecoderTable[RegNo];
+ MI.addOperand(MCOperand::createReg(Reg));
+ return MCDisassembler::Success;
+}
+
+static DecodeStatus DecodeCGImm(MCInst &MI, uint64_t Bits, uint64_t Address,
+ const void *Decoder);
+
+static DecodeStatus DecodeMemOperand(MCInst &MI, uint64_t Bits,
+ uint64_t Address,
+ const void *Decoder);
+
+#include "MSP430GenDisassemblerTables.inc"
+
+static DecodeStatus DecodeCGImm(MCInst &MI, uint64_t Bits, uint64_t Address,
+ const void *Decoder) {
+ int64_t Imm;
+ switch (Bits) {
+ default:
+ llvm_unreachable("Invalid immediate value");
+ case 0x22: Imm = 4; break;
+ case 0x32: Imm = 8; break;
+ case 0x03: Imm = 0; break;
+ case 0x13: Imm = 1; break;
+ case 0x23: Imm = 2; break;
+ case 0x33: Imm = -1; break;
+ }
+ MI.addOperand(MCOperand::createImm(Imm));
+ return MCDisassembler::Success;
+}
+
+static DecodeStatus DecodeMemOperand(MCInst &MI, uint64_t Bits,
+ uint64_t Address,
+ const void *Decoder) {
+ unsigned Reg = Bits & 15;
+ unsigned Imm = Bits >> 4;
+
+ if (DecodeGR16RegisterClass(MI, Reg, Address, Decoder) !=
+ MCDisassembler::Success)
+ return MCDisassembler::Fail;
+
+ MI.addOperand(MCOperand::createImm((int16_t)Imm));
+ return MCDisassembler::Success;
+}
+
+enum AddrMode {
+ amInvalid = 0,
+ amRegister,
+ amIndexed,
+ amIndirect,
+ amIndirectPost,
+ amSymbolic,
+ amImmediate,
+ amAbsolute,
+ amConstant
+};
+
+static AddrMode DecodeSrcAddrMode(unsigned Rs, unsigned As) {
+ switch (Rs) {
+ case 0:
+ if (As == 1) return amSymbolic;
+ if (As == 2) return amInvalid;
+ if (As == 3) return amImmediate;
+ break;
+ case 2:
+ if (As == 1) return amAbsolute;
+ if (As == 2) return amConstant;
+ if (As == 3) return amConstant;
+ break;
+ case 3:
+ return amConstant;
+ default:
+ break;
+ }
+ switch (As) {
+ case 0: return amRegister;
+ case 1: return amIndexed;
+ case 2: return amIndirect;
+ case 3: return amIndirectPost;
+ default:
+ llvm_unreachable("As out of range");
+ }
+}
+
+static AddrMode DecodeSrcAddrModeI(unsigned Insn) {
+ unsigned Rs = fieldFromInstruction(Insn, 8, 4);
+ unsigned As = fieldFromInstruction(Insn, 4, 2);
+ return DecodeSrcAddrMode(Rs, As);
+}
+
+static AddrMode DecodeSrcAddrModeII(unsigned Insn) {
+ unsigned Rs = fieldFromInstruction(Insn, 0, 4);
+ unsigned As = fieldFromInstruction(Insn, 4, 2);
+ return DecodeSrcAddrMode(Rs, As);
+}
+
+static AddrMode DecodeDstAddrMode(unsigned Insn) {
+ unsigned Rd = fieldFromInstruction(Insn, 0, 4);
+ unsigned Ad = fieldFromInstruction(Insn, 7, 1);
+ switch (Rd) {
+ case 0: return Ad ? amSymbolic : amRegister;
+ case 2: return Ad ? amAbsolute : amRegister;
+ default:
+ break;
+ }
+ return Ad ? amIndexed : amRegister;
+}
+
+static const uint8_t *getDecoderTable(AddrMode SrcAM, unsigned Words) {
+ assert(0 < Words && Words < 4 && "Incorrect number of words");
+ switch (SrcAM) {
+ default:
+ llvm_unreachable("Invalid addressing mode");
+ case amRegister:
+ assert(Words < 3 && "Incorrect number of words");
+ return Words == 2 ? DecoderTableAlpha32 : DecoderTableAlpha16;
+ case amConstant:
+ assert(Words < 3 && "Incorrect number of words");
+ return Words == 2 ? DecoderTableBeta32 : DecoderTableBeta16;
+ case amIndexed:
+ case amSymbolic:
+ case amImmediate:
+ case amAbsolute:
+ assert(Words > 1 && "Incorrect number of words");
+ return Words == 2 ? DecoderTableGamma32 : DecoderTableGamma48;
+ case amIndirect:
+ case amIndirectPost:
+ assert(Words < 3 && "Incorrect number of words");
+ return Words == 2 ? DecoderTableDelta32 : DecoderTableDelta16;
+ }
+}
+
+DecodeStatus MSP430Disassembler::getInstructionI(MCInst &MI, uint64_t &Size,
+ ArrayRef<uint8_t> Bytes,
+ uint64_t Address,
+ raw_ostream &VStream,
+ raw_ostream &CStream) const {
+ uint64_t Insn = support::endian::read16le(Bytes.data());
+ AddrMode SrcAM = DecodeSrcAddrModeI(Insn);
+ AddrMode DstAM = DecodeDstAddrMode(Insn);
+ if (SrcAM == amInvalid || DstAM == amInvalid) {
+ Size = 2; // skip one word and let disassembler to try further
+ return MCDisassembler::Fail;
+ }
+
+ unsigned Words = 1;
+ switch (SrcAM) {
+ case amIndexed:
+ case amSymbolic:
+ case amImmediate:
+ case amAbsolute:
+ if (Bytes.size() < (Words + 1) * 2) {
+ Size = 2;
+ return DecodeStatus::Fail;
+ }
+ Insn |= (uint64_t)support::endian::read16le(Bytes.data() + 2) << 16;
+ ++Words;
+ break;
+ default:
+ break;
+ }
+ switch (DstAM) {
+ case amIndexed:
+ case amSymbolic:
+ case amAbsolute:
+ if (Bytes.size() < (Words + 1) * 2) {
+ Size = 2;
+ return DecodeStatus::Fail;
+ }
+ Insn |= (uint64_t)support::endian::read16le(Bytes.data() + Words * 2)
+ << (Words * 16);
+ ++Words;
+ break;
+ default:
+ break;
+ }
+
+ DecodeStatus Result = decodeInstruction(getDecoderTable(SrcAM, Words), MI,
+ Insn, Address, this, STI);
+ if (Result != MCDisassembler::Fail) {
+ Size = Words * 2;
+ return Result;
+ }
+
+ Size = 2;
+ return DecodeStatus::Fail;
+}
+
+DecodeStatus MSP430Disassembler::getInstructionII(MCInst &MI, uint64_t &Size,
+ ArrayRef<uint8_t> Bytes,
+ uint64_t Address,
+ raw_ostream &VStream,
+ raw_ostream &CStream) const {
+ uint64_t Insn = support::endian::read16le(Bytes.data());
+ AddrMode SrcAM = DecodeSrcAddrModeII(Insn);
+ if (SrcAM == amInvalid) {
+ Size = 2; // skip one word and let disassembler to try further
+ return MCDisassembler::Fail;
+ }
+
+ unsigned Words = 1;
+ switch (SrcAM) {
+ case amIndexed:
+ case amSymbolic:
+ case amImmediate:
+ case amAbsolute:
+ if (Bytes.size() < (Words + 1) * 2) {
+ Size = 2;
+ return DecodeStatus::Fail;
+ }
+ Insn |= (uint64_t)support::endian::read16le(Bytes.data() + 2) << 16;
+ ++Words;
+ break;
+ default:
+ break;
+ }
+
+ const uint8_t *DecoderTable = Words == 2 ? DecoderTable32 : DecoderTable16;
+ DecodeStatus Result = decodeInstruction(DecoderTable, MI, Insn, Address,
+ this, STI);
+ if (Result != MCDisassembler::Fail) {
+ Size = Words * 2;
+ return Result;
+ }
+
+ Size = 2;
+ return DecodeStatus::Fail;
+}
+
+static MSP430CC::CondCodes getCondCode(unsigned Cond) {
+ switch (Cond) {
+ case 0: return MSP430CC::COND_NE;
+ case 1: return MSP430CC::COND_E;
+ case 2: return MSP430CC::COND_LO;
+ case 3: return MSP430CC::COND_HS;
+ case 4: return MSP430CC::COND_N;
+ case 5: return MSP430CC::COND_GE;
+ case 6: return MSP430CC::COND_L;
+ case 7: return MSP430CC::COND_NONE;
+ default:
+ llvm_unreachable("Cond out of range");
+ }
+}
+
+DecodeStatus MSP430Disassembler::getInstructionCJ(MCInst &MI, uint64_t &Size,
+ ArrayRef<uint8_t> Bytes,
+ uint64_t Address,
+ raw_ostream &VStream,
+ raw_ostream &CStream) const {
+ uint64_t Insn = support::endian::read16le(Bytes.data());
+ unsigned Cond = fieldFromInstruction(Insn, 10, 3);
+ unsigned Offset = fieldFromInstruction(Insn, 0, 10);
+
+ MI.addOperand(MCOperand::createImm(SignExtend32(Offset, 10)));
+
+ if (Cond == 7)
+ MI.setOpcode(MSP430::JMP);
+ else {
+ MI.setOpcode(MSP430::JCC);
+ MI.addOperand(MCOperand::createImm(getCondCode(Cond)));
+ }
+
+ Size = 2;
+ return DecodeStatus::Success;
+}
+
+DecodeStatus MSP430Disassembler::getInstruction(MCInst &MI, uint64_t &Size,
+ ArrayRef<uint8_t> Bytes,
+ uint64_t Address,
+ raw_ostream &VStream,
+ raw_ostream &CStream) const {
+ if (Bytes.size() < 2) {
+ Size = 0;
+ return MCDisassembler::Fail;
+ }
+
+ uint64_t Insn = support::endian::read16le(Bytes.data());
+ unsigned Opc = fieldFromInstruction(Insn, 13, 3);
+ switch (Opc) {
+ case 0:
+ return getInstructionII(MI, Size, Bytes, Address, VStream, CStream);
+ case 1:
+ return getInstructionCJ(MI, Size, Bytes, Address, VStream, CStream);
+ default:
+ return getInstructionI(MI, Size, Bytes, Address, VStream, CStream);
+ }
+}