diff --git a/lib/Target/Videocore/Disassembler/VideocoreDisassembler.cpp b/lib/Target/Videocore/Disassembler/VideocoreDisassembler.cpp index e5b6cfa3..a94f443a 100644 --- a/lib/Target/Videocore/Disassembler/VideocoreDisassembler.cpp +++ b/lib/Target/Videocore/Disassembler/VideocoreDisassembler.cpp @@ -13,6 +13,7 @@ #define DEBUG_TYPE "vc-disassembler" +#include "MCTargetDesc/VideocoreBinaryInstruction.h" #include "Videocore.h" #include "VideocoreRegisterInfo.h" #include "VideocoreSubtarget.h" @@ -127,64 +128,6 @@ static DecodeStatus DecodeMem_5_12(MCInst &MI, #include "VideocoreGenDisassemblerTables.inc" - /// readInstruction - read the correct number of bytes from the - /// MemoryObject and the full instruction in the correct bit order -static DecodeStatus readInstruction(const MemoryObject ®ion, - uint64_t address, - uint64_t &size, - uint64_t &insn) { - uint8_t bytes[4]; - size = 2; // if we are going to fail, we need to eat at least 2 bytes - - // Read the frist 16 bytes, to determin the length of the instruction - if (region.readBytes(address, 2, (uint8_t*)bytes, NULL) == -1) { - return MCDisassembler::Fail; - } - uint16_t word = bytes[0] | bytes[1] << 8; - - if ((word & 0x8000) == 0x0000) { // 0xxx xxxx xxxx xxxx - 16 bits - insn = word; - size = 2; - return MCDisassembler::Success; - } - if ((word & 0xf000) < 0xe000) { // 1YYx xxxx xxxx xxxx (Where YY != 11) - if (region.readBytes(address+2, 2, (uint8_t*)bytes, NULL) != -1) { - insn = (uint32_t)(word << 16 | bytes[1] << 8 | bytes[0]); - size = 4; - return MCDisassembler::Success; - } - } - if ((word & 0xf000) == 0xe000) { // 1110 xxxx xxxx xxxx - 48 bits - if (region.readBytes(address+2, 4, (uint8_t*)bytes, NULL) != -1) { - insn = ((uint64_t)bytes[3]) << 24 | - bytes[2] << 16 | - bytes[1] << 8 | - bytes[0]; - insn |= ((uint64_t)word) << 32; - size = 6; - return MCDisassembler::Success; - } - } - if ((word & 0xf800) == 0xf000) { // 1111 0xxx xxxx xxxx - vector 48 bits - if (region.readBytes(address+2, 4, (uint8_t*)bytes, NULL) != -1) { - insn = ((uint64_t)bytes[1]) << 24 | - bytes[0] << 16 | - bytes[3] << 8 | - bytes[2]; - insn |= ((uint64_t)word) << 32; - size = 6; - return MCDisassembler::Success; // Unimplemented - } - } - if ((word & 0xf800) == 0xf800) { // 1111 1xxx xxxx xxxx - vector 80 bits - // Vector instruction - size = 10; - return MCDisassembler::Fail; // Unimplemented - } - - return MCDisassembler::Fail; // readBytes failed -} - DecodeStatus VideocoreDisassembler::getInstruction(MCInst &instr, uint64_t &Size, @@ -192,24 +135,20 @@ VideocoreDisassembler::getInstruction(MCInst &instr, uint64_t Address, raw_ostream &vStream, raw_ostream &cStream) const { - uint64_t Insn = 0; - - DecodeStatus Result = readInstruction(Region, Address, Size, Insn); + DecodeStatus Result; + VideocoreBinaryInstr Insn(Region, Address); + Size = Insn.size(); - if (Result == MCDisassembler::Fail) { - if(Size > 4) { - instr.setOpcode((Size == 10) ? VC::VECTOR80 : VC::VECTOR48); - return MCDisassembler::SoftFail; - } + if (Insn.type() == VideocoreBinaryInstr::Invalid) return MCDisassembler::Fail; - } // Calling the auto-generated decoder function. const uint8_t *Table; switch(Size) { - case 2: Table = llvm::DecoderTable16; break; - case 4: Table = llvm::DecoderTable32; break; - case 6: Table = llvm::DecoderTable48; break; + case 2: Table = llvm::DecoderTable16; break; + case 4: Table = llvm::DecoderTable32; break; + case 6: Table = llvm::DecoderTable48; break; + case 10: Table = llvm::DecoderTable80; break; } Result = llvm::decodeInstruction(Table, instr, Insn, Address, this, STI); @@ -218,13 +157,21 @@ VideocoreDisassembler::getInstruction(MCInst &instr, return Result; } - switch(Size) { - case 2: instr.setOpcode(VC::SCALAR16); break; - case 4: instr.setOpcode(VC::SCALAR32); break; - case 6: instr.setOpcode(VC::SCALAR48); break; + switch(Insn.type()) { + case VideocoreBinaryInstr::Scalar16: + instr.setOpcode(VC::SCALAR16); break; + case VideocoreBinaryInstr::Scalar32: + instr.setOpcode(VC::SCALAR32); break; + case VideocoreBinaryInstr::Scalar48: + instr.setOpcode(VC::SCALAR48); break; + case VideocoreBinaryInstr::Vector48: + instr.setOpcode(VC::VECTOR48); break; + case VideocoreBinaryInstr::Vector80: + instr.setOpcode(VC::VECTOR80); break; + default: + return MCDisassembler::Fail; } - return MCDisassembler::SoftFail; } diff --git a/lib/Target/Videocore/MCTargetDesc/VideocoreBinaryInstruction.h b/lib/Target/Videocore/MCTargetDesc/VideocoreBinaryInstruction.h new file mode 100644 index 00000000..0637f569 --- /dev/null +++ b/lib/Target/Videocore/MCTargetDesc/VideocoreBinaryInstruction.h @@ -0,0 +1,329 @@ +//===-- VideocoreBinaryInstr.h ----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains a representation of the raw binary of a variable length +// videocore instruction and methods to read/write in the correct endiness. +// +//===----------------------------------------------------------------------===// + +#ifndef VIDEOCOREBINARYINSTRUCTION_H +#define VIDEOCOREBINARYINSTRYCTION_H + +#include "Videocore.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/MemoryObject.h" + +using namespace llvm; + +static inline uint64_t le_short(const MemoryObject ®ion, uint64_t address) { + uint8_t bytes[2]; + + int ret = region.readBytes(address, 2, (uint8_t*)bytes, NULL); + assert(ret != -1); // FIXME We need to fail better + + return bytes[0] | bytes[1] << 8; +} +static inline uint64_t le_int(const MemoryObject ®ion, uint64_t address) { + uint8_t bytes[4]; + + int ret = region.readBytes(address, 4, (uint8_t*)bytes, NULL); + assert(ret != -1); + + return bytes[0] | bytes[1] << 8 | bytes[2] << 16 | uint64_t(bytes[3]) << 24; +} + +class VideocoreBinaryInstr { +private: + // uint32_t + uint64_t = 96 bits + uint64_t lo; // 64 bits low + uint16_t hi; // 16 bits high + +public: // constructors + VideocoreBinaryInstr() : lo(0), hi(0) {} + VideocoreBinaryInstr(uint32_t value) : lo(value), hi(0) {} + VideocoreBinaryInstr(uint64_t value) : lo(value), hi(0) {} + VideocoreBinaryInstr(int32_t value) : lo(value), hi(0) { if(value < 0) hi = uint16_t(-1); } + VideocoreBinaryInstr(long long int value): lo(value), hi(0) { if(value < 0) hi = uint16_t(-1); } + VideocoreBinaryInstr(uint16_t hi, uint64_t lo): lo(lo), hi(hi) {} + + VideocoreBinaryInstr(const MemoryObject ®ion, uint64_t address) { + hi = 0; + uint16_t word = le_short(region, address); + if ((word & 0x8000) == 0x0000) { + lo = word; + } else if ((word & 0xf000) < 0xe000) { + lo = le_short(region, address+2) | + uint64_t(word) << 16; + } else if ((word & 0xf000) == 0xe000) { + lo = le_int(region, address+2) | + uint64_t(word) << 32; + } else if ((word & 0xf800) == 0xf000) { + lo = le_short(region, address+2) << 16 | + le_short(region, address+4) | + uint64_t(word) << 32; + } else if ((word & 0xf800) == 0xf800) { + lo = le_short(region, address+2) << 48 | + le_short(region, address+4) << 32 | + le_short(region, address+6) << 16 | + le_short(region, address+8); + hi = word; + } + } + +public: + enum Type { + Invalid, + Scalar16, + Scalar32, + Scalar48, + Vector48, + Vector80 + }; + + Type type() { + if ((hi & 0xf800) == 0xf800) + return Vector80; + else if (hi != 0) + return Invalid; + else if ((lo >> 43) == 0x1e) + return Vector48; + else if ((lo >> 44) == 0xe) + return Scalar48; + else if ((lo & 0x80000000) && (lo >> 28) < 0xe) + return Scalar32; + else if ((lo >> 15) == 0) + return Scalar16; + else + return Invalid; + } + + size_t size() { + switch (type()) { + case Scalar16: return 2; + case Scalar32: return 4; + case Scalar48: + case Vector48: return 6; + case Vector80: return 10; + default: return 2; + } + } + + VideocoreBinaryInstr &operator=(const VideocoreBinaryInstr &other) { + if(&other != this) { + lo = other.lo; + hi = other.hi; + } + return *this; + } + +// This class gets passed into TableGen'ed Dissassember code which treats it as +// an unsigned interger. So we overload enough math operators to let the +// Disassembler do it's work. +public: // comparison operators + template + bool operator==(const T &rhs) const { + VideocoreBinaryInstr o = static_cast(rhs); + return hi == o.hi && lo == o.lo; + } + + template + bool operator!=(const T &rhs) const { + VideocoreBinaryInstr o = static_cast(rhs); + return hi != o.hi || lo != o.lo; + } + +public: // unary operators + bool operator!() const { + return !(hi != 0 || lo != 0); + } + + VideocoreBinaryInstr operator-() const { + // standard 2's compliment negation + return ~VideocoreBinaryInstr(*this) + 1; + } + + VideocoreBinaryInstr operator~() const { + VideocoreBinaryInstr t(*this); + t.lo = ~t.lo; + t.hi = ~t.hi; + return t; + } + +public: // basic math operators + template + VideocoreBinaryInstr &operator+=(const otherType &rhs) { + VideocoreBinaryInstr b = static_cast(rhs); + uint64_t old_lo = lo; + + lo += b.lo; + hi += b.hi; + + if(lo < old_lo) { + ++hi; + } + + return *this; + } + + template + VideocoreBinaryInstr &operator-=(const otherType &rhs) { + // it happens to be way easier to write it + // this way instead of make a subtraction algorithm + return *this += -rhs; + } + + template + VideocoreBinaryInstr &operator|=(const otherType &rhs) { + VideocoreBinaryInstr b = static_cast(rhs); + hi |= b.hi; + lo |= b.lo; + return *this; + } + + template + VideocoreBinaryInstr &operator&=(const otherType &b) { + hi &= b.hi; + lo &= b.lo; + return *this; + } + + template + VideocoreBinaryInstr &operator^=(const otherType &b) { + hi ^= b.hi; + lo ^= b.lo; + return *this; + } + + template + VideocoreBinaryInstr &operator<<=(const otherType &rhs) { + uint32_t n = uint32_t(rhs); + + if (n >= 80) { + hi = 0; + lo = 0; + } else { + if (n >= 64) { + n -= 64; + hi = lo; + lo = 0; + } + + if (n != 0) { + hi <<= n; + uint64_t mask = ~(uint64_t(-1) >> n); + hi |= (lo & mask) >> (64 - n); + lo <<= n; + } + } + return *this; + } + + template + VideocoreBinaryInstr &operator>>=(const otherType &rhs) { + uint32_t n = uint32_t(rhs); + + if (n >= 80) { + hi = 0; + lo = 0; + } else { + if (n >= 64) { + n -= 64; + lo = hi; + hi = 0; + } + if (n != 0) { + lo >>= n; + uint64_t mask = ~(uint64_t(-1) << n); + lo |= (hi & mask) >> (64 - n); + hi >>= n; + } + } + return *this; + } + +public: + template + VideocoreBinaryInstr operator|(const otherType &rhs) { + VideocoreBinaryInstr t(*this); + t ^= rhs; + return t; + } + + template + VideocoreBinaryInstr operator&(const otherType &rhs) { + VideocoreBinaryInstr t(*this); + t &= rhs; + return t; + } + + template + VideocoreBinaryInstr operator^(const otherType &rhs) { + VideocoreBinaryInstr t(*this); + t ^= rhs; + return t; + } + + template + VideocoreBinaryInstr operator+(const otherType &rhs) { + VideocoreBinaryInstr t(*this); + t += rhs; + return t; + } + + template + VideocoreBinaryInstr operator-(const otherType &rhs) { + VideocoreBinaryInstr t(*this); + t -= rhs; + return t; + } + + template + VideocoreBinaryInstr operator<<(const otherType &rhs) { + VideocoreBinaryInstr t(*this); + t <<= rhs; + return t; + } + + template + VideocoreBinaryInstr operator>>(const otherType &rhs) { + VideocoreBinaryInstr t(*this); + t >>= rhs; + return t; + } + +public: // casting + operator uint64_t() const { + assert(hi == 0); + return lo; + } + //operator uint32_t() const { + // assert(hi == 0 && (lo & 0xffffffff00000000) == 0); + // return lo; + //} +}; + +// Reverse equality operators +template +bool operator!=(T &lhs, VideocoreBinaryInstr &rhs) { + return rhs != lhs; +} +template +bool operator==(T &lhs, VideocoreBinaryInstr &rhs) { + return rhs == lhs; +} + +// Printing +raw_ostream &operator<<(raw_ostream &O, VideocoreBinaryInstr &b) { + // FIXME: writeout the whole 80bit value, in hex? + return O << uint64_t(b); +} + + +#endif diff --git a/lib/Target/Videocore/VideocoreInstrVector.td b/lib/Target/Videocore/VideocoreInstrVector.td index 294ab54a..c96a34c0 100644 --- a/lib/Target/Videocore/VideocoreInstrVector.td +++ b/lib/Target/Videocore/VideocoreInstrVector.td @@ -275,7 +275,7 @@ defm VMULHDTsu : VectorData<61, "vmulhdt.su">; def VLDW : InstVC80<(outs), (ins), "vldw", []> { - let Inst{79-72} = 0b111101; + let Inst{79-72} = 0b11111000; let Inst{71} = 0; }