mirror of
https://github.com/Inori/GPCS4.git
synced 2024-05-20 13:07:58 -04:00
introduce new gcn decoder
This commit is contained in:
parent
86f9b04502
commit
a8ff46542b
|
@ -25,7 +25,9 @@
|
|||
<ClInclude Include="Emulator\VirtualCPU.h" />
|
||||
<ClInclude Include="Graphics\Gcn\GcnCommon.h" />
|
||||
<ClInclude Include="Graphics\Gcn\GcnContants.h" />
|
||||
<ClInclude Include="Graphics\Gcn\GcnEnums.h" />
|
||||
<ClInclude Include="Graphics\Gcn\GcnDecoder.h" />
|
||||
<ClInclude Include="Graphics\Gcn\GcnEnum.h" />
|
||||
<ClInclude Include="Graphics\Gcn\GcnInstruction.h" />
|
||||
<ClInclude Include="Graphics\Gcn\GcnProgramInfo.h" />
|
||||
<ClInclude Include="Graphics\Gcn\GcnShaderRegField.h" />
|
||||
<ClInclude Include="Graphics\Gcn\GcnShaderRegister.h" />
|
||||
|
@ -259,6 +261,8 @@
|
|||
<ClCompile Include="Emulator\TLSHandler.cpp" />
|
||||
<ClCompile Include="Emulator\VirtualCPU.cpp" />
|
||||
<ClCompile Include="GPCS4Main.cpp" />
|
||||
<ClCompile Include="Graphics\Gcn\GcnDecoder.cpp" />
|
||||
<ClCompile Include="Graphics\Gcn\GcnInstruction.cpp" />
|
||||
<ClCompile Include="Graphics\Gcn\GcnProgramInfo.cpp" />
|
||||
<ClCompile Include="Graphics\Gnm\GnmCommandBuffer.cpp" />
|
||||
<ClCompile Include="Graphics\Gnm\GnmCommandBufferDispatch.cpp" />
|
||||
|
|
|
@ -814,9 +814,6 @@
|
|||
<ClInclude Include="Graphics\Gcn\GcnContants.h">
|
||||
<Filter>Source Files\Graphics\Gcn</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Graphics\Gcn\GcnEnums.h">
|
||||
<Filter>Source Files\Graphics\Gcn</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Graphics\Gcn\GcnShaderRegField.h">
|
||||
<Filter>Source Files\Graphics\Gcn</Filter>
|
||||
</ClInclude>
|
||||
|
@ -826,6 +823,15 @@
|
|||
<ClInclude Include="Graphics\Gcn\GcnProgramInfo.h">
|
||||
<Filter>Source Files\Graphics\Gcn</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Graphics\Gcn\GcnDecoder.h">
|
||||
<Filter>Source Files\Graphics\Gcn</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Graphics\Gcn\GcnEnum.h">
|
||||
<Filter>Source Files\Graphics\Gcn</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Graphics\Gcn\GcnInstruction.h">
|
||||
<Filter>Source Files\Graphics\Gcn</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Loader\EbootObject.cpp">
|
||||
|
@ -1428,6 +1434,12 @@
|
|||
<ClCompile Include="Graphics\Gcn\GcnProgramInfo.cpp">
|
||||
<Filter>Source Files\Graphics\Gcn</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Graphics\Gcn\GcnDecoder.cpp">
|
||||
<Filter>Source Files\Graphics\Gcn</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Graphics\Gcn\GcnInstruction.cpp">
|
||||
<Filter>Source Files\Graphics\Gcn</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Text Include="Emulator\TLSStub.asm">
|
||||
|
|
856
GPCS4/Graphics/Gcn/GcnDecoder.cpp
Normal file
856
GPCS4/Graphics/Gcn/GcnDecoder.cpp
Normal file
|
@ -0,0 +1,856 @@
|
|||
#include "GcnDecoder.h"
|
||||
|
||||
#include "UtilBit.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
using namespace util;
|
||||
|
||||
LOG_CHANNEL(Graphic.Gcn.GcnDecoder);
|
||||
|
||||
namespace sce::gcn
|
||||
{
|
||||
|
||||
uint32_t GcnCodeSlice::at(uint32_t id) const
|
||||
{
|
||||
return m_ptr[id];
|
||||
}
|
||||
|
||||
uint32_t GcnCodeSlice::readu32()
|
||||
{
|
||||
return *(m_ptr++);
|
||||
}
|
||||
|
||||
uint64_t GcnCodeSlice::readu64()
|
||||
{
|
||||
uint64_t value = *(uint64_t*)m_ptr;
|
||||
m_ptr += 2;
|
||||
return value;
|
||||
}
|
||||
|
||||
///
|
||||
|
||||
GcnDecodeContext::GcnDecodeContext()
|
||||
{
|
||||
}
|
||||
|
||||
GcnDecodeContext::~GcnDecodeContext()
|
||||
{
|
||||
}
|
||||
|
||||
void GcnDecodeContext::decodeInstruction(GcnCodeSlice& code)
|
||||
{
|
||||
const uint32_t token = code.at(0);
|
||||
|
||||
GcnInstEncoding encoding = getInstructionEncoding(token);
|
||||
LOG_ASSERT(encoding != GcnInstEncoding::ILLEGAL, "illegal encoding %d", encoding);
|
||||
uint32_t encodingLen = getEncodingLength(encoding);
|
||||
|
||||
// Clear the instruction
|
||||
m_instruction = GcnShaderInstruction();
|
||||
// Decode
|
||||
if (encodingLen == sizeof(uint32_t))
|
||||
{
|
||||
decodeInstruction32(encoding, code);
|
||||
}
|
||||
else
|
||||
{
|
||||
decodeInstruction64(encoding, code);
|
||||
}
|
||||
|
||||
// Update instruction meta info.
|
||||
updateInstructionMeta(encoding);
|
||||
|
||||
// Detect literal constant.
|
||||
// Only 32 bits instructions may have literal constant.
|
||||
// Note:
|
||||
// Literal constant decode must be performed after meta info updated.
|
||||
if (encodingLen == sizeof(uint32_t))
|
||||
{
|
||||
decodeLiteralConstant(encoding, code);
|
||||
}
|
||||
}
|
||||
|
||||
GcnInstEncoding GcnDecodeContext::getInstructionEncoding(uint32_t hexInstruction)
|
||||
{
|
||||
GcnInstEncoding instructionEncoding = GcnInstEncoding::ILLEGAL;
|
||||
/// Try all instructions encoding masks from longest to shortest until
|
||||
/// legal GcnInstEncoding is found.
|
||||
|
||||
/// GcnEncodingMask::Mask9bit
|
||||
instructionEncoding = static_cast<GcnInstEncoding>(hexInstruction & (uint32_t)GcnEncodingMask::MASK_9bit);
|
||||
|
||||
switch (instructionEncoding)
|
||||
{
|
||||
case GcnInstEncoding::SOP1:
|
||||
case GcnInstEncoding::SOPP:
|
||||
case GcnInstEncoding::SOPC:
|
||||
return instructionEncoding;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/// GcnEncodingMask::Mask7bit
|
||||
instructionEncoding = static_cast<GcnInstEncoding>(hexInstruction & (uint32_t)GcnEncodingMask::MASK_7bit);
|
||||
|
||||
switch (instructionEncoding)
|
||||
{
|
||||
case GcnInstEncoding::VOP1:
|
||||
case GcnInstEncoding::VOPC:
|
||||
return instructionEncoding;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/// GcnEncodingMask::Mask6bit
|
||||
instructionEncoding = static_cast<GcnInstEncoding>(hexInstruction & (uint32_t)GcnEncodingMask::MASK_6bit);
|
||||
|
||||
switch (instructionEncoding)
|
||||
{
|
||||
case GcnInstEncoding::VOP3:
|
||||
case GcnInstEncoding::EXP:
|
||||
case GcnInstEncoding::VINTRP:
|
||||
case GcnInstEncoding::DS:
|
||||
case GcnInstEncoding::MUBUF:
|
||||
case GcnInstEncoding::MTBUF:
|
||||
case GcnInstEncoding::MIMG:
|
||||
return instructionEncoding;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/// GcnEncodingMask::Mask5bit
|
||||
instructionEncoding = static_cast<GcnInstEncoding>(hexInstruction & (uint32_t)GcnEncodingMask::MASK_5bit);
|
||||
|
||||
switch (instructionEncoding)
|
||||
{
|
||||
case GcnInstEncoding::SMRD:
|
||||
return instructionEncoding;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/// GcnEncodingMask::Mask4bit
|
||||
instructionEncoding = static_cast<GcnInstEncoding>(hexInstruction & (uint32_t)GcnEncodingMask::MASK_4bit);
|
||||
|
||||
switch (instructionEncoding)
|
||||
{
|
||||
case GcnInstEncoding::SOPK:
|
||||
return instructionEncoding;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/// GcnEncodingMask::Mask2bit
|
||||
instructionEncoding = static_cast<GcnInstEncoding>(hexInstruction & (uint32_t)GcnEncodingMask::MASK_2bit);
|
||||
|
||||
switch (instructionEncoding)
|
||||
{
|
||||
case GcnInstEncoding::SOP2:
|
||||
return instructionEncoding;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/// GcnEncodingMask::Mask1bit
|
||||
instructionEncoding = static_cast<GcnInstEncoding>(hexInstruction & (uint32_t)GcnEncodingMask::MASK_1bit);
|
||||
|
||||
switch (instructionEncoding)
|
||||
{
|
||||
case GcnInstEncoding::VOP2:
|
||||
return instructionEncoding;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/// If no legal GcnInstEncoding found return GcnInstEncoding::ILLEGAL
|
||||
return GcnInstEncoding::ILLEGAL;
|
||||
}
|
||||
|
||||
uint32_t GcnDecodeContext::getEncodingLength(GcnInstEncoding encoding)
|
||||
{
|
||||
uint32_t instLength = 0;
|
||||
|
||||
switch (encoding)
|
||||
{
|
||||
case GcnInstEncoding::SOP1:
|
||||
case GcnInstEncoding::SOPP:
|
||||
case GcnInstEncoding::SOPC:
|
||||
case GcnInstEncoding::SOPK:
|
||||
case GcnInstEncoding::SOP2:
|
||||
case GcnInstEncoding::VOP1:
|
||||
case GcnInstEncoding::VOPC:
|
||||
case GcnInstEncoding::VOP2:
|
||||
case GcnInstEncoding::SMRD:
|
||||
case GcnInstEncoding::VINTRP:
|
||||
instLength = sizeof(uint32_t);
|
||||
break;
|
||||
|
||||
case GcnInstEncoding::VOP3:
|
||||
case GcnInstEncoding::MUBUF:
|
||||
case GcnInstEncoding::MTBUF:
|
||||
case GcnInstEncoding::MIMG:
|
||||
case GcnInstEncoding::DS:
|
||||
case GcnInstEncoding::EXP:
|
||||
instLength = sizeof(uint64_t);
|
||||
break;
|
||||
}
|
||||
return instLength;
|
||||
}
|
||||
|
||||
uint32_t GcnDecodeContext::getOpMapOffset(GcnInstEncoding encoding)
|
||||
{
|
||||
uint32_t offset = 0;
|
||||
switch (encoding)
|
||||
{
|
||||
case GcnInstEncoding::SOP1:
|
||||
offset = (uint32_t)GcnOpcodeMap::OP_MAP_SOP1;
|
||||
break;
|
||||
case GcnInstEncoding::SOPP:
|
||||
offset = (uint32_t)GcnOpcodeMap::OP_MAP_SOPP;
|
||||
break;
|
||||
case GcnInstEncoding::SOPC:
|
||||
offset = (uint32_t)GcnOpcodeMap::OP_MAP_SOPC;
|
||||
break;
|
||||
case GcnInstEncoding::VOP1:
|
||||
offset = (uint32_t)GcnOpcodeMap::OP_MAP_VOP1;
|
||||
break;
|
||||
case GcnInstEncoding::VOPC:
|
||||
offset = (uint32_t)GcnOpcodeMap::OP_MAP_VOPC;
|
||||
break;
|
||||
case GcnInstEncoding::VOP3:
|
||||
offset = (uint32_t)GcnOpcodeMap::OP_MAP_VOP3;
|
||||
break;
|
||||
case GcnInstEncoding::EXP:
|
||||
offset = (uint32_t)GcnOpcodeMap::OP_MAP_EXP;
|
||||
break;
|
||||
case GcnInstEncoding::VINTRP:
|
||||
offset = (uint32_t)GcnOpcodeMap::OP_MAP_VINTRP;
|
||||
break;
|
||||
case GcnInstEncoding::DS:
|
||||
offset = (uint32_t)GcnOpcodeMap::OP_MAP_DS;
|
||||
break;
|
||||
case GcnInstEncoding::MUBUF:
|
||||
offset = (uint32_t)GcnOpcodeMap::OP_MAP_MUBUF;
|
||||
break;
|
||||
case GcnInstEncoding::MTBUF:
|
||||
offset = (uint32_t)GcnOpcodeMap::OP_MAP_MTBUF;
|
||||
break;
|
||||
case GcnInstEncoding::MIMG:
|
||||
offset = (uint32_t)GcnOpcodeMap::OP_MAP_MIMG;
|
||||
break;
|
||||
case GcnInstEncoding::SMRD:
|
||||
offset = (uint32_t)GcnOpcodeMap::OP_MAP_SMRD;
|
||||
break;
|
||||
case GcnInstEncoding::SOPK:
|
||||
offset = (uint32_t)GcnOpcodeMap::OP_MAP_SOPK;
|
||||
break;
|
||||
case GcnInstEncoding::SOP2:
|
||||
offset = (uint32_t)GcnOpcodeMap::OP_MAP_SOP2;
|
||||
break;
|
||||
case GcnInstEncoding::VOP2:
|
||||
offset = (uint32_t)GcnOpcodeMap::OP_MAP_VOP2;
|
||||
break;
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
uint32_t GcnDecodeContext::mapEncodingOp(GcnInstEncoding encoding, GcnOpcode opcode)
|
||||
{
|
||||
// Map from uniform opcode to encoding specific opcode.
|
||||
|
||||
uint32_t encodingOp = 0;
|
||||
|
||||
if (encoding == GcnInstEncoding::VOP3)
|
||||
{
|
||||
if (opcode >= GcnOpcode::V_CMP_F_F32 && opcode <= GcnOpcode::V_CMPX_T_U64)
|
||||
{
|
||||
uint32_t op = static_cast<uint32_t>(opcode) - static_cast<uint32_t>(GcnOpcodeMap::OP_MAP_VOPC);
|
||||
encodingOp = op + static_cast<uint32_t>(GcnOpMapVOP3VOPX::VOP3_TO_VOPC);
|
||||
}
|
||||
else if (opcode >= GcnOpcode::V_CNDMASK_B32 && opcode <= GcnOpcode::V_CVT_PK_I16_I32)
|
||||
{
|
||||
uint32_t op = static_cast<uint32_t>(opcode) - static_cast<uint32_t>(GcnOpcodeMap::OP_MAP_VOP2);
|
||||
encodingOp = op + static_cast<uint32_t>(GcnOpMapVOP3VOPX::VOP3_TO_VOP2);
|
||||
}
|
||||
else if (opcode >= GcnOpcode::V_NOP && opcode <= GcnOpcode::V_MOVRELSD_B32)
|
||||
{
|
||||
uint32_t op = static_cast<uint32_t>(opcode) - static_cast<uint32_t>(GcnOpcodeMap::OP_MAP_VOP1);
|
||||
encodingOp = op + static_cast<uint32_t>(GcnOpMapVOP3VOPX::VOP3_TO_VOP1);
|
||||
}
|
||||
else
|
||||
{
|
||||
encodingOp = static_cast<uint32_t>(opcode) - static_cast<uint32_t>(GcnOpcodeMap::OP_MAP_VOP3);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t mapOffset = getOpMapOffset(encoding);
|
||||
encodingOp = static_cast<uint32_t>(opcode) - mapOffset;
|
||||
}
|
||||
|
||||
return encodingOp;
|
||||
}
|
||||
|
||||
bool GcnDecodeContext::hasAdditionalLiteral(GcnInstEncoding encoding, uint32_t opcode)
|
||||
{
|
||||
// Some instructions require an additional literal constant following the binary stream
|
||||
// even if LiteralConst is not specified in src operand.
|
||||
|
||||
bool hasLiteral = false;
|
||||
switch (encoding)
|
||||
{
|
||||
case GcnInstEncoding::SOPK:
|
||||
{
|
||||
if (opcode == (uint32_t)GcnOpcodeSOPK::S_SETREG_IMM32_B32)
|
||||
{
|
||||
hasLiteral = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case GcnInstEncoding::VOP2:
|
||||
{
|
||||
if (opcode == (uint32_t)GcnOpcodeVOP2::V_MADMK_F32 ||
|
||||
opcode == (uint32_t)GcnOpcodeVOP2::V_MADAK_F32)
|
||||
{
|
||||
hasLiteral = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return hasLiteral;
|
||||
}
|
||||
|
||||
void GcnDecodeContext::updateInstructionMeta(GcnInstEncoding encoding)
|
||||
{
|
||||
uint32_t encodingOp = mapEncodingOp(encoding, m_instruction.opcode);
|
||||
GcnInstFormat instFormat = gcnInstructionFormat(encoding, encodingOp);
|
||||
|
||||
m_instruction.opClass = instFormat.instructionClass;
|
||||
m_instruction.encoding = encoding;
|
||||
m_instruction.srcCount = instFormat.srcCount;
|
||||
m_instruction.length = getEncodingLength(encoding);
|
||||
|
||||
// Update src operand numeric type.
|
||||
// Dst operand's type is set during instruction decoding.
|
||||
auto setOperandNumType = [&instFormat](GcnInstOperand& src)
|
||||
{
|
||||
// Only update uninitialized numeric type.
|
||||
if (src.numericType == GcnNumericType::Undefined)
|
||||
{
|
||||
src.numericType = instFormat.srcType;
|
||||
}
|
||||
};
|
||||
|
||||
std::for_each_n(std::begin(m_instruction.src), m_instruction.srcCount, setOperandNumType);
|
||||
}
|
||||
|
||||
GcnOperandField GcnDecodeContext::getOperandField(uint32_t code)
|
||||
{
|
||||
GcnOperandField field = {};
|
||||
|
||||
if (code >= ScalarGPRMin && code <= ScalarGPRMax)
|
||||
{
|
||||
field = GcnOperandField::ScalarGPR;
|
||||
}
|
||||
else if (code >= SignedConstIntPosMin && code <= SignedConstIntPosMax)
|
||||
{
|
||||
field = GcnOperandField::SignedConstIntPos;
|
||||
}
|
||||
else if (code >= SignedConstIntNegMin && code <= SignedConstIntNegMax)
|
||||
{
|
||||
field = GcnOperandField::SignedConstIntNeg;
|
||||
}
|
||||
else if (code >= VectorGPRMin && code <= VectorGPRMax)
|
||||
{
|
||||
field = GcnOperandField::VectorGPR;
|
||||
}
|
||||
else
|
||||
{
|
||||
field = static_cast<GcnOperandField>(code);
|
||||
}
|
||||
|
||||
return field;
|
||||
}
|
||||
|
||||
void GcnDecodeContext::decodeInstruction32(GcnInstEncoding encoding, GcnCodeSlice& code)
|
||||
{
|
||||
uint32_t hexInstruction = code.readu32();
|
||||
switch (encoding)
|
||||
{
|
||||
case GcnInstEncoding::SOP1:
|
||||
decodeInstructionSOP1(hexInstruction);
|
||||
break;
|
||||
case GcnInstEncoding::SOPP:
|
||||
decodeInstructionSOPP(hexInstruction);
|
||||
break;
|
||||
case GcnInstEncoding::SOPC:
|
||||
decodeInstructionSOPC(hexInstruction);
|
||||
break;
|
||||
case GcnInstEncoding::SOPK:
|
||||
decodeInstructionSOPK(hexInstruction);
|
||||
break;
|
||||
case GcnInstEncoding::SOP2:
|
||||
decodeInstructionSOP2(hexInstruction);
|
||||
break;
|
||||
case GcnInstEncoding::VOP1:
|
||||
decodeInstructionVOP1(hexInstruction);
|
||||
break;
|
||||
case GcnInstEncoding::VOPC:
|
||||
decodeInstructionVOPC(hexInstruction);
|
||||
break;
|
||||
case GcnInstEncoding::VOP2:
|
||||
decodeInstructionVOP2(hexInstruction);
|
||||
break;
|
||||
case GcnInstEncoding::SMRD:
|
||||
decodeInstructionSMRD(hexInstruction);
|
||||
break;
|
||||
case GcnInstEncoding::VINTRP:
|
||||
decodeInstructionVINTRP(hexInstruction);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void GcnDecodeContext::decodeInstruction64(GcnInstEncoding encoding, GcnCodeSlice& code)
|
||||
{
|
||||
uint64_t hexInstruction = code.readu64();
|
||||
switch (encoding)
|
||||
{
|
||||
case GcnInstEncoding::VOP3:
|
||||
decodeInstructionVOP3(hexInstruction);
|
||||
break;
|
||||
case GcnInstEncoding::MUBUF:
|
||||
decodeInstructionMUBUF(hexInstruction);
|
||||
break;
|
||||
case GcnInstEncoding::MTBUF:
|
||||
decodeInstructionMTBUF(hexInstruction);
|
||||
break;
|
||||
case GcnInstEncoding::MIMG:
|
||||
decodeInstructionMIMG(hexInstruction);
|
||||
break;
|
||||
case GcnInstEncoding::DS:
|
||||
decodeInstructionDS(hexInstruction);
|
||||
break;
|
||||
case GcnInstEncoding::EXP:
|
||||
decodeInstructionEXP(hexInstruction);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void GcnDecodeContext::decodeLiteralConstant(GcnInstEncoding encoding, GcnCodeSlice& code)
|
||||
{
|
||||
bool hasLiteral = false;
|
||||
do
|
||||
{
|
||||
// Detect if it's a special instruction.
|
||||
hasLiteral = hasAdditionalLiteral(
|
||||
encoding, mapEncodingOp(encoding, m_instruction.opcode));
|
||||
|
||||
if (hasLiteral)
|
||||
{
|
||||
uint32_t literalCount = code.readu32();
|
||||
m_instruction.src[m_instruction.srcCount++].literalConst = literalCount;
|
||||
break;
|
||||
}
|
||||
|
||||
// Find if the instruction contains a literal constant
|
||||
auto isLiteralSrc = [](GcnInstOperand& src)
|
||||
{
|
||||
return src.field == GcnOperandField::LiteralConst;
|
||||
};
|
||||
|
||||
auto iter = std::find_if(
|
||||
std::begin(m_instruction.src),
|
||||
std::end(m_instruction.src),
|
||||
isLiteralSrc);
|
||||
|
||||
hasLiteral = (iter != std::end(m_instruction.src));
|
||||
|
||||
if (hasLiteral)
|
||||
{
|
||||
uint32_t literalCount = code.readu32();
|
||||
iter->literalConst = literalCount;
|
||||
break;
|
||||
}
|
||||
|
||||
} while (false);
|
||||
|
||||
// Increase instruction length by 4
|
||||
// if literal constant append.
|
||||
if (hasLiteral)
|
||||
{
|
||||
m_instruction.length += sizeof(uint32_t);
|
||||
}
|
||||
}
|
||||
|
||||
void GcnDecodeContext::decodeInstructionSOP1(uint32_t hexInstruction)
|
||||
{
|
||||
uint32_t ssrc0 = bit::extract(hexInstruction, 7, 0);
|
||||
uint32_t op = bit::extract(hexInstruction, 15, 8);
|
||||
uint32_t sdst = bit::extract(hexInstruction, 22, 16);
|
||||
|
||||
m_instruction.opcode = static_cast<GcnOpcode>(op + static_cast<uint32_t>(GcnOpcodeMap::OP_MAP_SOP1));
|
||||
|
||||
m_instruction.src[0].field = getOperandField(ssrc0);
|
||||
m_instruction.src[0].code = ssrc0;
|
||||
m_instruction.dst[0].field = getOperandField(sdst);
|
||||
m_instruction.dst[0].code = sdst;
|
||||
m_instruction.dstCount = 1;
|
||||
}
|
||||
|
||||
void GcnDecodeContext::decodeInstructionSOPP(uint32_t hexInstruction)
|
||||
{
|
||||
uint32_t op = bit::extract(hexInstruction, 22, 16);
|
||||
|
||||
m_instruction.opcode = static_cast<GcnOpcode>(op + static_cast<uint32_t>(GcnOpcodeMap::OP_MAP_SOPP));
|
||||
|
||||
m_instruction.control.sopp = *reinterpret_cast<GcnInstControlSOPP*>(&hexInstruction);
|
||||
}
|
||||
|
||||
void GcnDecodeContext::decodeInstructionSOPC(uint32_t hexInstruction)
|
||||
{
|
||||
uint32_t ssrc0 = bit::extract(hexInstruction, 7, 0);
|
||||
uint32_t ssrc1 = bit::extract(hexInstruction, 15, 8);
|
||||
uint32_t op = bit::extract(hexInstruction, 22, 16);
|
||||
|
||||
m_instruction.opcode = static_cast<GcnOpcode>(op + static_cast<uint32_t>(GcnOpcodeMap::OP_MAP_SOPC));
|
||||
|
||||
m_instruction.src[0].field = getOperandField(ssrc0);
|
||||
m_instruction.src[0].code = ssrc0;
|
||||
m_instruction.src[1].field = getOperandField(ssrc1);
|
||||
m_instruction.src[1].code = ssrc1;
|
||||
}
|
||||
|
||||
void GcnDecodeContext::decodeInstructionSOPK(uint32_t hexInstruction)
|
||||
{
|
||||
uint32_t sdst = bit::extract(hexInstruction, 22, 16);
|
||||
uint32_t op = bit::extract(hexInstruction, 27, 23);
|
||||
|
||||
m_instruction.opcode = static_cast<GcnOpcode>(op + static_cast<uint32_t>(GcnOpcodeMap::OP_MAP_SOPK));
|
||||
|
||||
m_instruction.dst[0].field = getOperandField(sdst);
|
||||
m_instruction.dst[0].code = sdst;
|
||||
m_instruction.dstCount = 1;
|
||||
|
||||
m_instruction.control.sopk = *reinterpret_cast<GcnInstControlSOPK*>(&hexInstruction);
|
||||
}
|
||||
|
||||
void GcnDecodeContext::decodeInstructionSOP2(uint32_t hexInstruction)
|
||||
{
|
||||
uint32_t ssrc0 = bit::extract(hexInstruction, 7, 0);
|
||||
uint32_t ssrc1 = bit::extract(hexInstruction, 15, 8);
|
||||
uint32_t sdst = bit::extract(hexInstruction, 22, 16);
|
||||
uint32_t op = bit::extract(hexInstruction, 29, 23);
|
||||
|
||||
m_instruction.opcode = static_cast<GcnOpcode>(op + static_cast<uint32_t>(GcnOpcodeMap::OP_MAP_SOP2));
|
||||
|
||||
m_instruction.src[0].field = getOperandField(ssrc0);
|
||||
m_instruction.src[0].code = ssrc0;
|
||||
m_instruction.src[1].field = getOperandField(ssrc1);
|
||||
m_instruction.src[1].code = ssrc1;
|
||||
m_instruction.dst[0].field = getOperandField(sdst);
|
||||
m_instruction.dst[0].code = sdst;
|
||||
m_instruction.dstCount = 1;
|
||||
}
|
||||
|
||||
void GcnDecodeContext::decodeInstructionVOP1(uint32_t hexInstruction)
|
||||
{
|
||||
uint32_t src0 = bit::extract(hexInstruction, 8, 0);
|
||||
uint32_t op = bit::extract(hexInstruction, 16, 9);
|
||||
uint32_t vdst = bit::extract(hexInstruction, 24, 17);
|
||||
|
||||
m_instruction.opcode = static_cast<GcnOpcode>(op + static_cast<uint32_t>(GcnOpcodeMap::OP_MAP_VOP1));
|
||||
|
||||
m_instruction.src[0].field = getOperandField(src0);
|
||||
m_instruction.src[0].code = src0;
|
||||
m_instruction.src[1].field = GcnOperandField::VectorGPR;
|
||||
m_instruction.src[1].code = vdst;
|
||||
}
|
||||
|
||||
void GcnDecodeContext::decodeInstructionVOPC(uint32_t hexInstruction)
|
||||
{
|
||||
uint32_t src0 = bit::extract(hexInstruction, 8, 0);
|
||||
uint32_t vsrc1 = bit::extract(hexInstruction, 16, 9);
|
||||
uint32_t op = bit::extract(hexInstruction, 24, 17);
|
||||
|
||||
m_instruction.opcode = static_cast<GcnOpcode>(op + static_cast<uint32_t>(GcnOpcodeMap::OP_MAP_VOPC));
|
||||
|
||||
m_instruction.src[0].field = getOperandField(src0);
|
||||
m_instruction.src[0].code = src0;
|
||||
m_instruction.src[1].field = GcnOperandField::VectorGPR;
|
||||
m_instruction.src[1].code = vsrc1;
|
||||
}
|
||||
|
||||
void GcnDecodeContext::decodeInstructionVOP2(uint32_t hexInstruction)
|
||||
{
|
||||
uint32_t src0 = bit::extract(hexInstruction, 8, 0);
|
||||
uint32_t vsrc1 = bit::extract(hexInstruction, 16, 9);
|
||||
uint32_t vdst = bit::extract(hexInstruction, 24, 17);
|
||||
uint32_t op = bit::extract(hexInstruction, 30, 25);
|
||||
|
||||
m_instruction.opcode = static_cast<GcnOpcode>(op + static_cast<uint32_t>(GcnOpcodeMap::OP_MAP_VOP2));
|
||||
|
||||
m_instruction.src[0].field = getOperandField(src0);
|
||||
m_instruction.src[0].code = src0;
|
||||
m_instruction.src[1].field = GcnOperandField::VectorGPR;
|
||||
m_instruction.src[1].code = vsrc1;
|
||||
m_instruction.dst[0].field = GcnOperandField::VectorGPR;
|
||||
m_instruction.dst[0].code = vdst;
|
||||
m_instruction.dstCount = 1;
|
||||
}
|
||||
|
||||
void GcnDecodeContext::decodeInstructionSMRD(uint32_t hexInstruction)
|
||||
{
|
||||
uint32_t sbase = bit::extract(hexInstruction, 14, 9);
|
||||
uint32_t sdst = bit::extract(hexInstruction, 21, 15);
|
||||
uint32_t op = bit::extract(hexInstruction, 26, 22);
|
||||
|
||||
m_instruction.opcode = static_cast<GcnOpcode>(op + static_cast<uint32_t>(GcnOpcodeMap::OP_MAP_SMRD));
|
||||
|
||||
m_instruction.src[0].field = GcnOperandField::ScalarGPR;
|
||||
m_instruction.src[0].code = sbase;
|
||||
m_instruction.dst[0].field = GcnOperandField::ScalarGPR;
|
||||
m_instruction.dst[0].code = sdst;
|
||||
m_instruction.dstCount = 1;
|
||||
|
||||
m_instruction.control.smrd = *reinterpret_cast<GcnInstControlSMRD*>(&hexInstruction);
|
||||
|
||||
if (op <= static_cast<uint32_t>(GcnOpcodeSMRD::S_LOAD_DWORDX16))
|
||||
{
|
||||
m_instruction.control.smrd.count = 1 << op;
|
||||
}
|
||||
else if (op >= static_cast<uint32_t>(GcnOpcodeSMRD::S_BUFFER_LOAD_DWORD) &&
|
||||
op <= static_cast<uint32_t>(GcnOpcodeSMRD::S_BUFFER_LOAD_DWORDX16))
|
||||
{
|
||||
m_instruction.control.smrd.count = 1 << (op - 8);
|
||||
}
|
||||
}
|
||||
|
||||
void GcnDecodeContext::decodeInstructionVINTRP(uint32_t hexInstruction)
|
||||
{
|
||||
uint32_t vsrc = bit::extract(hexInstruction, 7, 0);
|
||||
uint32_t op = bit::extract(hexInstruction, 17, 16);
|
||||
uint32_t vdst = bit::extract(hexInstruction, 25, 18);
|
||||
|
||||
m_instruction.opcode = static_cast<GcnOpcode>(op + static_cast<uint32_t>(GcnOpcodeMap::OP_MAP_VINTRP));
|
||||
|
||||
m_instruction.src[0].field = GcnOperandField::VectorGPR;
|
||||
m_instruction.src[0].code = vsrc;
|
||||
m_instruction.dst[0].field = GcnOperandField::VectorGPR;
|
||||
m_instruction.dst[0].code = vdst;
|
||||
m_instruction.dstCount = 1;
|
||||
|
||||
m_instruction.control.vintrp = *reinterpret_cast<GcnInstControlVINTRP*>(&hexInstruction);
|
||||
}
|
||||
|
||||
void GcnDecodeContext::decodeInstructionVOP3(uint64_t hexInstruction)
|
||||
{
|
||||
uint32_t vdst = bit::extract(hexInstruction, 7, 0);
|
||||
uint32_t sdst = bit::extract(hexInstruction, 14, 8); // For VOP3B
|
||||
uint32_t op = bit::extract(hexInstruction, 25, 17);
|
||||
uint32_t src0 = bit::extract(hexInstruction, 40, 32);
|
||||
uint32_t src1 = bit::extract(hexInstruction, 49, 41);
|
||||
uint32_t src2 = bit::extract(hexInstruction, 58, 50);
|
||||
|
||||
if (op >= static_cast<uint32_t>(GcnOpcodeVOP3::V_CMP_F_F32) &&
|
||||
op <= static_cast<uint32_t>(GcnOpcodeVOP3::V_CMPX_T_U64))
|
||||
{
|
||||
// Map from VOP3 to VOPC
|
||||
uint32_t vopcOp = op - static_cast<uint32_t>(GcnOpMapVOP3VOPX::VOP3_TO_VOPC);
|
||||
m_instruction.opcode = static_cast<GcnOpcode>(vopcOp + static_cast<uint32_t>(GcnOpcodeMap::OP_MAP_VOPC));
|
||||
}
|
||||
else if (op >= static_cast<uint32_t>(GcnOpcodeVOP3::V_CNDMASK_B32) &&
|
||||
op <= static_cast<uint32_t>(GcnOpcodeVOP3::V_CVT_PK_I16_I32))
|
||||
{
|
||||
// Map from VOP3 to VOP2
|
||||
uint32_t vop2Op = op - static_cast<uint32_t>(GcnOpMapVOP3VOPX::VOP3_TO_VOP2);
|
||||
m_instruction.opcode = static_cast<GcnOpcode>(vop2Op + static_cast<uint32_t>(GcnOpcodeMap::OP_MAP_VOP2));
|
||||
}
|
||||
else if (op >= static_cast<uint32_t>(GcnOpcodeVOP3::V_NOP) &&
|
||||
op <= static_cast<uint32_t>(GcnOpcodeVOP3::V_MOVRELSD_B32))
|
||||
{
|
||||
// Map from VOP3 to VOP1
|
||||
uint32_t vop1Op = op - static_cast<uint32_t>(GcnOpMapVOP3VOPX::VOP3_TO_VOP1);
|
||||
m_instruction.opcode = static_cast<GcnOpcode>(vop1Op + static_cast<uint32_t>(GcnOpcodeMap::OP_MAP_VOP1));
|
||||
}
|
||||
else
|
||||
{
|
||||
// VOP3 encoding, do not map.
|
||||
m_instruction.opcode = static_cast<GcnOpcode>(op + static_cast<uint32_t>(GcnOpcodeMap::OP_MAP_VOP3));
|
||||
}
|
||||
|
||||
m_instruction.src[0].field = getOperandField(src0);
|
||||
m_instruction.src[0].code = src0;
|
||||
m_instruction.src[1].field = getOperandField(src1);
|
||||
m_instruction.src[1].code = src1;
|
||||
m_instruction.src[2].field = getOperandField(src2);
|
||||
m_instruction.src[2].code = src2;
|
||||
m_instruction.dst[0].field = GcnOperandField::VectorGPR;
|
||||
m_instruction.dst[0].code = vdst;
|
||||
m_instruction.dst[1].field = GcnOperandField::ScalarGPR;
|
||||
m_instruction.dst[1].code = sdst;
|
||||
|
||||
if (op >= static_cast<uint32_t>(GcnOpcodeVOP3::V_ADD_I32) &&
|
||||
op <= static_cast<uint32_t>(GcnOpcodeVOP3::V_DIV_SCALE_F64))
|
||||
{
|
||||
// VOP3B has a sdst operand.
|
||||
m_instruction.dstCount = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_instruction.dstCount = 1;
|
||||
}
|
||||
|
||||
m_instruction.control.vop3 = *reinterpret_cast<GcnInstControlVOP3*>(&hexInstruction);
|
||||
}
|
||||
|
||||
void GcnDecodeContext::decodeInstructionMUBUF(uint64_t hexInstruction)
|
||||
{
|
||||
uint32_t op = bit::extract(hexInstruction, 24, 18);
|
||||
uint32_t vaddr = bit::extract(hexInstruction, 39, 32);
|
||||
uint32_t vdata = bit::extract(hexInstruction, 47, 40);
|
||||
uint32_t srsrc = bit::extract(hexInstruction, 52, 48);
|
||||
uint32_t soffset = bit::extract(hexInstruction, 63, 56);
|
||||
|
||||
m_instruction.opcode = static_cast<GcnOpcode>(op + static_cast<uint32_t>(GcnOpcodeMap::OP_MAP_MUBUF));
|
||||
|
||||
m_instruction.src[0].field = GcnOperandField::VectorGPR;
|
||||
m_instruction.src[0].code = vaddr;
|
||||
m_instruction.src[1].field = GcnOperandField::VectorGPR;
|
||||
m_instruction.src[1].code = vdata;
|
||||
m_instruction.src[2].field = GcnOperandField::ScalarGPR;
|
||||
m_instruction.src[2].code = srsrc;
|
||||
m_instruction.src[3].field = GcnOperandField::ScalarGPR;
|
||||
m_instruction.src[3].code = soffset;
|
||||
|
||||
m_instruction.control.mubuf = *reinterpret_cast<GcnInstControlMUBUF*>(&hexInstruction);
|
||||
|
||||
if (op >= static_cast<uint32_t>(GcnOpcodeMUBUF::BUFFER_LOAD_FORMAT_X) &&
|
||||
op <= static_cast<uint32_t>(GcnOpcodeMUBUF::BUFFER_LOAD_FORMAT_XYZW))
|
||||
{
|
||||
m_instruction.control.mubuf.count = op + 1;
|
||||
}
|
||||
else if (op >= static_cast<uint32_t>(GcnOpcodeMUBUF::BUFFER_STORE_FORMAT_X) &&
|
||||
op <= static_cast<uint32_t>(GcnOpcodeMUBUF::BUFFER_STORE_FORMAT_XYZW))
|
||||
{
|
||||
m_instruction.control.mubuf.count = op - 3;
|
||||
}
|
||||
else if (op >= static_cast<uint32_t>(GcnOpcodeMUBUF::BUFFER_LOAD_DWORD) &&
|
||||
op <= static_cast<uint32_t>(GcnOpcodeMUBUF::BUFFER_LOAD_DWORDX4))
|
||||
{
|
||||
m_instruction.control.mubuf.count = 1 << (op - 12);
|
||||
}
|
||||
else if (op >= static_cast<uint32_t>(GcnOpcodeMUBUF::BUFFER_STORE_DWORD) &&
|
||||
op <= static_cast<uint32_t>(GcnOpcodeMUBUF::BUFFER_STORE_DWORDX4))
|
||||
{
|
||||
m_instruction.control.mubuf.count = 1 << (op - 28);
|
||||
}
|
||||
}
|
||||
|
||||
void GcnDecodeContext::decodeInstructionMTBUF(uint64_t hexInstruction)
|
||||
{
|
||||
uint32_t op = bit::extract(hexInstruction, 18, 16);
|
||||
uint32_t vaddr = bit::extract(hexInstruction, 39, 32);
|
||||
uint32_t vdata = bit::extract(hexInstruction, 47, 40);
|
||||
uint32_t srsrc = bit::extract(hexInstruction, 52, 48);
|
||||
uint32_t soffset = bit::extract(hexInstruction, 63, 56);
|
||||
|
||||
m_instruction.opcode = static_cast<GcnOpcode>(op + static_cast<uint32_t>(GcnOpcodeMap::OP_MAP_MTBUF));
|
||||
|
||||
m_instruction.src[0].field = GcnOperandField::VectorGPR;
|
||||
m_instruction.src[0].code = vaddr;
|
||||
m_instruction.src[1].field = GcnOperandField::VectorGPR;
|
||||
m_instruction.src[1].code = vdata;
|
||||
m_instruction.src[2].field = GcnOperandField::ScalarGPR;
|
||||
m_instruction.src[2].code = srsrc;
|
||||
m_instruction.src[3].field = GcnOperandField::ScalarGPR;
|
||||
m_instruction.src[3].code = soffset;
|
||||
|
||||
m_instruction.control.mtbuf = *reinterpret_cast<GcnInstControlMTBUF*>(&hexInstruction);
|
||||
|
||||
if (op >= static_cast<uint32_t>(GcnOpcodeMTBUF::TBUFFER_LOAD_FORMAT_X) &&
|
||||
op <= static_cast<uint32_t>(GcnOpcodeMTBUF::TBUFFER_LOAD_FORMAT_XYZW))
|
||||
{
|
||||
m_instruction.control.mtbuf.count = op + 1;
|
||||
}
|
||||
else if (op >= static_cast<uint32_t>(GcnOpcodeMTBUF::TBUFFER_STORE_FORMAT_X) &&
|
||||
op <= static_cast<uint32_t>(GcnOpcodeMTBUF::TBUFFER_STORE_FORMAT_XYZW))
|
||||
{
|
||||
m_instruction.control.mtbuf.count = op - 3;
|
||||
}
|
||||
}
|
||||
|
||||
void GcnDecodeContext::decodeInstructionMIMG(uint64_t hexInstruction)
|
||||
{
|
||||
uint32_t op = bit::extract(hexInstruction, 24, 18);
|
||||
uint32_t vaddr = bit::extract(hexInstruction, 39, 32);
|
||||
uint32_t vdata = bit::extract(hexInstruction, 47, 40);
|
||||
uint32_t srsrc = bit::extract(hexInstruction, 52, 48);
|
||||
uint32_t ssamp = bit::extract(hexInstruction, 57, 53);
|
||||
|
||||
m_instruction.opcode = static_cast<GcnOpcode>(op + static_cast<uint32_t>(GcnOpcodeMap::OP_MAP_MIMG));
|
||||
|
||||
m_instruction.src[0].field = GcnOperandField::VectorGPR;
|
||||
m_instruction.src[0].code = vaddr;
|
||||
m_instruction.src[1].field = GcnOperandField::VectorGPR;
|
||||
m_instruction.src[1].code = vdata;
|
||||
m_instruction.src[2].field = GcnOperandField::ScalarGPR;
|
||||
m_instruction.src[2].code = srsrc;
|
||||
m_instruction.src[3].field = GcnOperandField::ScalarGPR;
|
||||
m_instruction.src[3].code = ssamp;
|
||||
|
||||
m_instruction.control.mimg = *reinterpret_cast<GcnInstControlMIMG*>(&hexInstruction);
|
||||
}
|
||||
|
||||
void GcnDecodeContext::decodeInstructionDS(uint64_t hexInstruction)
|
||||
{
|
||||
uint32_t op = bit::extract(hexInstruction, 25, 18);
|
||||
uint32_t addr = bit::extract(hexInstruction, 39, 32);
|
||||
uint32_t data0 = bit::extract(hexInstruction, 47, 40);
|
||||
uint32_t data1 = bit::extract(hexInstruction, 55, 48);
|
||||
uint32_t vdst = bit::extract(hexInstruction, 63, 56);
|
||||
|
||||
m_instruction.opcode = static_cast<GcnOpcode>(op + static_cast<uint32_t>(GcnOpcodeMap::OP_MAP_DS));
|
||||
|
||||
m_instruction.src[0].field = GcnOperandField::VectorGPR;
|
||||
m_instruction.src[0].code = addr;
|
||||
m_instruction.src[1].field = GcnOperandField::VectorGPR;
|
||||
m_instruction.src[1].code = data0;
|
||||
m_instruction.src[2].field = GcnOperandField::VectorGPR;
|
||||
m_instruction.src[2].code = data1;
|
||||
m_instruction.dst[0].field = GcnOperandField::VectorGPR;
|
||||
m_instruction.dst[0].code = vdst;
|
||||
m_instruction.dstCount = 1;
|
||||
|
||||
m_instruction.control.ds = *reinterpret_cast<GcnInstControlDS*>(&hexInstruction);
|
||||
}
|
||||
|
||||
void GcnDecodeContext::decodeInstructionEXP(uint64_t hexInstruction)
|
||||
{
|
||||
uint32_t vsrc0 = bit::extract(hexInstruction, 39, 32);
|
||||
uint32_t vsrc1 = bit::extract(hexInstruction, 47, 40);
|
||||
uint32_t vsrc2 = bit::extract(hexInstruction, 55, 48);
|
||||
uint32_t vsrc3 = bit::extract(hexInstruction, 63, 56);
|
||||
|
||||
m_instruction.opcode = GcnOpcode::EXP;
|
||||
|
||||
m_instruction.src[0].field = GcnOperandField::VectorGPR;
|
||||
m_instruction.src[0].code = vsrc0;
|
||||
m_instruction.src[1].field = GcnOperandField::VectorGPR;
|
||||
m_instruction.src[1].code = vsrc1;
|
||||
m_instruction.src[2].field = GcnOperandField::VectorGPR;
|
||||
m_instruction.src[2].code = vsrc2;
|
||||
m_instruction.src[3].field = GcnOperandField::VectorGPR;
|
||||
m_instruction.src[3].code = vsrc3;
|
||||
|
||||
m_instruction.control.exp = *reinterpret_cast<GcnInstControlEXP*>(&hexInstruction);
|
||||
}
|
||||
|
||||
} // namespace sce::gcn
|
97
GPCS4/Graphics/Gcn/GcnDecoder.h
Normal file
97
GPCS4/Graphics/Gcn/GcnDecoder.h
Normal file
|
@ -0,0 +1,97 @@
|
|||
#pragma once
|
||||
|
||||
#include "GcnInstruction.h"
|
||||
|
||||
namespace sce::gcn
|
||||
{
|
||||
|
||||
class GcnCodeSlice
|
||||
{
|
||||
|
||||
public:
|
||||
GcnCodeSlice(
|
||||
const uint32_t* ptr,
|
||||
const uint32_t* end) :
|
||||
m_ptr(ptr),
|
||||
m_end(end)
|
||||
{
|
||||
}
|
||||
|
||||
uint32_t at(uint32_t id) const;
|
||||
|
||||
uint32_t readu32();
|
||||
uint64_t readu64();
|
||||
|
||||
bool atEnd() const
|
||||
{
|
||||
return m_ptr == m_end;
|
||||
}
|
||||
|
||||
private:
|
||||
const uint32_t* m_ptr = nullptr;
|
||||
const uint32_t* m_end = nullptr;
|
||||
};
|
||||
|
||||
class GcnDecodeContext
|
||||
{
|
||||
enum GcnOperandFieldRange
|
||||
{
|
||||
ScalarGPRMin = 0,
|
||||
ScalarGPRMax = 103,
|
||||
SignedConstIntPosMin = 129,
|
||||
SignedConstIntPosMax = 192,
|
||||
SignedConstIntNegMin = 193,
|
||||
SignedConstIntNegMax = 208,
|
||||
VectorGPRMin = 256,
|
||||
VectorGPRMax = 511
|
||||
};
|
||||
|
||||
public:
|
||||
GcnDecodeContext();
|
||||
~GcnDecodeContext();
|
||||
|
||||
const GcnShaderInstruction& getInstruction() const
|
||||
{
|
||||
return m_instruction;
|
||||
}
|
||||
|
||||
void decodeInstruction(GcnCodeSlice& code);
|
||||
|
||||
private:
|
||||
GcnInstEncoding getInstructionEncoding(uint32_t token);
|
||||
uint32_t getEncodingLength(GcnInstEncoding encoding);
|
||||
uint32_t getOpMapOffset(GcnInstEncoding encoding);
|
||||
uint32_t mapEncodingOp(GcnInstEncoding encoding, GcnOpcode opcode);
|
||||
bool hasAdditionalLiteral(GcnInstEncoding encoding, uint32_t opcode);
|
||||
void updateInstructionMeta(GcnInstEncoding encoding);
|
||||
|
||||
GcnOperandField getOperandField(uint32_t code);
|
||||
|
||||
void decodeInstruction32(GcnInstEncoding encoding, GcnCodeSlice& code);
|
||||
void decodeInstruction64(GcnInstEncoding encoding, GcnCodeSlice& code);
|
||||
void decodeLiteralConstant(GcnInstEncoding encoding, GcnCodeSlice& code);
|
||||
|
||||
// 32 bits encodings
|
||||
void decodeInstructionSOP1(uint32_t hexInstruction);
|
||||
void decodeInstructionSOPP(uint32_t hexInstruction);
|
||||
void decodeInstructionSOPC(uint32_t hexInstruction);
|
||||
void decodeInstructionSOPK(uint32_t hexInstruction);
|
||||
void decodeInstructionSOP2(uint32_t hexInstruction);
|
||||
void decodeInstructionVOP1(uint32_t hexInstruction);
|
||||
void decodeInstructionVOPC(uint32_t hexInstruction);
|
||||
void decodeInstructionVOP2(uint32_t hexInstruction);
|
||||
void decodeInstructionSMRD(uint32_t hexInstruction);
|
||||
void decodeInstructionVINTRP(uint32_t hexInstruction);
|
||||
// 64 bits encodings
|
||||
void decodeInstructionVOP3(uint64_t hexInstruction);
|
||||
void decodeInstructionMUBUF(uint64_t hexInstruction);
|
||||
void decodeInstructionMTBUF(uint64_t hexInstruction);
|
||||
void decodeInstructionMIMG(uint64_t hexInstruction);
|
||||
void decodeInstructionDS(uint64_t hexInstruction);
|
||||
void decodeInstructionEXP(uint64_t hexInstruction);
|
||||
|
||||
private:
|
||||
GcnShaderInstruction m_instruction;
|
||||
};
|
||||
|
||||
} // namespace sce::gcn
|
2412
GPCS4/Graphics/Gcn/GcnEnum.h
Normal file
2412
GPCS4/Graphics/Gcn/GcnEnum.h
Normal file
File diff suppressed because it is too large
Load diff
|
@ -1,18 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
namespace sce::gcn
|
||||
{
|
||||
|
||||
enum class PsslProgramType
|
||||
{
|
||||
PixelShader = 0,
|
||||
VertexShader = 1,
|
||||
GeometryShader = 2,
|
||||
HullShader = 3,
|
||||
DomainShader = 4,
|
||||
ComputeShader = 5,
|
||||
FetchShader = 6,
|
||||
ShaderTypeCount
|
||||
};
|
||||
|
||||
} // namespace sce::gcn
|
3899
GPCS4/Graphics/Gcn/GcnInstruction.cpp
Normal file
3899
GPCS4/Graphics/Gcn/GcnInstruction.cpp
Normal file
File diff suppressed because it is too large
Load diff
168
GPCS4/Graphics/Gcn/GcnInstruction.h
Normal file
168
GPCS4/Graphics/Gcn/GcnInstruction.h
Normal file
|
@ -0,0 +1,168 @@
|
|||
#pragma once
|
||||
|
||||
#include "GcnEnum.h"
|
||||
|
||||
namespace sce::gcn
|
||||
{
|
||||
|
||||
constexpr uint32_t GcnMaxSrcCount = 4;
|
||||
constexpr uint32_t GcnMaxDstCount = 2;
|
||||
|
||||
struct GcnInstFormat
|
||||
{
|
||||
// Instruction class
|
||||
GcnInstClass instructionClass = GcnInstClass::Undefined;
|
||||
|
||||
uint32_t srcCount = 0;
|
||||
uint32_t dstCount = 0;
|
||||
|
||||
GcnNumericType srcType = GcnNumericType::Undefined;
|
||||
GcnNumericType dstType = GcnNumericType::Undefined;
|
||||
};
|
||||
|
||||
struct GcnInstOperand
|
||||
{
|
||||
GcnOperandField field = GcnOperandField::Undefined;
|
||||
GcnNumericType numericType = GcnNumericType::Undefined;
|
||||
union
|
||||
{
|
||||
uint32_t code = 0xFFFFFFFF;
|
||||
uint32_t literalConst;
|
||||
};
|
||||
};
|
||||
|
||||
struct GcnInstControlSOPK
|
||||
{
|
||||
uint32_t simm : 16;
|
||||
uint32_t : 16;
|
||||
};
|
||||
|
||||
struct GcnInstControlSOPP
|
||||
{
|
||||
uint32_t simm : 16;
|
||||
uint32_t : 16;
|
||||
};
|
||||
|
||||
struct GcnInstControlVOP3
|
||||
{
|
||||
uint64_t : 8;
|
||||
uint64_t abs : 3;
|
||||
uint64_t clmp : 1;
|
||||
uint64_t : 47;
|
||||
uint64_t omod : 2;
|
||||
uint64_t neg : 3;
|
||||
};
|
||||
|
||||
struct GcnInstControlSMRD
|
||||
{
|
||||
uint32_t offset : 8;
|
||||
uint32_t imm : 1;
|
||||
uint32_t count : 5;
|
||||
uint32_t : 18;
|
||||
};
|
||||
|
||||
struct GcnInstControlMUBUF
|
||||
{
|
||||
uint64_t offset : 12;
|
||||
uint64_t offen : 1;
|
||||
uint64_t idxen : 1;
|
||||
uint64_t glc : 1;
|
||||
uint64_t : 1;
|
||||
uint64_t lds : 1;
|
||||
uint64_t : 37;
|
||||
uint64_t slc : 1;
|
||||
uint64_t tfe : 1;
|
||||
uint64_t count : 3;
|
||||
uint64_t : 5;
|
||||
};
|
||||
|
||||
struct GcnInstControlMTBUF
|
||||
{
|
||||
uint64_t offset : 12;
|
||||
uint64_t offen : 1;
|
||||
uint64_t idxen : 1;
|
||||
uint64_t glc : 1;
|
||||
uint64_t : 4;
|
||||
uint64_t dfmt : 4;
|
||||
uint64_t nfmt : 3;
|
||||
uint64_t : 28;
|
||||
uint64_t slc : 1;
|
||||
uint64_t tfe : 1;
|
||||
uint64_t count : 3;
|
||||
uint64_t : 5;
|
||||
};
|
||||
|
||||
struct GcnInstControlMIMG
|
||||
{
|
||||
uint64_t : 8;
|
||||
uint64_t dmask : 4;
|
||||
uint64_t unrm : 1;
|
||||
uint64_t glc : 1;
|
||||
uint64_t da : 1;
|
||||
uint64_t r128 : 1;
|
||||
uint64_t tfe : 1;
|
||||
uint64_t lwe : 1;
|
||||
uint64_t : 7;
|
||||
uint64_t slc : 1;
|
||||
uint64_t : 38;
|
||||
};
|
||||
|
||||
struct GcnInstControlDS
|
||||
{
|
||||
uint64_t offset0 : 8;
|
||||
uint64_t offset1 : 8;
|
||||
uint64_t : 1;
|
||||
uint64_t gds : 1;
|
||||
uint64_t : 46;
|
||||
};
|
||||
|
||||
struct GcnInstControlVINTRP
|
||||
{
|
||||
uint32_t : 8;
|
||||
uint32_t chan : 2;
|
||||
uint32_t attr : 6;
|
||||
uint32_t : 16;
|
||||
};
|
||||
|
||||
struct GcnInstControlEXP
|
||||
{
|
||||
uint64_t en : 4;
|
||||
uint64_t target : 6;
|
||||
uint64_t compr : 1;
|
||||
uint64_t done : 1;
|
||||
uint64_t vm : 1;
|
||||
uint64_t reserved : 51;
|
||||
};
|
||||
|
||||
union GcnInstControl
|
||||
{
|
||||
GcnInstControlSOPK sopk;
|
||||
GcnInstControlSOPP sopp;
|
||||
GcnInstControlVOP3 vop3;
|
||||
GcnInstControlSMRD smrd;
|
||||
GcnInstControlMUBUF mubuf;
|
||||
GcnInstControlMTBUF mtbuf;
|
||||
GcnInstControlMIMG mimg;
|
||||
GcnInstControlDS ds;
|
||||
GcnInstControlVINTRP vintrp;
|
||||
GcnInstControlEXP exp;
|
||||
};
|
||||
|
||||
struct GcnShaderInstruction
|
||||
{
|
||||
GcnOpcode opcode;
|
||||
uint32_t length; // in bytes
|
||||
GcnInstEncoding encoding;
|
||||
GcnInstClass opClass;
|
||||
GcnInstControl control;
|
||||
|
||||
uint32_t srcCount;
|
||||
uint32_t dstCount;
|
||||
|
||||
GcnInstOperand src[GcnMaxSrcCount];
|
||||
GcnInstOperand dst[GcnMaxDstCount];
|
||||
};
|
||||
|
||||
GcnInstFormat gcnInstructionFormat(GcnInstEncoding encoding, uint32_t opcode);
|
||||
|
||||
} // namespace sce::gcn
|
1302
Tools/GCNInstructionDefs.cpp
Normal file
1302
Tools/GCNInstructionDefs.cpp
Normal file
File diff suppressed because it is too large
Load diff
3150
Tools/GCNInstructions.cpp
Normal file
3150
Tools/GCNInstructions.cpp
Normal file
File diff suppressed because it is too large
Load diff
264
Tools/GCNInternals.h
Normal file
264
Tools/GCNInternals.h
Normal file
|
@ -0,0 +1,264 @@
|
|||
/*
|
||||
* CLRadeonExtender - Unofficial OpenCL Radeon Extensions Library
|
||||
* Copyright (C) 2014-2018 Mateusz Szpakowski
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef __CLRX_GCNINTERNALS_H__
|
||||
#define __CLRX_GCNINTERNALS_H__
|
||||
|
||||
#include <CLRX/Config.h>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <CLRX/utils/Utilities.h>
|
||||
#include <CLRX/utils/GPUId.h>
|
||||
|
||||
namespace CLRX
|
||||
{
|
||||
|
||||
// enums for GCN encodings
|
||||
enum : cxbyte
|
||||
{
|
||||
GCNENC_NONE,
|
||||
GCNENC_SOPC, /* 0x17e<<23, opcode = (7bit)<<16 */
|
||||
GCNENC_SOPP, /* 0x17f<<23, opcode = (7bit)<<16 */
|
||||
GCNENC_SOP1, /* 0x17d<<23, opcode = (8bit)<<8 */
|
||||
GCNENC_SOP2, /* 0x2<<30, opcode = (7bit)<<23 */
|
||||
GCNENC_SOPK, /* 0xb<<28, opcode = (5bit)<<23 */
|
||||
GCNENC_SMRD, /* 0x18<<27, opcode = (6bit)<<22 */
|
||||
GCNENC_SMEM = GCNENC_SMRD, /* 0x18<<27, opcode = (6bit)<<22 */
|
||||
GCNENC_VOPC, /* 0x3e<<25, opcode = (8bit)<<17 */
|
||||
GCNENC_VOP1, /* 0x3f<<25, opcode = (8bit)<<9 */
|
||||
GCNENC_VOP2, /* 0x0<<31, opcode = (6bit)<<25 */
|
||||
GCNENC_VOP3A, /* 0x34<<26, opcode = (9bit)<<17 */
|
||||
GCNENC_VOP3B, /* 0x34<<26, opcode = (9bit)<<17 */
|
||||
GCNENC_VINTRP, /* 0x32<<26, opcode = (2bit)<<16 */
|
||||
GCNENC_DS, /* 0x36<<26, opcode = (8bit)<<18 */
|
||||
GCNENC_MUBUF, /* 0x38<<26, opcode = (7bit)<<18 */
|
||||
GCNENC_MTBUF, /* 0x3a<<26, opcode = (3bit)<<16 */
|
||||
GCNENC_MIMG, /* 0x3c<<26, opcode = (7bit)<<18 */
|
||||
GCNENC_EXP, /* 0x3e<<26, opcode = none */
|
||||
GCNENC_FLAT, /* 0x37<<26, opcode = (8bit)<<18 (???8bit) */
|
||||
GCNENC_VOP3P,
|
||||
GCNENC_MAXVAL = GCNENC_FLAT
|
||||
};
|
||||
|
||||
|
||||
typedef uint32_t GCNInsnMode;
|
||||
|
||||
// modes for GCN instructions
|
||||
enum : GCNInsnMode
|
||||
{
|
||||
GCN_STDMODE = 0, /// standard mode
|
||||
GCN_REG_ALL_64 = 15, /// all register operand is 64-bit
|
||||
GCN_REG_DST_64 = 1, /// destination is 64-bit
|
||||
GCN_REG_SRC0_64 = 2, /// source0 is 64-bit
|
||||
GCN_REG_SRC1_64 = 4, /// source1 is 64-bit
|
||||
GCN_REG_SRC2_64 = 8, /// source2 is 64-bit
|
||||
GCN_REG_DS0_64 = 3, /// destination and source0 is 64-bit
|
||||
GCN_REG_DS1_64 = 5, /// destination and source1 is 64-bit
|
||||
GCN_REG_DS2_64 = 9, /// destination and source2 is 64-bit
|
||||
/* SOP */
|
||||
GCN_IMM_NONE = 0x10, // used in Scall insns
|
||||
GCN_ARG_NONE = 0x20, /// no arguments (operands)
|
||||
GCN_DST_NONE = 0x20, /// omit destination argument
|
||||
GCN_IMM_REL = 0x30, /// SOPK, immediate as relative address
|
||||
GCN_IMM_LOCKS = 0x40, /// SOPK, s_waitcnt locks
|
||||
GCN_IMM_MSGS = 0x50, /// SOPK, s_sendmsg* message function
|
||||
GCN_IMM_SREG = 0x60, /// SOPK, hwreg function
|
||||
GCN_SRC_NONE = 0x70, /// SOP1, omit source
|
||||
GCN_DST_SRC = 0x80, /// SOPK, SDST is first source
|
||||
GCN_IMM_DST = 0x100, /// immediate is first (destplace), destination is second
|
||||
GCN_SOPK_CONST = 0x200, /// constant instead destination
|
||||
GCN_SOPK_SRIMM32 = 0x300, /// GCN_IMM_DST and GCN_SOPK_CONST together
|
||||
/* SOPC */
|
||||
GCN_SRC1_IMM = 0x10, /// treat source1 as immediate value
|
||||
/* VOP */
|
||||
GCN_SRC2_NONE = 0x10, /// omit source2
|
||||
GCN_DS2_VCC = 0x20, /// extra sgpr or VCC in extra destination and in source2
|
||||
GCN_SRC12_NONE = 0x30, /// omit source1 and source2
|
||||
GCN_ARG1_IMM = 0x40, /// immediate value as second operand
|
||||
GCN_ARG2_IMM = 0x50, /// immediate value as third operand
|
||||
GCN_S0EQS12 = 0x60, /// source0 must be equal to source1 or source2
|
||||
GCN_DST_VCC = 0x70, /// extra sgpr or VCC in extra destination
|
||||
GCN_SRC2_VCC = 0x80, /// sgpr or VCC in source2
|
||||
GCN_DST_VCC_VSRC2 = 0x90, /// sgpr or VCC as dest operand and source2
|
||||
GCN_DS1_SGPR = 0xa0, /// destination and source1 is SGPR
|
||||
GCN_SRC1_SGPR = 0xb0, /// source1 is SGPR
|
||||
GCN_DST_SGPR = 0xc0, /// destination is SGPR
|
||||
GCN_VOP_ARG_NONE = 0xd0, /// no argument for VOP encodings
|
||||
GCN_NEW_OPCODE = 0xe0, /// unique opcode that doesn't exists in VINTRP
|
||||
GCN_P0_P10_P20 = 0xf0, /// second operand is param (P0,P10,P20)
|
||||
GCN_VOPC_NOVCC = 0x80, /// no VCC in VOPC instruction
|
||||
GCN_VOP3_VOP2 = 0x100, /// VOP2 encoded as VOP3
|
||||
GCN_VOP3_VOP1 = 0x200, /// VOP1 encoded as VOP3
|
||||
GCN_VOP3_VINTRP = 0x300, /// VINTRP encoded as VOP3
|
||||
GCN_VOP3_DS2_128 = 0x7000, /// VOP3 with DST 128 and SRC2 128
|
||||
GCN_VOP3_VINTRP_NEW = 0x3e0, /// new VINTRP instructions encoded as VOP3
|
||||
GCN_VOP3_VOP2_DS01 = 0x110, /// VOP2 in VOP3, destination and two sources
|
||||
GCN_VOP3_VOP1_DS0 = 0x230, /// VOP1 in VOP3, destination and one source
|
||||
GCN_VOP3_DST_SGPR = 0x400, /// VOPX in VOP3, and dst is SGPR (if mask1 used)
|
||||
GCN_VOP3_SRC1_SGPR = 0x800, /// VOPX in VOP3, and src1 is SGPR (if mask1 used)
|
||||
GCN_VOP3_DS1_SGPR = 0xc00, /// VOPX in VOP3, and dst and src1 is SGPR (if mask1 used)
|
||||
GCN_VOP3_MASK2 = 0x8300, // mask for VOPx in VOP2 encodings
|
||||
GCN_VINTRP_SRC2 = 0x1000, /// VOP3/VINTRP with source2 (third source)
|
||||
GCN_VOP3_MASK3 = 0x3000, /// mask for VINTRP in VOP2 encodings
|
||||
GCN_VOP3_VOP3P = 0x8000, /// VOP3P encoding
|
||||
GCN_VOP3_NODST = 0x1000000, /// VOP3 - no DST
|
||||
GCN_VOP_NODPP = 0x10000, /// VOP instruction can not have DPP
|
||||
GCN_VOP_NOSDWA = 0x20000, /// VOP instruction can not have SDWA
|
||||
GCN_VOP_NODPPSDWA = 0x30000, /// VOP instruction can not have DPP and SDWA
|
||||
GCN_VOP_NOSDWAVEGA = 0x40000, /// VOP instruction can not have SDWA for VEGA
|
||||
GCN_VCC_IMPL_READ = 0x80000, /// VOP instruction with implicit VCC read
|
||||
GCN_VCC_IMPL_WRITE = 0x100000, /// VOP instruction with implicit VCC write
|
||||
GCN_VOP_NOWVSZ = 0x200000, // VOP SDST/VCC size doesn't not depend on wavesize
|
||||
// DS encoding modes
|
||||
GCN_ADDR_STD = 0x0, /// standard place of address
|
||||
GCN_ADDR_DST = 0x10, /// address operand in destination place
|
||||
GCN_ADDR_SRC = 0x20, /// address operand in source
|
||||
GCN_ADDR_DST64 = 0x1f, /// address operand in destination place and all is 64-bit
|
||||
GCN_ADDR_SRC64 = 0x2f, /// address operand in source and all is 64-bit
|
||||
GCN_ADDR_SRC_D64 = 0x21, /// address operand in source and dest is bit (not addr)
|
||||
GCN_2OFFSETS = 0x100, /// two 8-bit offsets
|
||||
GCN_VDATA2 = 0x140, /* two datas, two offsets */
|
||||
GCN_NOSRC = 0x80, /* only address, no source */
|
||||
GCN_2SRCS = 0x40, // two (source or dest) datas (DATA), DATA1)
|
||||
GCN_NOSRC_2OFF = 0x180, /* only address */
|
||||
GCN_SRC_ADDR2 = 0x200, /// for ds_XXX_src2_XXX instructions
|
||||
GCN_SRC_ADDR2_64 = 0x20f, /// for ds_XXX_src2_XXX instructions, all is 64-bit
|
||||
GCN_DS_96 = 0x800, /// 96-bit dest and source
|
||||
GCN_DS_128 = 0x1000, /// 128-bit dest and source
|
||||
GCN_ONLYDST = 0x400, /* only vdst */
|
||||
GCN_DSMASK = 0x3f0, // mask for DS encoding
|
||||
GCN_DSMASK2 = 0x3c0, // mask for DS encoding 2
|
||||
GCN_SRCS_MASK = 0xc0, /// only srcs mask
|
||||
GCN_ONLYGDS = 0x2000, /// instruction must have GDS
|
||||
GCN_DST128 = 0x4000, // dest is 128-bit
|
||||
GCN_ONLY_SRC = 0x8000,
|
||||
// others
|
||||
GCN_SBASE4 = 0x10, /// SBASE requires 4 registers
|
||||
GCN_FLOATLIT = 0x40000000U, /// float literal
|
||||
GCN_F16LIT = 0x80000000U, /// half literal
|
||||
GCN_LITMASK = 0xc0000000U,
|
||||
GCN_SMRD_ONLYDST = 0x30, // only destination (no other operands)
|
||||
GCN_SMEM_SDATA_IMM = 0x40, // treat SDATA as immediate
|
||||
GCN_SMEM_NOSDATA = 0x80, // no destination
|
||||
GCN_MEMOP_MX1 = 0x0, /// sdst/sdata requires 1 register
|
||||
GCN_MEMOP_MX2 = 0x100, /// sdst/sdata requires 2 registers
|
||||
GCN_MEMOP_MX4 = 0x200, /// sdst/sdata requires 4 registers
|
||||
GCN_MEMOP_MX8 = 0x300, /// sdst/sdata requires 8 registers
|
||||
GCN_MEMOP_MX16 = 0x400, /// sdst/sdata requires 16 registers
|
||||
GCN_MUBUF_X = 0x0, /// vdata requires 1 register
|
||||
GCN_MUBUF_NOVAD = 0x10, // no vaddr and vdata
|
||||
GCN_MUBUF_XY = 0x100, /// vdata requires 2 registers
|
||||
GCN_MUBUF_XYZ = 0x200, /// vdata requires 3 registers
|
||||
GCN_MUBUF_XYZW = 0x300, /// vdata requires 4 registers
|
||||
GCN_MUBUF_MX1 = 0x0, /// vdata requires 1 register
|
||||
GCN_MUBUF_MX2 = 0x100, /// vdata requires 2 registers
|
||||
GCN_MUBUF_MX3 = 0x200, /// vdata requires 3 registers
|
||||
GCN_MUBUF_MX4 = 0x300, /// vdata requires 4 registers
|
||||
GCN_MUBUF_D16 = 0x800, /// vdata size depends on arch (GCN 1.4 - half of size)
|
||||
GCN_MUBUF_X_D16 = 0x800, /// vdata requires 1 register
|
||||
GCN_MUBUF_XY_D16 = 0x900, /// vdata requires 2 registers (or 1 for GCN 1.4)
|
||||
GCN_MUBUF_XYZ_D16 = 0xa00, /// vdata requires 3 registers (or 2 for GCN 1.4)
|
||||
GCN_MUBUF_XYZW_D16 = 0xb00, /// vdata requires 4 registers (or 2 for GCN 1.4)
|
||||
GCN_MIMG_SAMPLE = 0x100, /// last operand is SSAMP (4 sregisters)
|
||||
GCN_MIMG_VDATA4 = 0x200, /// gather requires 4 vdata registers
|
||||
GCN_MIMG_GATHER = 0x300, /// gather requires 4 vdata registers
|
||||
GCN_MIMG_VAGE1 = 0x0, /// vaddr requires 1 or more registers
|
||||
GCN_MIMG_VAGE2 = 0x1, /// vaddr requires 2 or more registers
|
||||
GCN_MIMG_VAGE3 = 0x2, /// vaddr requires 3 or more registers
|
||||
GCN_MIMG_VAGE4 = 0x3, /// vaddr requires 4 or more registers
|
||||
GCN_MIMG_VAGE5 = 0x4, /// vaddr requires 5 or more registers
|
||||
GCN_MIMG_VAGE6 = 0x5, /// vaddr requires 6 or more registers
|
||||
GCN_MIMG_VADERIV = 0x10, /// vaddr holds user derivatives
|
||||
GCN_MIMG_VAGE2D = 0x11, /// vaddr requires 2 or more registers and holds user derivs
|
||||
GCN_MIMG_VAGE3D = 0x12, /// vaddr requires 3 or more registers and holds user derivs
|
||||
GCN_MIMG_VAGE4D = 0x13, /// vaddr requires 4 or more registers and holds user derivs
|
||||
GCN_MIMG_VAGE5D = 0x14, /// vaddr requires 5 or more registers and holds user derivs
|
||||
GCN_MIMG_VAGE6D = 0x15, /// vaddr requires 6 or more registers and holds user derivs
|
||||
GCN_MIMG_VA_O = 0x20, // vaddr *O*
|
||||
GCN_MIMG_VA_B = 0x40, // vaddr *B*
|
||||
GCN_MIMG_VA_C = 0x80, // vaddr *C*
|
||||
GCN_MIMG_VA_L = 0x400, // vaddr *L*
|
||||
GCN_MIMG_VA_CL = 0x800, // vaddr *CL*
|
||||
GCN_MIMG_VA_B_O = GCN_MIMG_VA_B|GCN_MIMG_VA_O, // vaddr *B* and *O*
|
||||
GCN_MIMG_VA_B_CL = GCN_MIMG_VA_B|GCN_MIMG_VA_CL, // vaddr *B* and *CL*
|
||||
// vaddr *B* and *CL* and *O*
|
||||
GCN_MIMG_VA_B_CL_O = GCN_MIMG_VA_B|GCN_MIMG_VA_CL|GCN_MIMG_VA_O,
|
||||
GCN_MIMG_VA_C_B = GCN_MIMG_VA_C|GCN_MIMG_VA_B, // vaddr *C* and *B*
|
||||
// vaddr *C* and *B* and *CL*
|
||||
GCN_MIMG_VA_C_B_CL = GCN_MIMG_VA_C|GCN_MIMG_VA_B|GCN_MIMG_VA_CL,
|
||||
GCN_MIMG_VA_L_O = GCN_MIMG_VA_L|GCN_MIMG_VA_O, // vaddr *L* anc *O*
|
||||
GCN_MIMG_VA_C_L = GCN_MIMG_VA_C|GCN_MIMG_VA_L, // vaddr *C* and *L*
|
||||
GCN_MIMG_VA_C_CL = GCN_MIMG_VA_C|GCN_MIMG_VA_CL, // vaddr *C* and *CLL*
|
||||
GCN_MIMG_VA_C_O = GCN_MIMG_VA_C|GCN_MIMG_VA_O, // vaddr *C* and *O*
|
||||
GCN_MIMG_VA_CL_O = GCN_MIMG_VA_CL|GCN_MIMG_VA_O, // vaddr *CL* and *O*
|
||||
// vaddr *C* and *CL* and *O*
|
||||
GCN_MIMG_VA_C_CL_O = GCN_MIMG_VA_C|GCN_MIMG_VA_CL|GCN_MIMG_VA_O,
|
||||
// vaddr *C* and *CL* and *B* and *O*
|
||||
GCN_MIMG_VA_C_B_CL_O = GCN_MIMG_VA_C|GCN_MIMG_VA_CL|GCN_MIMG_VA_B|GCN_MIMG_VA_O,
|
||||
// vaddr *C* and *L* and *O*
|
||||
GCN_MIMG_VA_C_L_O = GCN_MIMG_VA_C|GCN_MIMG_VA_L|GCN_MIMG_VA_O,
|
||||
// vaddr *C* and *B* and *O*
|
||||
GCN_MIMG_VA_C_B_O = GCN_MIMG_VA_C|GCN_MIMG_VA_B|GCN_MIMG_VA_O,
|
||||
GCN_MIMG_VA_MIP = 0x10000, // vaddr _MIP
|
||||
GCN_MIMG_VA_MASK = 0xf,
|
||||
GCN_MLOAD = 0x1000, // instruction load data to vgprs
|
||||
GCN_MATOMIC = 0x2000, // instruction perform atomics and returns data if glc==1
|
||||
GCN_MHALFWRITE = 0x4000,
|
||||
GCN_MCMPSWAP = 0x6000,
|
||||
GCN_FLAT_DDST = 0x00, // destination as first operand
|
||||
GCN_FLAT_ADST = 0x10, /// first address, second is DST
|
||||
GCN_FLAT_NODATA = 0x20, /// omit DATA
|
||||
GCN_FLAT_NODST = 0x40, /// omit DST
|
||||
GCN_FLAT_STORE = 0x50, /// store instruction
|
||||
GCN_CMPSWAP = 0x80, /// ???
|
||||
GCN_ACMPSWAP = 0x6080, /// ???
|
||||
GCN_FLAT_FLAT = 0,
|
||||
GCN_FLAT_SCRATCH = 1,
|
||||
GCN_FLAT_GLOBAL = 2,
|
||||
GCN_FLAT_MODEMASK = 7,
|
||||
GCN_MASK1 = 0xf0,
|
||||
GCN_MASK2 = 0xf00,
|
||||
GCN_DSIZE_MASK = 0x700, /// dsize mask
|
||||
GCN_SHIFT2 = 8
|
||||
};
|
||||
|
||||
struct CLRX_INTERNAL GCNInstruction
|
||||
{
|
||||
const char* mnemonic;
|
||||
cxbyte encoding;
|
||||
GCNInsnMode mode;
|
||||
uint16_t code;
|
||||
GPUArchMask archMask; // mask of architectures whose have instruction
|
||||
};
|
||||
|
||||
// version GCNInstruction for assembler (with two code: for VOPX and VOP3)
|
||||
struct CLRX_INTERNAL GCNAsmInstruction
|
||||
{
|
||||
const char* mnemonic;
|
||||
cxbyte encoding;
|
||||
GCNInsnMode mode;
|
||||
uint16_t code1, code2; // code1 - first code, code2 - VOP3 encoding code
|
||||
GPUArchMask archMask; // mask of architectures whose have instruction
|
||||
};
|
||||
|
||||
CLRX_INTERNAL extern const GCNInstruction gcnInstrsTable[];
|
||||
|
||||
};
|
||||
|
||||
#endif
|
344
Tools/ParseOpcode.py
Normal file
344
Tools/ParseOpcode.py
Normal file
|
@ -0,0 +1,344 @@
|
|||
import re
|
||||
|
||||
|
||||
ArchDic = {
|
||||
'ARCH_SOUTHERN_ISLANDS': 1,
|
||||
'ARCH_SEA_ISLANDS': 2,
|
||||
'ARCH_VOLCANIC_ISLANDS': 4,
|
||||
'ARCH_HD7X00': 1,
|
||||
'ARCH_RX2X0': 2,
|
||||
'ARCH_RX3X0': 4,
|
||||
'ARCH_RXVEGA': 8,
|
||||
'ARCH_VEGA20': 16,
|
||||
'ARCH_NAVI': 32,
|
||||
'ARCH_NAVI_DL': 64,
|
||||
'ARCH_GCN_1_0_1': 0x3,
|
||||
'ARCH_GCN_1_1_2': 0x6,
|
||||
'ARCH_GCN_1_1_5': 0x62,
|
||||
'ARCH_GCN_1_1_2_4': 0x1e,
|
||||
'ARCH_GCN_1_0_1_2_4': 0x1f,
|
||||
'ARCH_GCN_1_2_4': 0x1c,
|
||||
'ARCH_GCN_1_4': 0x18,
|
||||
'ARCH_GCN_1_5': 0x60,
|
||||
'ARCH_GCN_1_5_1': 0x40,
|
||||
'ARCH_GCN_1_1_2_4_5': 0x7e,
|
||||
'ARCH_GCN_1_2_4_5': 0x7c,
|
||||
'ARCH_GCN_1_4_5': 0x78,
|
||||
'ARCH_GCN_1_0_1_5': 0x63,
|
||||
'ARCH_GCN_ALL': 0xfff,
|
||||
}
|
||||
|
||||
TypeDic = {
|
||||
'TypeNone' : 'Undefined',
|
||||
'TypeB8' : 'B8',
|
||||
'TypeB16' : 'B16',
|
||||
'TypeB32' : 'B32',
|
||||
'TypeB64' : 'B64',
|
||||
'TypeB96' : 'B96',
|
||||
'TypeB128' : 'B128',
|
||||
'TypeF16' : 'F16',
|
||||
'TypeF32' : 'F32',
|
||||
'TypeF64' : 'F64',
|
||||
'TypeU8' : 'U8',
|
||||
'TypeU16' : 'U16',
|
||||
'TypeU24' : 'U24',
|
||||
'TypeU32' : 'U32',
|
||||
'TypeU64' : 'U64',
|
||||
'TypeI4' : 'I4',
|
||||
'TypeI8' : 'I8',
|
||||
'TypeI16' : 'I16',
|
||||
'TypeI24' : 'I24',
|
||||
'TypeI32' : 'I32',
|
||||
'TypeI64' : 'I64',
|
||||
'TypeF16F32' : 'F16',
|
||||
'TypeF32F16' : 'F32',
|
||||
'TypeF32F64' : 'F32',
|
||||
'TypeF32I32' : 'F32',
|
||||
'TypeF32I4' : 'F32',
|
||||
'TypeF32U32' : 'F32',
|
||||
'TypeF64F32' : 'F64',
|
||||
'TypeF64I32' : 'F64',
|
||||
'TypeF64U32' : 'F64',
|
||||
'TypeI16F32' : 'I16',
|
||||
'TypeI16I32' : 'I16',
|
||||
'TypeI32B32' : 'I32',
|
||||
'TypeI32B64' : 'I32',
|
||||
'TypeI32F32' : 'I32',
|
||||
'TypeI32F64' : 'I32',
|
||||
'TypeI32I16' : 'I32',
|
||||
'TypeI32I24' : 'I32',
|
||||
'TypeI32I64' : 'I32',
|
||||
'TypeI32I8' : 'I32',
|
||||
'TypeU16F32' : 'U16',
|
||||
'TypeU16U32' : 'U16',
|
||||
'TypeU32B32' : 'U32',
|
||||
'TypeU32F32' : 'U32',
|
||||
'TypeU32F64' : 'U32',
|
||||
'TypeU32U24' : 'U32',
|
||||
'TypeU8F32' : 'U8',
|
||||
}
|
||||
|
||||
DefaultSrcCountTable = {
|
||||
'GCNENC_SOPC' : 2,
|
||||
'GCNENC_SOPP' : 0,
|
||||
'GCNENC_SOP1' : 1,
|
||||
'GCNENC_SOP2' : 2,
|
||||
'GCNENC_SOPK' : 0,
|
||||
'GCNENC_SMRD' : 1,
|
||||
'GCNENC_VOPC' : 2,
|
||||
'GCNENC_VOP1' : 1,
|
||||
'GCNENC_VOP2' : 2,
|
||||
'GCNENC_VOP3' : 3,
|
||||
'GCNENC_VINTRP' : 1,
|
||||
'GCNENC_DS' : 3,
|
||||
'GCNENC_MUBUF' : 4,
|
||||
'GCNENC_MTBUF' : 4,
|
||||
'GCNENC_MIMG' : 4,
|
||||
'GCNENC_EXP' : 4,
|
||||
}
|
||||
|
||||
ARCH_SOUTHERN_ISLANDS = 1
|
||||
ARCH_SEA_ISLANDS = 2
|
||||
|
||||
InstDefDic = {}
|
||||
|
||||
def WriteList(encoding, op_list):
|
||||
dst_name = encoding + '.txt'
|
||||
with open(dst_name, 'w') as dst:
|
||||
for opcode, value, mode in op_list:
|
||||
line = '{}\t{}\t{}\n'.format(opcode, value, mode)
|
||||
dst.write(line)
|
||||
|
||||
def IsOpInList(op_name, op_list):
|
||||
|
||||
for opcode, value, mode in op_list:
|
||||
if opcode == op_name:
|
||||
return True
|
||||
return False
|
||||
|
||||
def FindUniqueVOP3(op_dic, vop3_list):
|
||||
unique_vop3 = []
|
||||
for opcode, value, mode in vop3_list:
|
||||
if IsOpInList(opcode, op_dic['GCNENC_VOP1']):
|
||||
continue
|
||||
if IsOpInList(opcode, op_dic['GCNENC_VOP2']):
|
||||
continue
|
||||
if IsOpInList(opcode, op_dic['GCNENC_VOPC']):
|
||||
continue
|
||||
|
||||
unique_vop3.append((opcode, value, mode))
|
||||
return unique_vop3
|
||||
|
||||
|
||||
def GetOpKey(encoding, op_name):
|
||||
key_name = op_name
|
||||
|
||||
if encoding == 'GCNENC_VOP3':
|
||||
key_name = 'V3_' + op_name[2:]
|
||||
return key_name
|
||||
|
||||
|
||||
def GetMaxOpValue(op_list):
|
||||
count = len(op_list)
|
||||
last = op_list[count - 1]
|
||||
return last[1]
|
||||
|
||||
def GetMaxOpName(op_list):
|
||||
count = len(op_list)
|
||||
last = op_list[count - 1]
|
||||
return last[0]
|
||||
|
||||
def GetArraySize(op_list):
|
||||
return GetMaxOpValue(op_list) + 1
|
||||
|
||||
def ParseOpType(op_name):
|
||||
src_type = 'Undefined'
|
||||
dst_type = src_type
|
||||
|
||||
dual_type_pat = re.compile('_(\S\d+)_(\S\d+)$')
|
||||
single_type_pat = re.compile('_(\S\d+)$')
|
||||
|
||||
m = dual_type_pat.search(op_name)
|
||||
if m:
|
||||
dst_type = m.group(1)
|
||||
src_type = m.group(2)
|
||||
|
||||
# VINTRP special
|
||||
if 'P' in dst_type:
|
||||
dst_type = src_type
|
||||
else:
|
||||
m = single_type_pat.search(op_name)
|
||||
if m:
|
||||
src_type = m.group(1)
|
||||
if 'X' in src_type:
|
||||
src_type = 'Undefined'
|
||||
dst_type = src_type
|
||||
return dst_type, src_type
|
||||
|
||||
|
||||
def WriteOpFormat(op_dic):
|
||||
dst = open('OpFormat.cpp', 'w')
|
||||
|
||||
for encoding, op_list in op_dic.items():
|
||||
|
||||
array_size = GetArraySize(op_list)
|
||||
|
||||
dst.write('const std::array<GcnInstFormat, {}> g_instructionFormat{} = {{{{\n'.format(array_size, encoding.replace('GCNENC_', '')))
|
||||
|
||||
struct_array = ['\t{ },'] * array_size
|
||||
for opcode, value, mode in op_list:
|
||||
op_key = GetOpKey(encoding, opcode)
|
||||
|
||||
if not op_key in InstDefDic:
|
||||
#print('inst not found: {}'.format(op_key))
|
||||
continue
|
||||
|
||||
inst_info = InstDefDic[op_key]
|
||||
cls = inst_info[0]
|
||||
src_count = DefaultSrcCountTable[encoding]
|
||||
dst_type, src_type = ParseOpType(opcode)
|
||||
|
||||
if 'GCN_SRC_NONE' in mode:
|
||||
src_count = 0
|
||||
if 'GCN_SRC2_NONE' in mode:
|
||||
src_count -= 1
|
||||
if 'GCN_VOP3_VOP2_DS01' in mode:
|
||||
src_count = 2
|
||||
if 'GCN_VOP3_VOP1_DS0' in mode:
|
||||
src_count = 1
|
||||
if 'GCN_VOP_ARG_NONE' in mode:
|
||||
src_count = 0
|
||||
# VOPC in VOP3, specify 2 src operands
|
||||
if encoding == 'GCNENC_VOP3' and (value >= 0 and value <= 247):
|
||||
src_count = 2
|
||||
|
||||
code_line = '\t// {} = {}\n\t{{ GcnInstClass::{}, {}, {},\n\t\tGcnNumericType::{}, GcnNumericType::{} }},'.\
|
||||
format(value, opcode, cls, src_count, 1, src_type, dst_type)
|
||||
struct_array[value] = code_line
|
||||
|
||||
dst.write('\n'.join(struct_array))
|
||||
dst.write('\n}};\n\n\n')
|
||||
|
||||
dst.close()
|
||||
|
||||
def WriteOpEnum(op_dic):
|
||||
dst = open('OpEnum.cpp', 'w')
|
||||
for encoding, op_list in op_dic.items():
|
||||
|
||||
encoding_short = encoding.replace('GCNENC_', '')
|
||||
dst.write('enum class GcnOpcode{} : uint32_t\n'.format(encoding_short))
|
||||
dst.write('{\n')
|
||||
|
||||
for opcode, value, mode in op_list:
|
||||
dst.write('\t{} = {},\n'.format(opcode, value))
|
||||
|
||||
max_op = GetMaxOpName(op_list)
|
||||
dst.write('\n\tOP_RANGE_{} = {} + 1,\n'.format(encoding_short, max_op))
|
||||
dst.write('};\n\n')
|
||||
|
||||
dst.close()
|
||||
|
||||
def ProcessOpcodes(op_list):
|
||||
print('opcode count:{}'.format(len(op_list)))
|
||||
|
||||
op_dic = {}
|
||||
for opcode, encoding, mode, value in op_list:
|
||||
|
||||
if not encoding in op_dic:
|
||||
op_dic[encoding] = []
|
||||
|
||||
op_dic[encoding].append((opcode, value, mode))
|
||||
|
||||
def takeOpValue(element):
|
||||
return element[1]
|
||||
|
||||
for value in op_dic.values():
|
||||
value.sort(key=takeOpValue)
|
||||
|
||||
WriteOpFormat(op_dic)
|
||||
WriteOpEnum(op_dic)
|
||||
|
||||
for encoding, lst in op_dic.items():
|
||||
WriteList(encoding, lst)
|
||||
|
||||
vop3_list = op_dic['GCNENC_VOP3']
|
||||
unique_vop3 = FindUniqueVOP3(op_dic, vop3_list)
|
||||
WriteList('VOP3_UNIQUE', unique_vop3)
|
||||
|
||||
|
||||
|
||||
def ParseInstDefs(src_name):
|
||||
src = open(src_name)
|
||||
pat = re.compile('\{(.*),.*\{(.*),(.*)\}.*\}')
|
||||
for line in src.readlines():
|
||||
|
||||
if not line:
|
||||
continue
|
||||
line = line.rstrip('\n')
|
||||
|
||||
m = pat.search(line)
|
||||
if not m:
|
||||
continue
|
||||
|
||||
op = m.group(1).strip().split('::')[1]
|
||||
cls = m.group(2).strip().split('::')[1]
|
||||
type = m.group(3).strip().split('::')[1]
|
||||
type = TypeDic[type]
|
||||
|
||||
if op in InstDefDic:
|
||||
input('already in dic:' + op)
|
||||
|
||||
InstDefDic[op] = (cls, type)
|
||||
|
||||
src.close()
|
||||
|
||||
|
||||
# use
|
||||
# ^ (?!\{).*\},
|
||||
# in sublime to merge lines
|
||||
|
||||
def main():
|
||||
src = open('GCNInstructions.cpp')
|
||||
|
||||
op_list = []
|
||||
pat = re.compile('\{.*\}')
|
||||
for line in src.readlines():
|
||||
line = line.rstrip('\n')
|
||||
if not line:
|
||||
continue
|
||||
m = pat.search(line)
|
||||
if not m:
|
||||
continue
|
||||
|
||||
line = line.replace('{', '').replace('}', '')
|
||||
parts = line.split(',')
|
||||
parts = [x.strip() for x in parts if x]
|
||||
|
||||
opcode = parts[0].replace('"', '').upper()
|
||||
encoding = parts[1]
|
||||
|
||||
if encoding == 'GCNENC_VOP3A' or encoding == 'GCNENC_VOP3B':
|
||||
encoding = 'GCNENC_VOP3'
|
||||
|
||||
mode = parts[2]
|
||||
value_str = parts[3]
|
||||
if 'x' in value_str:
|
||||
op_value = int(parts[3], 16)
|
||||
else:
|
||||
op_value = int(parts[3])
|
||||
|
||||
arch = parts[4]
|
||||
arch_mask = ArchDic[arch]
|
||||
if not (arch_mask & ARCH_SEA_ISLANDS):
|
||||
continue
|
||||
|
||||
op_list.append((opcode.upper(), encoding, mode, op_value))
|
||||
|
||||
src.close()
|
||||
|
||||
ParseInstDefs('GCNInstructionDefs.cpp')
|
||||
ProcessOpcodes(op_list)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
Loading…
Reference in a new issue