diff --git a/GPU/Common/GPUDebugInterface.cpp b/GPU/Common/GPUDebugInterface.cpp index a058d6cbf6..34cb050ffd 100644 --- a/GPU/Common/GPUDebugInterface.cpp +++ b/GPU/Common/GPUDebugInterface.cpp @@ -50,6 +50,9 @@ enum class GEReferenceIndex : uint32_t { PROJ_MATRIX = 0x278, TGEN_MATRIX = 0x288, MATRIX_END = 0x294, + + FIELD_START = 0x1000, + FIELD_END = 0xFF000, }; ENUM_CLASS_BITOPS(GEReferenceIndex); @@ -81,6 +84,228 @@ static constexpr ReferenceName referenceNames[] = { { GEReferenceIndex::TEXADDR7, "texaddr7" }, }; +enum class GECmdField : uint8_t { + DATA, // Alias for the entire data. + LOW_FLAG, + LOW_U2, + LOW_U4, + LOW_U7, + LOW_U8, + LOW_U10, + LOW_U10_P1, + LOW_U11, + LOW_U16, + MID_U8, + MID_U10, // At 10, 10 bits. + MID_U10_P1, // At 10, 10 bits (add 1 to value.) + TOP_U8, + FLAG_AFTER_1, // At 1, 1 bit. + FLAG_AFTER_2, // At 2, 1 bit. + FLAG_AFTER_8, // At 8, 1 bit. + FLAG_AFTER_9, // At 9, 1 bit. + FLAG_AFTER_10, // At 10, 1 bit. + FLAG_AFTER_11, // At 11, 1 bit. + FLAG_AFTER_16, // At 16, 1 bit. + FLAG_AFTER_18, // At 18, 1 bit. + FLAG_AFTER_19, // At 19, 1 bit. + FLAG_AFTER_20, // At 20, 1 bit. + FLAG_AFTER_21, // At 21, 1 bit. + FLAG_AFTER_22, // At 22, 1 bit. + FLAG_AFTER_23, // At 23, 1 bit. + U2_AFTER_8, // At 8, 2 bits. + U3_AFTER_16, // At 16, 3 bits. + U12_AFTER_4, // At 4, 12 bits. + PRIM_TYPE, // At 16, 3 bits. + SPLINE_UTYPE, // At 16, 2 bits. + SPLINE_VTYPE, // At 18, 2 bits. + SIGNAL_TYPE, // At 16, 8 bits. + VTYPE_TC, // At 0, 2 bits. + VTYPE_COL, // At 2, 3 bits. + VTYPE_NRM, // At 5, 2 bits. + VTYPE_POS, // At 7, 2 bits. + VTYPE_WEIGHTTYPE, // At 9, 2 bits. + VTYPE_INDEX, // At 11, 2 bits. + VTYPE_WEIGHTCOUNT, // At 14, 3 bits. + VTYPE_MORPHCOUNT, // At 18, 3 bits. + PATCH_PRIM_TYPE, // At 0, 2 bits. + LIGHT_COMP, // At 0, 2 bits. + LIGHT_TYPE, // At 8, 2 bits. + LIGHT_TYPE_SPECULAR, // 1 if comp is 1 (but not 3.) + HIGH_ADDR, // At 16, 8 bits moved left to top 8 bits. + TEX_W, // At 0, 4 bits - 1 to this power. + TEX_H, // At 8, 4 bits - 1 to this power. + UVGEN_TYPE, // At 0, 2 bits. + UVGEN_PROJ, // At 8, 2 bits. + TEX_FORMAT, // At 0, 4 bits. + TEX_MINFILTER, // At 0, 3 bits. + TEX_MAGFILTER, // At 8, 1 bit. + TEX_LEVEL_MODE, // At 0, 2 bits. + LOW_U12_4_FLOAT, // At 0, 12.4 converted to float. + HIGH_S4_4_FLOAT, // At 16, s.3.4 converted to float. + TEX_FUNC, // At 0, 3 bits. + CLUT_BYTES, // At 0, 6 bits, multiplied by 8. + CLUT_FORMAT, // At 0, 2 bits. + CLUT_SHIFT, // At 2, 5 bits. + CLUT_OFFSET, // At 16, 5 bits, multiplied by 16. + COMPARE_FUNC2, // At 0, 2 bits. + COMPARE_FUNC3, // At 0, 3 bits. + STENCIL_OP_AT_0, // At 0, 3 bits. + STENCIL_OP_AT_8, // At 8, 3 bits. + STENCIL_OP_AT_16, // At 16, 3 bits. + BLEND_SRC, // At 0, 4 bits. + BLEND_DST, // At 4, 4 bits. + BLEND_EQUATION, // At 8, 3 bits. + LOGIC_OP, // At 0, 4 bits. +}; + +struct FieldName { + GECmdFormat fmt; + GECmdField field; + const char *name; +}; + +static constexpr FieldName fieldNames[] = { + { GECmdFormat::PRIM, GECmdField::LOW_U16, "count" }, + { GECmdFormat::PRIM, GECmdField::PRIM_TYPE, "type" }, + { GECmdFormat::BEZIER, GECmdField::LOW_U8, "ucount" }, + { GECmdFormat::BEZIER, GECmdField::LOW_U8, "u" }, + { GECmdFormat::BEZIER, GECmdField::MID_U8, "vcount" }, + { GECmdFormat::BEZIER, GECmdField::MID_U8, "v" }, + { GECmdFormat::SPLINE, GECmdField::LOW_U8, "ucount" }, + { GECmdFormat::SPLINE, GECmdField::LOW_U8, "u" }, + { GECmdFormat::SPLINE, GECmdField::MID_U8, "vcount" }, + { GECmdFormat::SPLINE, GECmdField::MID_U8, "v" }, + { GECmdFormat::SPLINE, GECmdField::SPLINE_UTYPE, "utype" }, + { GECmdFormat::SPLINE, GECmdField::SPLINE_VTYPE, "vtype" }, + { GECmdFormat::SIGNAL, GECmdField::LOW_U16, "data" }, + { GECmdFormat::SIGNAL, GECmdField::SIGNAL_TYPE, "type" }, + { GECmdFormat::VERTEX_TYPE, GECmdField::VTYPE_TC, "texcoord" }, + { GECmdFormat::VERTEX_TYPE, GECmdField::VTYPE_TC, "tc" }, + { GECmdFormat::VERTEX_TYPE, GECmdField::VTYPE_COL, "col" }, + { GECmdFormat::VERTEX_TYPE, GECmdField::VTYPE_COL, "color" }, + { GECmdFormat::VERTEX_TYPE, GECmdField::VTYPE_NRM, "normal" }, + { GECmdFormat::VERTEX_TYPE, GECmdField::VTYPE_POS, "pos" }, + { GECmdFormat::VERTEX_TYPE, GECmdField::VTYPE_POS, "position" }, + { GECmdFormat::VERTEX_TYPE, GECmdField::VTYPE_WEIGHTTYPE, "weighttype" }, + { GECmdFormat::VERTEX_TYPE, GECmdField::VTYPE_WEIGHTTYPE, "weight" }, + { GECmdFormat::VERTEX_TYPE, GECmdField::VTYPE_INDEX, "index" }, + { GECmdFormat::VERTEX_TYPE, GECmdField::VTYPE_WEIGHTCOUNT, "weightcount" }, + { GECmdFormat::VERTEX_TYPE, GECmdField::VTYPE_MORPHCOUNT, "morphcount" }, + { GECmdFormat::VERTEX_TYPE, GECmdField::FLAG_AFTER_23, "through" }, + { GECmdFormat::VERTEX_TYPE, GECmdField::FLAG_AFTER_23, "throughmode" }, + { GECmdFormat::X10_Y10, GECmdField::LOW_U10, "x" }, + { GECmdFormat::X10_Y10, GECmdField::MID_U10, "y" }, + { GECmdFormat::X10_Y10, GECmdField::LOW_U10_P1, "w" }, + { GECmdFormat::X10_Y10, GECmdField::MID_U10_P1, "h" }, + { GECmdFormat::FLAG, GECmdField::LOW_FLAG, "flag" }, + { GECmdFormat::BONE_NUM, GECmdField::LOW_U7, "num" }, + { GECmdFormat::MATRIX_NUM, GECmdField::LOW_U4, "num" }, + { GECmdFormat::FLOAT, GECmdField::DATA, "data" }, + { GECmdFormat::PATCH_DIVISION, GECmdField::LOW_U8, "u" }, + { GECmdFormat::PATCH_DIVISION, GECmdField::MID_U8, "v" }, + { GECmdFormat::PATCH_PRIM, GECmdField::PATCH_PRIM_TYPE, "type" }, + { GECmdFormat::SUBPIXEL_COORD, GECmdField::LOW_U4, "frac" }, + { GECmdFormat::SUBPIXEL_COORD, GECmdField::LOW_U4, "sub" }, + { GECmdFormat::SUBPIXEL_COORD, GECmdField::LOW_U4, "subpixels" }, + { GECmdFormat::SUBPIXEL_COORD, GECmdField::U12_AFTER_4, "int" }, + { GECmdFormat::SUBPIXEL_COORD, GECmdField::U12_AFTER_4, "integer" }, + { GECmdFormat::SUBPIXEL_COORD, GECmdField::LOW_U12_4_FLOAT, "pixels" }, + { GECmdFormat::MATERIAL_UPDATE, GECmdField::LOW_FLAG, "ambient" }, + { GECmdFormat::MATERIAL_UPDATE, GECmdField::FLAG_AFTER_1, "diffuse" }, + { GECmdFormat::MATERIAL_UPDATE, GECmdField::FLAG_AFTER_2, "specular" }, + { GECmdFormat::RGB, GECmdField::LOW_U8, "r" }, + { GECmdFormat::RGB, GECmdField::LOW_U8, "red" }, + { GECmdFormat::RGB, GECmdField::MID_U8, "g" }, + { GECmdFormat::RGB, GECmdField::MID_U8, "green" }, + { GECmdFormat::RGB, GECmdField::TOP_U8, "b" }, + { GECmdFormat::RGB, GECmdField::TOP_U8, "blue" }, + { GECmdFormat::LIGHT_TYPE, GECmdField::LIGHT_COMP, "computation" }, + { GECmdFormat::LIGHT_TYPE, GECmdField::LIGHT_TYPE, "type" }, + { GECmdFormat::LIGHT_TYPE, GECmdField::LIGHT_TYPE_SPECULAR, "specular" }, + { GECmdFormat::STRIDE, GECmdField::LOW_U11, "stride" }, + { GECmdFormat::STRIDE_HIGH_ADDR, GECmdField::HIGH_ADDR, "highaddr" }, + { GECmdFormat::HIGH_ADDR, GECmdField::HIGH_ADDR, "highaddr" }, + { GECmdFormat::HIGH_ADDR_ONLY, GECmdField::HIGH_ADDR, "highaddr" }, + { GECmdFormat::TEX_SIZE, GECmdField::TEX_W, "w" }, + { GECmdFormat::TEX_SIZE, GECmdField::TEX_W, "width" }, + { GECmdFormat::TEX_SIZE, GECmdField::TEX_H, "h" }, + { GECmdFormat::TEX_SIZE, GECmdField::TEX_H, "height" }, + { GECmdFormat::TEX_MAP_MODE, GECmdField::UVGEN_TYPE, "type" }, + { GECmdFormat::TEX_MAP_MODE, GECmdField::UVGEN_TYPE, "uv" }, + { GECmdFormat::TEX_MAP_MODE, GECmdField::UVGEN_PROJ, "proj" }, + { GECmdFormat::TEX_MAP_MODE, GECmdField::UVGEN_PROJ, "factor" }, + { GECmdFormat::TEX_LIGHT_SRC, GECmdField::LOW_U2, "u" }, + { GECmdFormat::TEX_LIGHT_SRC, GECmdField::U2_AFTER_8, "v" }, + { GECmdFormat::TEX_MODE, GECmdField::LOW_FLAG, "swizzle" }, + { GECmdFormat::TEX_MODE, GECmdField::FLAG_AFTER_8, "separateclut" }, + { GECmdFormat::TEX_MODE, GECmdField::FLAG_AFTER_8, "separate" }, + { GECmdFormat::TEX_MODE, GECmdField::U3_AFTER_16, "maxlevel" }, + { GECmdFormat::TEX_MODE, GECmdField::U3_AFTER_16, "level" }, + { GECmdFormat::TEX_FORMAT, GECmdField::TEX_FORMAT, "format" }, + { GECmdFormat::TEX_FORMAT, GECmdField::TEX_FORMAT, "fmt" }, + { GECmdFormat::TEX_FORMAT, GECmdField::FLAG_AFTER_2, "indexed" }, + { GECmdFormat::TEX_FILTER, GECmdField::TEX_MINFILTER, "min" }, + { GECmdFormat::TEX_FILTER, GECmdField::TEX_MINFILTER, "minify" }, + { GECmdFormat::TEX_FILTER, GECmdField::TEX_MAGFILTER, "mag" }, + { GECmdFormat::TEX_FILTER, GECmdField::TEX_MAGFILTER, "magnify" }, + { GECmdFormat::TEX_CLAMP, GECmdField::LOW_FLAG, "s" }, + { GECmdFormat::TEX_CLAMP, GECmdField::FLAG_AFTER_8, "t" }, + { GECmdFormat::TEX_LEVEL_MODE, GECmdField::TEX_LEVEL_MODE, "mode" }, + { GECmdFormat::TEX_LEVEL_MODE, GECmdField::HIGH_S4_4_FLOAT, "bias" }, + { GECmdFormat::TEX_FUNC, GECmdField::TEX_FUNC, "func" }, + { GECmdFormat::TEX_FUNC, GECmdField::TEX_FUNC, "function" }, + { GECmdFormat::TEX_FUNC, GECmdField::FLAG_AFTER_8, "alpha" }, + { GECmdFormat::TEX_FUNC, GECmdField::FLAG_AFTER_8, "a" }, + { GECmdFormat::TEX_FUNC, GECmdField::FLAG_AFTER_16, "double" }, + { GECmdFormat::TEX_FUNC, GECmdField::FLAG_AFTER_16, "doubling" }, + { GECmdFormat::CLUT_FORMAT, GECmdField::CLUT_FORMAT, "format" }, + { GECmdFormat::CLUT_FORMAT, GECmdField::CLUT_FORMAT, "fmt" }, + { GECmdFormat::CLUT_FORMAT, GECmdField::CLUT_SHIFT, "shift" }, + { GECmdFormat::CLUT_FORMAT, GECmdField::MID_U8, "mask" }, + { GECmdFormat::CLUT_FORMAT, GECmdField::CLUT_OFFSET, "offset" }, + { GECmdFormat::CLUT_FORMAT, GECmdField::CLUT_OFFSET, "base" }, + { GECmdFormat::CLEAR_MODE, GECmdField::LOW_FLAG, "on" }, + { GECmdFormat::CLEAR_MODE, GECmdField::LOW_FLAG, "enable" }, + { GECmdFormat::CLEAR_MODE, GECmdField::LOW_FLAG, "flag" }, + { GECmdFormat::CLEAR_MODE, GECmdField::FLAG_AFTER_8, "color" }, + { GECmdFormat::CLEAR_MODE, GECmdField::FLAG_AFTER_9, "alpha" }, + { GECmdFormat::CLEAR_MODE, GECmdField::FLAG_AFTER_9, "stencil" }, + { GECmdFormat::CLEAR_MODE, GECmdField::FLAG_AFTER_10, "depth" }, + { GECmdFormat::COLOR_TEST_FUNC, GECmdField::COMPARE_FUNC2, "func" }, + { GECmdFormat::ALPHA_TEST, GECmdField::COMPARE_FUNC3, "func" }, + { GECmdFormat::ALPHA_TEST, GECmdField::MID_U8, "ref" }, + { GECmdFormat::ALPHA_TEST, GECmdField::MID_U8, "reference" }, + { GECmdFormat::ALPHA_TEST, GECmdField::TOP_U8, "mask" }, + { GECmdFormat::STENCIL_OP, GECmdField::STENCIL_OP_AT_0, "sfail" }, + { GECmdFormat::STENCIL_OP, GECmdField::STENCIL_OP_AT_8, "zfail" }, + { GECmdFormat::STENCIL_OP, GECmdField::STENCIL_OP_AT_16, "zpass" }, + { GECmdFormat::STENCIL_OP, GECmdField::STENCIL_OP_AT_16, "pass" }, + { GECmdFormat::DEPTH_TEST_FUNC, GECmdField::COMPARE_FUNC3, "func" }, + { GECmdFormat::BLEND_MODE, GECmdField::BLEND_SRC, "src" }, + { GECmdFormat::BLEND_MODE, GECmdField::BLEND_SRC, "srcfactor" }, + { GECmdFormat::BLEND_MODE, GECmdField::BLEND_DST, "dst" }, + { GECmdFormat::BLEND_MODE, GECmdField::BLEND_DST, "dstfactor" }, + { GECmdFormat::BLEND_MODE, GECmdField::BLEND_DST, "dest" }, + { GECmdFormat::BLEND_MODE, GECmdField::BLEND_DST, "destfactor" }, + { GECmdFormat::BLEND_MODE, GECmdField::BLEND_EQUATION, "eq" }, + { GECmdFormat::BLEND_MODE, GECmdField::BLEND_EQUATION, "equation" }, + { GECmdFormat::BLEND_MODE, GECmdField::BLEND_EQUATION, "mode" }, + { GECmdFormat::LOGIC_OP, GECmdField::LOGIC_OP, "op" }, + { GECmdFormat::LOGIC_OP, GECmdField::LOGIC_OP, "mode" }, + { GECmdFormat::ALPHA_PRIM, GECmdField::LOW_U8, "alpha" }, + { GECmdFormat::ALPHA_PRIM, GECmdField::PRIM_TYPE, "type" }, + { GECmdFormat::ALPHA_PRIM, GECmdField::PRIM_TYPE, "prim" }, + { GECmdFormat::ALPHA_PRIM, GECmdField::FLAG_AFTER_11, "antialias" }, + // TODO: Clip bits? + { GECmdFormat::ALPHA_PRIM, GECmdField::FLAG_AFTER_18, "shading" }, + { GECmdFormat::ALPHA_PRIM, GECmdField::FLAG_AFTER_18, "gouraud" }, + { GECmdFormat::ALPHA_PRIM, GECmdField::FLAG_AFTER_19, "cull" }, + { GECmdFormat::ALPHA_PRIM, GECmdField::FLAG_AFTER_20, "cullccw" }, + { GECmdFormat::ALPHA_PRIM, GECmdField::FLAG_AFTER_21, "tex" }, + { GECmdFormat::ALPHA_PRIM, GECmdField::FLAG_AFTER_22, "fog" }, + { GECmdFormat::ALPHA_PRIM, GECmdField::FLAG_AFTER_23, "dither" }, +}; + class GEExpressionFunctions : public IExpressionFunctions { public: GEExpressionFunctions(GPUDebugInterface *gpu) : gpu_(gpu) {} @@ -92,6 +317,10 @@ public: bool getMemoryValue(uint32_t address, int size, uint32_t &dest, char *error) override; private: + bool parseFieldReference(const char *ref, const char *field, uint32_t &referenceIndex); + uint32_t getFieldValue(GECmdFormat fmt, GECmdField field, uint32_t value); + ExpressionType getFieldType(GECmdFormat fmt, GECmdField field); + GPUDebugInterface *gpu_; }; @@ -104,6 +333,15 @@ bool GEExpressionFunctions::parseReference(char *str, uint32_t &referenceIndex) return true; } + char *dot = strchr(str, '.'); + if (dot != nullptr) { + *dot = '\0'; + bool success = parseFieldReference(str, dot + 1, referenceIndex); + *dot = '.'; + if (success) + return true; + } + // Also allow non-register references. for (const auto &entry : referenceNames) { if (strcasecmp(str, entry.name) == 0) { @@ -150,6 +388,22 @@ bool GEExpressionFunctions::parseReference(char *str, uint32_t &referenceIndex) return false; } +bool GEExpressionFunctions::parseFieldReference(const char *ref, const char *field, uint32_t &referenceIndex) { + GECmdInfo info; + if (!GECmdInfoByName(ref, info)) { + return false; + } + + for (const auto &entry : fieldNames) { + if (entry.fmt == info.fmt && strcasecmp(field, entry.name) == 0) { + referenceIndex = (info.reg << 12) | (uint32_t)entry.field; + return true; + } + } + + return false; +} + bool GEExpressionFunctions::parseSymbol(char *str, uint32_t &symbolValue) { // Mainly useful for checking memory addresses. return g_symbolMap->GetLabelValue(str, symbolValue); @@ -158,11 +412,19 @@ bool GEExpressionFunctions::parseSymbol(char *str, uint32_t &symbolValue) { uint32_t GEExpressionFunctions::getReferenceValue(uint32_t referenceIndex) { GPUgstate state = gpu_->GetGState(); if (referenceIndex < 0x100) { + GECmdFormat fmt = GECmdInfoByCmd(GECommand(referenceIndex)).fmt; uint32_t value = state.cmdmem[referenceIndex]; - // TODO: Later, support float values and similar. + if (fmt == GECmdFormat::FLOAT) + return value << 8; return value & 0x00FFFFFF; } + if (referenceIndex >= (uint32_t)GEReferenceIndex::FIELD_START && referenceIndex <= (uint32_t)GEReferenceIndex::FIELD_END) { + uint32_t value = state.cmdmem[referenceIndex >> 12] & 0x00FFFFFF; + GECmdFormat fmt = GECmdInfoByCmd(GECommand(referenceIndex >> 12)).fmt; + return getFieldValue(fmt, GECmdField(referenceIndex & 0xFF), value); + } + // We return the matrix value as float bits, which gets interpreted correctly in the parser. if (referenceIndex >= (uint32_t)GEReferenceIndex::BONE_MATRIX && referenceIndex < (uint32_t)GEReferenceIndex::MATRIX_END) { float value; @@ -209,7 +471,6 @@ uint32_t GEExpressionFunctions::getReferenceValue(uint32_t referenceIndex) { } return 0; case GEReferenceIndex::OP: - // TODO: Support fields under this as per the cmd format? if (gpu_->GetCurrentDisplayList(list)) { return Memory::Read_U32(list.pc); } @@ -245,6 +506,8 @@ uint32_t GEExpressionFunctions::getReferenceValue(uint32_t referenceIndex) { case GEReferenceIndex::PROJ_MATRIX: case GEReferenceIndex::TGEN_MATRIX: case GEReferenceIndex::MATRIX_END: + case GEReferenceIndex::FIELD_START: + case GEReferenceIndex::FIELD_END: // Shouldn't have gotten here. break; } @@ -253,17 +516,202 @@ uint32_t GEExpressionFunctions::getReferenceValue(uint32_t referenceIndex) { return 0; } +uint32_t GEExpressionFunctions::getFieldValue(GECmdFormat fmt, GECmdField field, uint32_t value) { + switch (field) { + case GECmdField::DATA: + return value; + case GECmdField::LOW_FLAG: + return value & 1; + case GECmdField::LOW_U2: + return value & 3; + case GECmdField::LOW_U4: + return value & 0xF; + case GECmdField::LOW_U7: + return value & 0x7F; + case GECmdField::LOW_U8: + return value & 0xFF; + case GECmdField::LOW_U10: + return value & 0x03FF; + case GECmdField::LOW_U10_P1: + return (value & 0x03FF) + 1; + case GECmdField::LOW_U11: + return value & 0x07FF; + case GECmdField::LOW_U16: + return value & 0xFFFF; + case GECmdField::MID_U8: + return (value >> 8) & 0xFF; + case GECmdField::MID_U10: + return (value >> 10) & 0x03FF; + case GECmdField::MID_U10_P1: + return ((value >> 10) & 0x03FF) + 1; + case GECmdField::TOP_U8: + return (value >> 16) & 0xFF; + case GECmdField::FLAG_AFTER_1: + return (value >> 1) & 1; + case GECmdField::FLAG_AFTER_2: + return (value >> 2) & 1; + case GECmdField::FLAG_AFTER_8: + return (value >> 8) & 1; + case GECmdField::FLAG_AFTER_9: + return (value >> 8) & 1; + case GECmdField::FLAG_AFTER_10: + return (value >> 10) & 1; + case GECmdField::FLAG_AFTER_11: + return (value >> 11) & 1; + case GECmdField::FLAG_AFTER_16: + return (value >> 16) & 1; + case GECmdField::FLAG_AFTER_18: + return (value >> 18) & 1; + case GECmdField::FLAG_AFTER_19: + return (value >> 19) & 1; + case GECmdField::FLAG_AFTER_20: + return (value >> 20) & 1; + case GECmdField::FLAG_AFTER_21: + return (value >> 21) & 1; + case GECmdField::FLAG_AFTER_22: + return (value >> 22) & 1; + case GECmdField::FLAG_AFTER_23: + return (value >> 23) & 1; + case GECmdField::U2_AFTER_8: + return (value >> 8) & 3; + case GECmdField::U3_AFTER_16: + return (value >> 16) & 7; + case GECmdField::U12_AFTER_4: + return (value >> 4) & 0x0FFF; + + // Below here are "typed" values, maybe they'll be exposed differently than integers someday. + + case GECmdField::PRIM_TYPE: + return (value >> 16) & 7; + case GECmdField::SPLINE_UTYPE: + return (value >> 16) & 3; + case GECmdField::SPLINE_VTYPE: + return (value >> 18) & 3; + case GECmdField::SIGNAL_TYPE: + return (value >> 16) & 0xFF; + case GECmdField::VTYPE_TC: + return value & 3; + case GECmdField::VTYPE_COL: + return (value >> 2) & 7; + case GECmdField::VTYPE_NRM: + return (value >> 5) & 3; + case GECmdField::VTYPE_POS: + return (value >> 7) & 3; + case GECmdField::VTYPE_WEIGHTTYPE: + return (value >> 9) & 3; + case GECmdField::VTYPE_INDEX: + return (value >> 11) & 3; + case GECmdField::VTYPE_WEIGHTCOUNT: + return ((value >> 14) & 7) + 1; + case GECmdField::VTYPE_MORPHCOUNT: + return ((value >> 18) & 7) + 1; + case GECmdField::PATCH_PRIM_TYPE: + return value & 3; + case GECmdField::LIGHT_COMP: + return value & 3; + case GECmdField::LIGHT_TYPE: + return (value >> 8) & 3; + case GECmdField::LIGHT_TYPE_SPECULAR: + return (value & 3) == 1; + case GECmdField::HIGH_ADDR: + return (value << 8) & 0xFF000000; + case GECmdField::TEX_W: + return 1 << (value & 0xF); + case GECmdField::TEX_H: + return 1 << ((value >> 8) & 0xF); + case GECmdField::UVGEN_TYPE: + return value & 3; + case GECmdField::UVGEN_PROJ: + return (value >> 8) & 3; + case GECmdField::TEX_FORMAT: + return value & 0xF; + case GECmdField::TEX_MINFILTER: + return value & 7; + case GECmdField::TEX_MAGFILTER: + return (value >> 8) & 1; + case GECmdField::TEX_LEVEL_MODE: + return value & 3; + case GECmdField::LOW_U12_4_FLOAT: + { + float f = (value & 0xFFFF) / 16.0f; + uint32_t result; + memcpy(&result, &f, sizeof(result)); + return result; + } + case GECmdField::HIGH_S4_4_FLOAT: // At 16, s.3.4 converted to float. + { + int value8 = (int)(s8)((value >> 16) & 0xFF); + float f = value8 / 16.0f; + uint32_t result; + memcpy(&result, &f, sizeof(result)); + return result; + } + case GECmdField::TEX_FUNC: + return value & 7; + case GECmdField::CLUT_BYTES: + return (value & 0x3F) * 8; + case GECmdField::CLUT_FORMAT: + return value & 3; + case GECmdField::CLUT_SHIFT: + return (value >> 2) & 0x1F; + case GECmdField::CLUT_OFFSET: + return ((value >> 16) & 0x1F) << 4; + case GECmdField::COMPARE_FUNC2: + return value & 3; + case GECmdField::COMPARE_FUNC3: + return value & 7; + case GECmdField::STENCIL_OP_AT_0: + return value & 7; + case GECmdField::STENCIL_OP_AT_8: + return (value >> 8) & 7; + case GECmdField::STENCIL_OP_AT_16: + return (value >> 16) & 7; + case GECmdField::BLEND_SRC: + return value & 0xF; + case GECmdField::BLEND_DST: + return (value >> 4) & 0xF; + case GECmdField::BLEND_EQUATION: + return (value >> 8) & 7; + case GECmdField::LOGIC_OP: + return value & 0xF; + } + + _assert_msg_(false, "Invalid field type"); + return 0; +} + ExpressionType GEExpressionFunctions::getReferenceType(uint32_t referenceIndex) { if (referenceIndex < 0x100) { - // TODO: Later, support float values and similar. + GECmdFormat fmt = GECmdInfoByCmd(GECommand(referenceIndex)).fmt; + if (fmt == GECmdFormat::FLOAT) + return EXPR_TYPE_FLOAT; return EXPR_TYPE_UINT; } + if (referenceIndex >= (uint32_t)GEReferenceIndex::FIELD_START && referenceIndex <= (uint32_t)GEReferenceIndex::FIELD_END) { + GECmdFormat fmt = GECmdInfoByCmd(GECommand(referenceIndex >> 12)).fmt; + return getFieldType(fmt, GECmdField(referenceIndex & 0xFF)); + } + if (referenceIndex >= (uint32_t)GEReferenceIndex::BONE_MATRIX && referenceIndex < (uint32_t)GEReferenceIndex::MATRIX_END) return EXPR_TYPE_FLOAT; return EXPR_TYPE_UINT; } +ExpressionType GEExpressionFunctions::getFieldType(GECmdFormat fmt, GECmdField field) { + switch (field) { + case GECmdField::LOW_U12_4_FLOAT: + case GECmdField::HIGH_S4_4_FLOAT: + return EXPR_TYPE_FLOAT; + + default: + // Almost all of these are uint, so not listing each one. + break; + } + + return EXPR_TYPE_UINT; +} + bool GEExpressionFunctions::getMemoryValue(uint32_t address, int size, uint32_t &dest, char *error) { if (!Memory::IsValidRange(address, size)) { sprintf(error, "Invalid address or size %08x + %d", address, size); diff --git a/GPU/Debugger/GECommandTable.h b/GPU/Debugger/GECommandTable.h index 95b4eddf0f..01d2059079 100644 --- a/GPU/Debugger/GECommandTable.h +++ b/GPU/Debugger/GECommandTable.h @@ -48,7 +48,7 @@ enum class GECmdFormat { STRIDE, // 11 bits. STRIDE_HIGH_ADDR, // 11 bits stride, 5 ignored, 8 bits high address. TEX_SIZE, // 4 bits width power, 4 bits ignored, 4 bits height power. - TEX_MAP_MODE, // 8 bits mode (2 bits), 2 bits environment factor. + TEX_MAP_MODE, // 8 bits mode (2 bits), 2 bits matrix factor. TEX_LIGHT_SRC, // 8 bits lightu (2 bits), 2 bits lightv. TEX_MODE, // 8 bits swizzle (1 bit), 8 bits separate clut4 (1 bit), 3 bits max level. TEX_FORMAT, // 4 bits format.