GE Debugger: Add fields to register expressions.

This means a conditional breakpoint can now use, for example,
vtype.through == 1 to check the through mode flag.

No constants, but this makes it easier to get right.  Would be nice to
have an autocomplete of the field names, of course...
This commit is contained in:
Unknown W. Brackets 2022-09-11 13:09:03 -07:00
parent 55c70332a1
commit 7d07e4e75d
2 changed files with 452 additions and 4 deletions

View File

@ -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);

View File

@ -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.