Use formatters in GetBPRegInfo; add missing commands

BPMEM_TEV_COLOR_ENV + 6 (0xC6) was missing due to a typo.  BPMEM_BP_MASK (0xFE) does not lend itself well to documentation with the current FIFO analyzer implementation (since it requires remembering the values in BP memory) but still shouldn't be treated as unknown.  BPMEM_TX_SETMODE0_4 and BPMEM_TX_SETMODE1_4 (0xA4-0xAB) were missing entirely.
This commit is contained in:
Pokechu22 2021-02-07 15:25:11 -08:00
parent 70f9fc4e75
commit df81210e96
3 changed files with 821 additions and 378 deletions

View File

@ -287,11 +287,17 @@ void FIFOAnalyzer::UpdateDetails()
case OpcodeDecoder::GX_LOAD_BP_REG:
{
u32 cmd2 = Common::swap32(objectdata);
objectdata += 4;
new_label = QStringLiteral("BP %1 %2")
.arg(cmd2 >> 24, 2, 16, QLatin1Char('0'))
.arg(cmd2 & 0xFFFFFF, 6, 16, QLatin1Char('0'));
const u8 cmd2 = *objectdata++;
const u32 cmddata = Common::swap24(objectdata);
objectdata += 3;
const auto [name, desc] = GetBPRegInfo(cmd2, cmddata);
ASSERT(!name.empty());
new_label = QStringLiteral("BP %1 %2 %3")
.arg(cmd2, 2, 16, QLatin1Char('0'))
.arg(cmddata, 6, 16, QLatin1Char('0'))
.arg(QString::fromStdString(name));
}
break;
@ -476,14 +482,14 @@ void FIFOAnalyzer::UpdateDescription()
QString text;
if (*cmddata == OpcodeDecoder::GX_LOAD_BP_REG)
{
std::string name;
std::string desc;
GetBPRegInfo(cmddata + 1, &name, &desc);
const u8 cmd = *(cmddata + 1);
const u32 value = Common::swap24(cmddata + 2);
const auto [name, desc] = GetBPRegInfo(cmd, value);
ASSERT(!name.empty());
text = tr("BP register ");
text += name.empty() ?
QStringLiteral("UNKNOWN_%1").arg(*(cmddata + 1), 2, 16, QLatin1Char('0')) :
QString::fromStdString(name);
text += QString::fromStdString(name);
text += QLatin1Char{'\n'};
if (desc.empty())

View File

@ -6,8 +6,10 @@
#include <array>
#include <string>
#include <utility>
#include "Common/BitField.h"
#include "Common/BitUtils.h"
#include "Common/CommonTypes.h"
#include "Common/EnumFormatter.h"
#include "Common/Inline.h"
@ -411,6 +413,50 @@ struct TevStageCombiner
ColorCombiner colorC;
AlphaCombiner alphaC;
};
template <>
struct fmt::formatter<TevStageCombiner::ColorCombiner>
{
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
template <typename FormatContext>
auto format(const TevStageCombiner::ColorCombiner& cc, FormatContext& ctx)
{
return format_to(ctx.out(),
"a: {}\n"
"b: {}\n"
"c: {}\n"
"d: {}\n"
"Bias: {}\n"
"Op: {} / Comparison: {}\n"
"Clamp: {}\n"
"Scale factor: {} / Compare mode: {}\n"
"Dest: {}",
cc.a, cc.b, cc.c, cc.d, cc.bias, cc.op, cc.comparison, cc.clamp ? "Yes" : "No",
cc.scale, cc.compare_mode, cc.dest);
}
};
template <>
struct fmt::formatter<TevStageCombiner::AlphaCombiner>
{
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
template <typename FormatContext>
auto format(const TevStageCombiner::AlphaCombiner& ac, FormatContext& ctx)
{
return format_to(ctx.out(),
"a: {}\n"
"b: {}\n"
"c: {}\n"
"d: {}\n"
"Bias: {}\n"
"Op: {} / Comparison: {}\n"
"Clamp: {}\n"
"Scale factor: {} / Compare mode: {}\n"
"Dest: {}\n"
"Ras sel: {}\n"
"Tex sel: {}",
ac.a, ac.b, ac.c, ac.d, ac.bias, ac.op, ac.comparison, ac.clamp ? "Yes" : "No",
ac.scale, ac.compare_mode, ac.dest, ac.rswap, ac.tswap);
}
};
// several discoveries:
// GXSetTevIndBumpST(tevstage, indstage, matrixind)
@ -444,10 +490,33 @@ union TevStageIndirect
u32 unused : 11;
};
u32 fullhex;
// If bs and mid are zero, the result of the stage is independent of
// the texture sample data, so we can skip sampling the texture.
bool IsActive() const { return bs != IndTexBumpAlpha::Off || mid != 0; }
};
template <>
struct fmt::formatter<TevStageIndirect>
{
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
template <typename FormatContext>
auto format(const TevStageIndirect& tevind, FormatContext& ctx)
{
return format_to(ctx.out(),
"Indirect tex stage ID: {}\n"
"Format: {}\n"
"Bias: {}\n"
"Bump alpha: {}\n"
"Offset matrix ID: {}\n"
"Regular coord S wrapping factor: {}\n"
"Regular coord T wrapping factor: {}\n"
"Use modified texture coordinates for LOD computation: {}\n"
"Add texture coordinates from previous TEV stage: {}",
tevind.bt, tevind.fmt, tevind.bias, tevind.bs, tevind.mid, tevind.sw,
tevind.tw, tevind.lb_utclod ? "Yes" : "No", tevind.fb_addprev ? "Yes" : "No");
}
};
enum class RasColorChan : u32
{
@ -485,6 +554,23 @@ union TwoTevStageOrders
u32 getEnable(int i) const { return i ? enable1.Value() : enable0.Value(); }
RasColorChan getColorChan(int i) const { return i ? colorchan1.Value() : colorchan0.Value(); }
};
template <>
struct fmt::formatter<TwoTevStageOrders>
{
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
template <typename FormatContext>
auto format(const TwoTevStageOrders& stages, FormatContext& ctx)
{
return format_to(ctx.out(),
"Stage 0 texmap: {}\nStage 0 tex coord: {}\n"
"Stage 0 enable texmap: {}\nStage 0 color channel: {}\n"
"Stage 1 texmap: {}\nStage 1 tex coord: {}\n"
"Stage 1 enable texmap: {}\nStage 1 color channel: {}\n",
stages.texmap0, stages.texcoord0, stages.enable0 ? "Yes" : "No",
stages.colorchan0, stages.texmap1, stages.texcoord1,
stages.enable1 ? "Yes" : "No", stages.colorchan1);
}
};
union TEXSCALE
{
@ -494,6 +580,22 @@ union TEXSCALE
BitField<12, 4, u32> ts1; // Indirect tex stage 1
u32 hex;
};
template <>
struct fmt::formatter<TEXSCALE>
{
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
template <typename FormatContext>
auto format(const TEXSCALE& scale, FormatContext& ctx)
{
return format_to(ctx.out(),
"Even stage S scale: {} ({})\n"
"Even stage T scale: {} ({})\n"
"Odd stage S scale: {} ({})\n"
"Odd stage T scale: {} ({})",
scale.ss0, 1.f / (1 << scale.ss0), scale.ts0, 1.f / (1 << scale.ts0),
scale.ss1, 1.f / (1 << scale.ss1), scale.ts1, 1.f / (1 << scale.ts1));
}
};
union RAS1_IREF
{
@ -510,6 +612,23 @@ union RAS1_IREF
u32 getTexCoord(int i) const { return (hex >> (6 * i + 3)) & 7; }
u32 getTexMap(int i) const { return (hex >> (6 * i)) & 7; }
};
template <>
struct fmt::formatter<RAS1_IREF>
{
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
template <typename FormatContext>
auto format(const RAS1_IREF& indref, FormatContext& ctx)
{
// The field names here are suspicious, since there is no bi3 or bc2
return format_to(ctx.out(),
"Stage 0 ntexmap: {}\nStage 0 ntexcoord: {}\n"
"Stage 1 ntexmap: {}\nStage 1 ntexcoord: {}\n"
"Stage 2 ntexmap: {}\nStage 2 ntexcoord: {}\n"
"Stage 3 ntexmap: {}\nStage 3 ntexcoord: {}",
indref.bi0, indref.bc0, indref.bi1, indref.bc1, indref.bi2, indref.bc3,
indref.bi4, indref.bc4);
}
};
// Texture structs
enum class WrapMode : u32
@ -583,12 +702,47 @@ union TexMode0
BitField<21, 1, bool, u32> lod_clamp;
u32 hex;
};
template <>
struct fmt::formatter<TexMode0>
{
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
template <typename FormatContext>
auto format(const TexMode0& mode, FormatContext& ctx)
{
return format_to(ctx.out(),
"Wrap S: {}\n"
"Wrap T: {}\n"
"Mag filter: {}\n"
"Mipmap filter: {}\n"
"Min filter: {}\n"
"LOD type: {}\n"
"LOD bias: {} ({})\n"
"Max aniso: {}\n"
"LOD/bias clamp: {}",
mode.wrap_s, mode.wrap_t, mode.mag_filter, mode.mipmap_filter, mode.min_filter,
mode.diag_lod, mode.lod_bias, mode.lod_bias / 32.f, mode.max_aniso,
mode.lod_clamp ? "Yes" : "No");
}
};
union TexMode1
{
BitField<0, 8, u32> min_lod;
BitField<8, 8, u32> max_lod;
u32 hex;
};
template <>
struct fmt::formatter<TexMode1>
{
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
template <typename FormatContext>
auto format(const TexMode1& mode, FormatContext& ctx)
{
return format_to(ctx.out(), "Min LOD: {} ({})\nMax LOD: {} ({})", mode.min_lod,
mode.min_lod / 16.f, mode.max_lod, mode.max_lod / 16.f);
}
};
union TexImage0
{
BitField<0, 10, u32> width; // Actually w-1
@ -596,6 +750,21 @@ union TexImage0
BitField<20, 4, TextureFormat> format;
u32 hex;
};
template <>
struct fmt::formatter<TexImage0>
{
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
template <typename FormatContext>
auto format(const TexImage0& teximg, FormatContext& ctx)
{
return format_to(ctx.out(),
"Width: {}\n"
"Height: {}\n"
"Format: {}",
teximg.width + 1, teximg.height + 1, teximg.format);
}
};
union TexImage1
{
BitField<0, 15, u32> tmem_even; // TMEM line index for even LODs
@ -606,6 +775,22 @@ union TexImage1
BitField<21, 1, bool, u32> cache_manually_managed;
u32 hex;
};
template <>
struct fmt::formatter<TexImage1>
{
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
template <typename FormatContext>
auto format(const TexImage1& teximg, FormatContext& ctx)
{
return format_to(ctx.out(),
"Even TMEM Offset: {:x}\n"
"Even TMEM Width: {}\n"
"Even TMEM Height: {}\n"
"Cache is manually managed: {}",
teximg.tmem_even, teximg.cache_width, teximg.cache_height,
teximg.cache_manually_managed ? "Yes" : "No");
}
};
union TexImage2
{
@ -614,18 +799,55 @@ union TexImage2
BitField<18, 3, u32> cache_height;
u32 hex;
};
template <>
struct fmt::formatter<TexImage2>
{
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
template <typename FormatContext>
auto format(const TexImage2& teximg, FormatContext& ctx)
{
return format_to(ctx.out(),
"Odd TMEM Offset: {:x}\n"
"Odd TMEM Width: {}\n"
"Odd TMEM Height: {}",
teximg.tmem_odd, teximg.cache_width, teximg.cache_height);
}
};
union TexImage3
{
BitField<0, 24, u32> image_base; // address in memory >> 5 (was 20 for GC)
u32 hex;
};
template <>
struct fmt::formatter<TexImage3>
{
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
template <typename FormatContext>
auto format(const TexImage3& teximg, FormatContext& ctx)
{
return format_to(ctx.out(), "Source address (32 byte aligned): 0x{:06X}",
teximg.image_base << 5);
}
};
union TexTLUT
{
BitField<0, 10, u32> tmem_offset;
BitField<10, 2, TLUTFormat> tlut_format;
u32 hex;
};
template <>
struct fmt::formatter<TexTLUT>
{
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
template <typename FormatContext>
auto format(const TexTLUT& tlut, FormatContext& ctx)
{
return format_to(ctx.out(), "Address: {:08x}\nFormat: {}", tlut.tmem_offset << 9,
tlut.tlut_format);
}
};
union ZTex1
{
@ -639,6 +861,16 @@ union ZTex2
BitField<2, 2, ZTexOp> op;
u32 hex;
};
template <>
struct fmt::formatter<ZTex2>
{
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
template <typename FormatContext>
auto format(const ZTex2& ztex2, FormatContext& ctx)
{
return format_to(ctx.out(), "Type: {}\nOperation: {}", ztex2.type, ztex2.op);
}
};
struct FourTexUnits
{
@ -686,6 +918,29 @@ union GenMode
u32 hex;
};
template <>
struct fmt::formatter<GenMode>
{
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
template <typename FormatContext>
auto format(const GenMode& mode, FormatContext& ctx)
{
return format_to(ctx.out(),
"Num tex gens: {}\n"
"Num color channels: {}\n"
"Unused bit: {}\n"
"Flat shading (unconfirmed): {}\n"
"Multisampling: {}\n"
"Num TEV stages: {}\n"
"Cull mode: {}\n"
"Num indirect stages: {}\n"
"ZFreeze: {}",
mode.numtexgens, mode.numcolchans, mode.unused,
mode.flat_shading ? "Yes" : "No", mode.multisampling ? "Yes" : "No",
mode.numtevstages, mode.cullmode, mode.numindstages,
mode.zfreeze ? "Yes" : "No");
}
};
enum class AspectRatioAdjustment
{
@ -708,6 +963,23 @@ union LPSize
BitField<22, 1, AspectRatioAdjustment> adjust_for_aspect_ratio;
u32 hex;
};
template <>
struct fmt::formatter<LPSize>
{
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
template <typename FormatContext>
auto format(const LPSize& lp, FormatContext& ctx)
{
return format_to(ctx.out(),
"Line size: {} ({:.3} pixels)\n"
"Point size: {} ({:.3} pixels)\n"
"Line offset: {}\n"
"Point offset: {}\n"
"Adjust line aspect ratio: {}",
lp.linesize, lp.linesize / 6.f, lp.pointsize, lp.pointsize / 6.f, lp.lineoff,
lp.pointoff, lp.adjust_for_aspect_ratio);
}
};
union X12Y12
{
@ -820,6 +1092,29 @@ union BlendMode
bool UseLogicOp() const;
};
template <>
struct fmt::formatter<BlendMode>
{
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
template <typename FormatContext>
auto format(const BlendMode& mode, FormatContext& ctx)
{
static constexpr std::array<const char*, 2> no_yes = {"No", "Yes"};
return format_to(ctx.out(),
"Enable: {}\n"
"Logic ops: {}\n"
"Dither: {}\n"
"Color write: {}\n"
"Alpha write: {}\n"
"Dest factor: {}\n"
"Source factor: {}\n"
"Subtract: {}\n"
"Logic mode: {}",
no_yes[mode.blendenable], no_yes[mode.logicopenable], no_yes[mode.dither],
no_yes[mode.colorupdate], no_yes[mode.alphaupdate], mode.dstfactor,
mode.srcfactor, no_yes[mode.subtract], mode.logicmode);
}
};
union FogParam0
{
@ -830,6 +1125,17 @@ union FogParam0
u32 hex;
float FloatValue() const;
};
template <>
struct fmt::formatter<FogParam0>
{
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
template <typename FormatContext>
auto format(const FogParam0& param, FormatContext& ctx)
{
return format_to(ctx.out(), "A value: {}\nMantissa: {}\nExponent: {}\nSign: {}",
param.FloatValue(), param.mant, param.exp, param.sign ? '-' : '+');
}
};
enum class FogProjection : u32
{
@ -878,6 +1184,19 @@ union FogParam3
u32 hex;
float FloatValue() const;
};
template <>
struct fmt::formatter<FogParam3>
{
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
template <typename FormatContext>
auto format(const FogParam3& param, FormatContext& ctx)
{
return format_to(ctx.out(),
"C value: {}\nMantissa: {}\nExponent: {}\nSign: {}\nProjection: {}\nFsel: {}",
param.FloatValue(), param.c_mant, param.c_exp, param.c_sign ? '-' : '+',
param.proj, param.fsel);
}
};
union FogRangeKElement
{
@ -900,6 +1219,28 @@ struct FogRangeParams
RangeBase Base;
FogRangeKElement K[5];
};
template <>
struct fmt::formatter<FogRangeParams::RangeBase>
{
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
template <typename FormatContext>
auto format(const FogRangeParams::RangeBase& range, FormatContext& ctx)
{
return format_to(ctx.out(), "Center: {}\nEnabled: {}", range.Center,
range.Enabled ? "Yes" : "No");
}
};
template <>
struct fmt::formatter<FogRangeKElement>
{
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
template <typename FormatContext>
auto format(const FogRangeKElement& range, FormatContext& ctx)
{
return format_to(ctx.out(), "High: {}\nLow: {}", range.HI, range.LO);
}
};
// final eq: ze = A/(B_MAG - (Zs>>B_SHF));
struct FogParams
{
@ -925,6 +1266,16 @@ struct FogParams
// amount to subtract from eyespacez after range adjustment
float GetC() const;
};
template <>
struct fmt::formatter<FogParams::FogColor>
{
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
template <typename FormatContext>
auto format(const FogParams::FogColor& color, FormatContext& ctx)
{
return format_to(ctx.out(), "Red: {}\nGreen: {}\nBlue: {}", color.r, color.g, color.b);
}
};
enum class CompareMode : u32
{
@ -953,6 +1304,20 @@ union ZMode
u32 hex;
};
template <>
struct fmt::formatter<ZMode>
{
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
template <typename FormatContext>
auto format(const ZMode& mode, FormatContext& ctx)
{
return format_to(ctx.out(),
"Enable test: {}\n"
"Compare function: {}\n"
"Enable updates: {}",
mode.testenable ? "Yes" : "No", mode.func, mode.updateenable ? "Yes" : "No");
}
};
union ConstantAlpha
{
@ -960,6 +1325,19 @@ union ConstantAlpha
BitField<8, 1, bool, u32> enable;
u32 hex;
};
template <>
struct fmt::formatter<ConstantAlpha>
{
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
template <typename FormatContext>
auto format(const ConstantAlpha& c, FormatContext& ctx)
{
return format_to(ctx.out(),
"Enable: {}\n"
"Alpha value: {:02x}",
c.enable ? "Yes" : "No", c.alpha);
}
};
union FieldMode
{
@ -967,6 +1345,17 @@ union FieldMode
BitField<0, 1, AspectRatioAdjustment> texLOD;
u32 hex;
};
template <>
struct fmt::formatter<FieldMode>
{
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
template <typename FormatContext>
auto format(const FieldMode& mode, FormatContext& ctx)
{
return format_to(ctx.out(), "Adjust vertex tex LOD computation to account for interlacing: {}",
mode.texLOD);
}
};
enum class FieldMaskState : u32
{
@ -986,6 +1375,16 @@ union FieldMask
BitField<1, 1, FieldMaskState> even;
u32 hex;
};
template <>
struct fmt::formatter<FieldMask>
{
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
template <typename FormatContext>
auto format(const FieldMask& mask, FormatContext& ctx)
{
return format_to(ctx.out(), "Odd field: {}\nEven field: {}", mask.odd, mask.even);
}
};
enum class PixelFormat : u32
{
@ -1038,6 +1437,20 @@ union PEControl
u32 hex;
};
template <>
struct fmt::formatter<PEControl>
{
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
template <typename FormatContext>
auto format(const PEControl& config, FormatContext& ctx)
{
return format_to(ctx.out(),
"EFB pixel format: {}\n"
"Depth format: {}\n"
"Early depth test: {}",
config.pixel_format, config.zformat, config.early_ztest ? "Yes" : "No");
}
};
// Texture coordinate stuff
@ -1051,6 +1464,25 @@ union TCInfo
BitField<19, 1, bool, u32> point_offset;
u32 hex;
};
template <>
struct fmt::formatter<TCInfo>
{
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
template <typename FormatContext>
auto format(const TCInfo& info, FormatContext& ctx)
{
return format_to(ctx.out(),
"Scale: {}\n"
"Range bias: {}\n"
"Cylindric wrap: {}\n"
"Use line offset: {} (s only)\n"
"Use point offset: {} (s only)",
info.scale_minus_1 + 1, info.range_bias ? "Yes" : "No",
info.cylindric_wrap ? "Yes" : "No", info.line_offset ? "Yes" : "No",
info.point_offset ? "Yes" : "No");
}
};
struct TCoordInfo
{
TCInfo s;
@ -1062,6 +1494,11 @@ enum class TevRegType : u32
Color = 0,
Constant = 1,
};
template <>
struct fmt::formatter<TevRegType> : EnumFormatter<TevRegType::Constant>
{
formatter() : EnumFormatter({"Color", "Constant"}) {}
};
struct TevReg
{
@ -1086,6 +1523,37 @@ struct TevReg
RA ra;
BG bg;
};
template <>
struct fmt::formatter<TevReg::RA>
{
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
template <typename FormatContext>
auto format(const TevReg::RA& ra, FormatContext& ctx)
{
return format_to(ctx.out(), "Type: {}\nAlpha: {:03x}\nRed: {:03x}", ra.type, ra.alpha, ra.red);
}
};
template <>
struct fmt::formatter<TevReg::BG>
{
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
template <typename FormatContext>
auto format(const TevReg::BG& bg, FormatContext& ctx)
{
return format_to(ctx.out(), "Type: {}\nGreen: {:03x}\nBlue: {:03x}", bg.type, bg.green,
bg.blue);
}
};
template <>
struct fmt::formatter<TevReg>
{
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
template <typename FormatContext>
auto format(const TevReg& reg, FormatContext& ctx)
{
return format_to(ctx.out(), "{}\n{}", reg.ra, reg.bg);
}
};
enum class KonstSel : u32
{
@ -1172,6 +1640,19 @@ union TevKSel
KonstSel getKC(int i) const { return i ? kcsel1.Value() : kcsel0.Value(); }
KonstSel getKA(int i) const { return i ? kasel1.Value() : kasel0.Value(); }
};
template <>
struct fmt::formatter<TevKSel>
{
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
template <typename FormatContext>
auto format(const TevKSel& ksel, FormatContext& ctx)
{
return format_to(ctx.out(),
"Swap 1: {}\nSwap 2: {}\nColor sel 0: {}\nAlpha sel 0: {}\n"
"Color sel 1: {}\nAlpha sel 1: {}",
ksel.swap1, ksel.swap2, ksel.kcsel0, ksel.kasel0, ksel.kcsel1, ksel.kasel1);
}
};
enum class AlphaTestOp : u32
{
@ -1245,6 +1726,20 @@ union AlphaTest
return AlphaTestResult::Undetermined;
}
};
template <>
struct fmt::formatter<AlphaTest>
{
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
template <typename FormatContext>
auto format(const AlphaTest& test, FormatContext& ctx)
{
return format_to(ctx.out(),
"Test 1: {} (ref: 0x{:02x})\n"
"Test 2: {} (ref: 0x{:02x})\n"
"Logic: {}\n",
test.comp0, test.ref0, test.comp1, test.ref1, test.logic);
}
};
enum class FrameToField : u32
{
@ -1286,6 +1781,60 @@ union UPE_Copy
return static_cast<EFBCopyFormat>(target_pixel_format / 2 + (target_pixel_format & 1) * 8);
}
};
template <>
struct fmt::formatter<UPE_Copy>
{
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
template <typename FormatContext>
auto format(const UPE_Copy& copy, FormatContext& ctx)
{
static constexpr std::array<const char*, 2> no_yes = {"No", "Yes"};
std::string_view clamp;
if (copy.clamp_top)
{
if (copy.clamp_bottom)
clamp = "Top and Bottom";
else
clamp = "Top only";
}
else
{
if (copy.clamp_bottom)
clamp = "Bottom only";
else
clamp = "None";
}
std::string_view gamma = "Invalid";
switch (copy.gamma)
{
case 0:
gamma = "1.0";
break;
case 1:
gamma = "1.7";
break;
case 2:
gamma = "2.2";
break;
}
return format_to(ctx.out(),
"Clamping: {}\n"
"Converting from RGB to YUV: {}\n"
"Target pixel format: {}\n"
"Gamma correction: {}\n"
"Mipmap filter: {}\n"
"Vertical scaling: {}\n"
"Clear: {}\n"
"Frame to field: {}\n"
"Copy to XFB: {}\n"
"Intensity format: {}\n"
"Automatic color conversion: {}",
clamp, no_yes[copy.yuv], copy.tp_realFormat(), gamma, no_yes[copy.half_scale],
no_yes[copy.scale_invert], no_yes[copy.clear], copy.frame_to_field,
no_yes[copy.copy_to_xfb], no_yes[copy.intensity_fmt], no_yes[copy.auto_conv]);
}
};
union CopyFilterCoefficients
{
@ -1321,6 +1870,16 @@ union BPU_PreloadTileInfo
BitField<15, 2, u32> type;
u32 hex;
};
template <>
struct fmt::formatter<BPU_PreloadTileInfo>
{
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
template <typename FormatContext>
auto format(const BPU_PreloadTileInfo& info, FormatContext& ctx)
{
return format_to(ctx.out(), "Type: {}\nCount: {}", info.type, info.count);
}
};
struct BPS_TmemConfig
{
@ -1420,4 +1979,4 @@ extern BPMemory bpmem;
void LoadBPReg(u32 value0);
void LoadBPRegPreprocess(u32 value0);
void GetBPRegInfo(const u8* data, std::string* name, std::string* desc);
std::pair<std::string, std::string> GetBPRegInfo(u8 cmd, u32 cmddata);

View File

@ -745,61 +745,59 @@ void LoadBPRegPreprocess(u32 value0)
}
}
void GetBPRegInfo(const u8* data, std::string* name, std::string* desc)
std::pair<std::string, std::string> GetBPRegInfo(u8 cmd, u32 cmddata)
{
const char* no_yes[2] = {"No", "Yes"};
// Macro to set the register name and make sure it was written correctly via compile time assertion
#define RegName(reg) ((void)(reg), #reg)
#define DescriptionlessReg(reg) std::make_pair(RegName(reg), "");
u8 cmd = data[0];
u32 cmddata = Common::swap32(data) & 0xFFFFFF;
switch (cmd)
{
// Macro to set the register name and make sure it was written correctly via compile time assertion
#define SetRegName(reg) \
*name = #reg; \
(void)(reg);
case BPMEM_GENMODE: // 0x00
SetRegName(BPMEM_GENMODE);
// TODO: Description
break;
return std::make_pair(RegName(BPMEM_GENMODE), fmt::to_string(GenMode{.hex = cmddata}));
case BPMEM_DISPLAYCOPYFILTER: // 0x01
case BPMEM_DISPLAYCOPYFILTER + 1:
case BPMEM_DISPLAYCOPYFILTER + 2:
case BPMEM_DISPLAYCOPYFILTER + 3:
// TODO: This is actually the sample pattern used for copies from an antialiased EFB
SetRegName(BPMEM_DISPLAYCOPYFILTER);
return DescriptionlessReg(BPMEM_DISPLAYCOPYFILTER);
// TODO: Description
break;
case 0x02: // 0x02
case 0x03: // 0x03
case 0x04: // 0x04
// TODO: same as BPMEM_DISPLAYCOPYFILTER
break;
case BPMEM_IND_MTXA: // 0x06
case BPMEM_IND_MTXA + 3:
case BPMEM_IND_MTXA + 6:
SetRegName(BPMEM_IND_MTXA);
// TODO: Description
break;
case BPMEM_IND_MTXB: // 0x07
case BPMEM_IND_MTXB + 3:
case BPMEM_IND_MTXB + 6:
SetRegName(BPMEM_IND_MTXB);
// TODO: Descriptio
break;
case BPMEM_IND_MTXC: // 0x08
case BPMEM_IND_MTXA + 3:
case BPMEM_IND_MTXB + 3:
case BPMEM_IND_MTXC + 3:
case BPMEM_IND_MTXA + 6:
case BPMEM_IND_MTXB + 6:
case BPMEM_IND_MTXC + 6:
SetRegName(BPMEM_IND_MTXC);
// TODO: Description
break;
{
const u32 matrix_num = (cmd - BPMEM_IND_MTXA) / 3;
const u32 matrix_col = (cmd - BPMEM_IND_MTXA) % 3;
// These all use the same structure, though the meaning is *slightly* different;
// for conveninece implement it only once
const s32 row0 = cmddata & 0x0007ff; // ma or mc or me
const s32 row1 = (cmddata & 0x3ff800) >> 11; // mb or md or mf
const u32 scale = (cmddata & 0xc00000) >> 22; // 2 bits of a 6-bit field for each column
const float row0f = static_cast<float>(row0) / (1 << 10);
const float row1f = static_cast<float>(row0) / (1 << 10);
return std::make_pair(fmt::format("BPMEM_IND_MTX{} Matrix {}", "ABC"[matrix_col], matrix_num),
fmt::format("Matrix {} column {} ({})\n"
"Row 0 (m{}): {} ({})\n"
"Row 1 (m{}): {} ({})\n"
"Scale bits: {} (shifted: {})",
matrix_num, matrix_col, "ABC"[matrix_col], "ace"[matrix_col],
row0f, row0, "bdf"[matrix_col], row1f, row1, scale,
scale << (2 * matrix_col)));
}
case BPMEM_IND_IMASK: // 0x0F
SetRegName(BPMEM_IND_IMASK);
return DescriptionlessReg(BPMEM_IND_IMASK);
// TODO: Description
break;
case BPMEM_IND_CMD: // 0x10
case BPMEM_IND_CMD + 1:
@ -817,49 +815,47 @@ void GetBPRegInfo(const u8* data, std::string* name, std::string* desc)
case BPMEM_IND_CMD + 13:
case BPMEM_IND_CMD + 14:
case BPMEM_IND_CMD + 15:
SetRegName(BPMEM_IND_CMD);
// TODO: Description
break;
return std::make_pair(fmt::format("BPMEM_IND_CMD command {}", cmd - BPMEM_IND_CMD),
fmt::to_string(TevStageIndirect{.fullhex = cmddata}));
case BPMEM_SCISSORTL: // 0x20
SetRegName(BPMEM_SCISSORTL);
// TODO: Description
break;
{
const X12Y12 top_left{.hex = cmddata};
return std::make_pair(RegName(BPMEM_SCISSORTL),
fmt::format("Scissor Top: {}\nScissor Left: {}", top_left.y, top_left.x));
}
case BPMEM_SCISSORBR: // 0x21
SetRegName(BPMEM_SCISSORBR);
// TODO: Description
break;
{
const X12Y12 bottom_right{.hex = cmddata};
return std::make_pair(
RegName(BPMEM_SCISSORBR),
fmt::format("Scissor Bottom: {}\nScissor Right: {}", bottom_right.y, bottom_right.x));
}
case BPMEM_LINEPTWIDTH: // 0x22
SetRegName(BPMEM_LINEPTWIDTH);
// TODO: Description
break;
return std::make_pair(RegName(BPMEM_LINEPTWIDTH), fmt::to_string(LPSize{.hex = cmddata}));
case BPMEM_PERF0_TRI: // 0x23
SetRegName(BPMEM_PERF0_TRI);
return DescriptionlessReg(BPMEM_PERF0_TRI);
// TODO: Description
break;
case BPMEM_PERF0_QUAD: // 0x24
SetRegName(BPMEM_PERF0_QUAD);
return DescriptionlessReg(BPMEM_PERF0_QUAD);
// TODO: Description
break;
case BPMEM_RAS1_SS0: // 0x25
SetRegName(BPMEM_RAS1_SS0);
// TODO: Description
break;
return std::make_pair(
RegName(BPMEM_RAS1_SS0),
fmt::format("Indirect texture stages 0 and 1:\n{}", TEXSCALE{.hex = cmddata}));
case BPMEM_RAS1_SS1: // 0x26
SetRegName(BPMEM_RAS1_SS1);
// TODO: Description
break;
return std::make_pair(
RegName(BPMEM_RAS1_SS1),
fmt::format("Indirect texture stages 2 and 3:\n{}", TEXSCALE{.hex = cmddata}));
case BPMEM_IREF: // 0x27
SetRegName(BPMEM_IREF);
// TODO: Description
break;
return std::make_pair(RegName(BPMEM_IREF), fmt::to_string(RAS1_IREF{.hex = cmddata}));
case BPMEM_TREF: // 0x28
case BPMEM_TREF + 1:
@ -869,9 +865,8 @@ void GetBPRegInfo(const u8* data, std::string* name, std::string* desc)
case BPMEM_TREF + 5:
case BPMEM_TREF + 6:
case BPMEM_TREF + 7:
SetRegName(BPMEM_TREF);
// TODO: Description
break;
return std::make_pair(fmt::format("BPMEM_TREF number {}", cmd - BPMEM_TREF),
fmt::to_string(TwoTevStageOrders{.hex = cmddata}));
case BPMEM_SU_SSIZE: // 0x30
case BPMEM_SU_SSIZE + 2:
@ -881,9 +876,8 @@ void GetBPRegInfo(const u8* data, std::string* name, std::string* desc)
case BPMEM_SU_SSIZE + 10:
case BPMEM_SU_SSIZE + 12:
case BPMEM_SU_SSIZE + 14:
SetRegName(BPMEM_SU_SSIZE);
// TODO: Description
break;
return std::make_pair(fmt::format("BPMEM_SU_SSIZE number {}", (cmd - BPMEM_SU_SSIZE) / 2),
fmt::format("S size info:\n{}", TCInfo{.hex = cmddata}));
case BPMEM_SU_TSIZE: // 0x31
case BPMEM_SU_TSIZE + 2:
@ -893,359 +887,283 @@ void GetBPRegInfo(const u8* data, std::string* name, std::string* desc)
case BPMEM_SU_TSIZE + 10:
case BPMEM_SU_TSIZE + 12:
case BPMEM_SU_TSIZE + 14:
SetRegName(BPMEM_SU_TSIZE);
// TODO: Description
break;
return std::make_pair(fmt::format("BPMEM_SU_TSIZE number {}", (cmd - BPMEM_SU_TSIZE) / 2),
fmt::format("T size info:\n{}", TCInfo{.hex = cmddata}));
case BPMEM_ZMODE: // 0x40
SetRegName(BPMEM_ZMODE);
// TODO: Description
break;
return std::make_pair(RegName(BPMEM_ZMODE), fmt::format("Z mode: {}", ZMode{.hex = cmddata}));
case BPMEM_BLENDMODE: // 0x41
{
SetRegName(BPMEM_BLENDMODE);
BlendMode mode;
mode.hex = cmddata;
*desc = fmt::format("Enable: {}\n"
"Logic ops: {}\n"
"Dither: {}\n"
"Color write: {}\n"
"Alpha write: {}\n"
"Dest factor: {}\n"
"Source factor: {}\n"
"Subtract: {}\n"
"Logic mode: {}\n",
no_yes[mode.blendenable], no_yes[mode.logicopenable], no_yes[mode.dither],
no_yes[mode.colorupdate], no_yes[mode.alphaupdate], mode.dstfactor,
mode.srcfactor, no_yes[mode.subtract], mode.logicmode);
}
break;
return std::make_pair(RegName(BPMEM_BLENDMODE), fmt::to_string(BlendMode{.hex = cmddata}));
case BPMEM_CONSTANTALPHA: // 0x42
SetRegName(BPMEM_CONSTANTALPHA);
// TODO: Description
break;
return std::make_pair(RegName(BPMEM_CONSTANTALPHA),
fmt::to_string(ConstantAlpha{.hex = cmddata}));
case BPMEM_ZCOMPARE: // 0x43
{
SetRegName(BPMEM_ZCOMPARE);
PEControl config;
config.hex = cmddata;
*desc = fmt::format("EFB pixel format: {}\n"
"Depth format: {}\n"
"Early depth test: {}\n",
config.pixel_format, config.zformat, no_yes[config.early_ztest]);
}
break;
return std::make_pair(RegName(BPMEM_ZCOMPARE), fmt::to_string(PEControl{.hex = cmddata}));
case BPMEM_FIELDMASK: // 0x44
SetRegName(BPMEM_FIELDMASK);
// TODO: Description
break;
return std::make_pair(RegName(BPMEM_FIELDMASK), fmt::to_string(FieldMask{.hex = cmddata}));
case BPMEM_SETDRAWDONE: // 0x45
SetRegName(BPMEM_SETDRAWDONE);
return DescriptionlessReg(BPMEM_SETDRAWDONE);
// TODO: Description
break;
case BPMEM_BUSCLOCK0: // 0x46
SetRegName(BPMEM_BUSCLOCK0);
return DescriptionlessReg(BPMEM_BUSCLOCK0);
// TODO: Description
break;
case BPMEM_PE_TOKEN_ID: // 0x47
SetRegName(BPMEM_PE_TOKEN_ID);
return DescriptionlessReg(BPMEM_PE_TOKEN_ID);
// TODO: Description
break;
case BPMEM_PE_TOKEN_INT_ID: // 0x48
SetRegName(BPMEM_PE_TOKEN_INT_ID);
return DescriptionlessReg(BPMEM_PE_TOKEN_INT_ID);
// TODO: Description
break;
case BPMEM_EFB_TL: // 0x49
{
SetRegName(BPMEM_EFB_TL);
X10Y10 left_top;
left_top.hex = cmddata;
*desc = fmt::format("Left: {}\nTop: {}", u32(left_top.x), u32(left_top.y));
const X10Y10 left_top{.hex = cmddata};
return std::make_pair(RegName(BPMEM_EFB_TL),
fmt::format("EFB Left: {}\nEFB Top: {}", left_top.x, left_top.y));
}
break;
case BPMEM_EFB_WH: // 0x4A
{
SetRegName(BPMEM_EFB_WH);
X10Y10 width_height;
width_height.hex = cmddata;
*desc = fmt::format("Width: {}\nHeight: {}", width_height.x + 1, width_height.y + 1);
const X10Y10 width_height{.hex = cmddata};
return std::make_pair(
RegName(BPMEM_EFB_WH),
fmt::format("EFB Width: {}\nEFB Height: {}", width_height.x + 1, width_height.y + 1));
}
break;
case BPMEM_EFB_ADDR: // 0x4B
SetRegName(BPMEM_EFB_ADDR);
*desc = fmt::format("Target address (32 byte aligned): 0x{:06X}", cmddata << 5);
break;
return std::make_pair(
RegName(BPMEM_EFB_ADDR),
fmt::format("EFB Target address (32 byte aligned): 0x{:06X}", cmddata << 5));
case BPMEM_MIPMAP_STRIDE: // 0x4D
SetRegName(BPMEM_MIPMAP_STRIDE);
return DescriptionlessReg(BPMEM_MIPMAP_STRIDE);
// TODO: Description
break;
case BPMEM_COPYYSCALE: // 0x4E
SetRegName(BPMEM_COPYYSCALE);
*desc = fmt::format("Scaling factor (XFB copy only): 0x{:X} ({} or inverted {})", cmddata,
static_cast<float>(cmddata) / 256.f, 256.f / static_cast<float>(cmddata));
break;
return std::make_pair(
RegName(BPMEM_COPYYSCALE),
fmt::format("Y scaling factor (XFB copy only): 0x{:X} ({}, reciprocal {})", cmddata,
static_cast<float>(cmddata) / 256.f, 256.f / static_cast<float>(cmddata)));
case BPMEM_CLEAR_AR: // 0x4F
SetRegName(BPMEM_CLEAR_AR);
*desc = fmt::format("Alpha: 0x{:02X}\nRed: 0x{:02X}", (cmddata & 0xFF00) >> 8, cmddata & 0xFF);
break;
return std::make_pair(RegName(BPMEM_CLEAR_AR),
fmt::format("Clear color alpha: 0x{:02X}\nClear color red: 0x{:02X}",
(cmddata & 0xFF00) >> 8, cmddata & 0xFF));
case BPMEM_CLEAR_GB: // 0x50
SetRegName(BPMEM_CLEAR_GB);
*desc = fmt::format("Green: 0x{:02X}\nBlue: 0x{:02X}", (cmddata & 0xFF00) >> 8, cmddata & 0xFF);
break;
return std::make_pair(RegName(BPMEM_CLEAR_GB),
fmt::format("Clear color green: 0x{:02X}\nClear color blue: 0x{:02X}",
(cmddata & 0xFF00) >> 8, cmddata & 0xFF));
case BPMEM_CLEAR_Z: // 0x51
SetRegName(BPMEM_CLEAR_Z);
*desc = fmt::format("Z value: 0x{:06X}", cmddata);
break;
return std::make_pair(RegName(BPMEM_CLEAR_Z), fmt::format("Clear Z value: 0x{:06X}", cmddata));
case BPMEM_TRIGGER_EFB_COPY: // 0x52
{
SetRegName(BPMEM_TRIGGER_EFB_COPY);
UPE_Copy copy;
copy.Hex = cmddata;
*desc = fmt::format(
"Clamping: {}\n"
"Converting from RGB to YUV: {}\n"
"Target pixel format: 0x{:X}\n"
"Gamma correction: {}\n"
"Mipmap filter: {}\n"
"Vertical scaling: {}\n"
"Clear: {}\n"
"Frame to field: {}\n"
"Copy to XFB: {}\n"
"Intensity format: {}\n"
"Automatic color conversion: {}",
(copy.clamp_top && copy.clamp_bottom) ?
"Top and Bottom" :
(copy.clamp_top) ? "Top only" : (copy.clamp_bottom) ? "Bottom only" : "None",
no_yes[copy.yuv], static_cast<int>(copy.tp_realFormat()),
(copy.gamma == 0) ?
"1.0" :
(copy.gamma == 1) ? "1.7" : (copy.gamma == 2) ? "2.2" : "Invalid value 0x3?",
no_yes[copy.half_scale], no_yes[copy.scale_invert], no_yes[copy.clear], copy.frame_to_field,
no_yes[copy.copy_to_xfb], no_yes[copy.intensity_fmt], no_yes[copy.auto_conv]);
}
break;
return std::make_pair(RegName(BPMEM_TRIGGER_EFB_COPY),
fmt::to_string(UPE_Copy{.Hex = cmddata}));
case BPMEM_COPYFILTER0: // 0x53
SetRegName(BPMEM_COPYFILTER0);
// TODO: Description
break;
{
const u32 w0 = (cmddata & 0x00003f);
const u32 w1 = (cmddata & 0x000fc0) >> 6;
const u32 w2 = (cmddata & 0x03f000) >> 12;
const u32 w3 = (cmddata & 0xfc0000) >> 18;
return std::make_pair(RegName(BPMEM_COPYFILTER0),
fmt::format("w0: {}\nw1: {}\nw2: {}\nw3: {}", w0, w1, w2, w3));
}
case BPMEM_COPYFILTER1: // 0x54
SetRegName(BPMEM_COPYFILTER1);
// TODO: Description
break;
{
const u32 w4 = (cmddata & 0x00003f);
const u32 w5 = (cmddata & 0x000fc0) >> 6;
const u32 w6 = (cmddata & 0x03f000) >> 12;
// There is no w7
return std::make_pair(RegName(BPMEM_COPYFILTER1),
fmt::format("w4: {}\nw5: {}\nw6: {}", w4, w5, w6));
}
case BPMEM_CLEARBBOX1: // 0x55
SetRegName(BPMEM_CLEARBBOX1);
return DescriptionlessReg(BPMEM_CLEARBBOX1);
// TODO: Description
break;
case BPMEM_CLEARBBOX2: // 0x56
SetRegName(BPMEM_CLEARBBOX2);
return DescriptionlessReg(BPMEM_CLEARBBOX2);
// TODO: Description
break;
case BPMEM_CLEAR_PIXEL_PERF: // 0x57
SetRegName(BPMEM_CLEAR_PIXEL_PERF);
return DescriptionlessReg(BPMEM_CLEAR_PIXEL_PERF);
// TODO: Description
break;
case BPMEM_REVBITS: // 0x58
SetRegName(BPMEM_REVBITS);
return DescriptionlessReg(BPMEM_REVBITS);
// TODO: Description
break;
case BPMEM_SCISSOROFFSET: // 0x59
SetRegName(BPMEM_SCISSOROFFSET);
// TODO: Description
break;
{
const X10Y10 xy{.hex = cmddata};
return std::make_pair(RegName(BPMEM_EFB_TL),
fmt::format("Scissor X offset: {}\nScissor Y offset: {}", xy.x, xy.y));
}
case BPMEM_PRELOAD_ADDR: // 0x60
SetRegName(BPMEM_PRELOAD_ADDR);
return DescriptionlessReg(BPMEM_PRELOAD_ADDR);
// TODO: Description
break;
case BPMEM_PRELOAD_TMEMEVEN: // 0x61
SetRegName(BPMEM_PRELOAD_TMEMEVEN);
return DescriptionlessReg(BPMEM_PRELOAD_TMEMEVEN);
// TODO: Description
break;
case BPMEM_PRELOAD_TMEMODD: // 0x62
SetRegName(BPMEM_PRELOAD_TMEMODD);
return DescriptionlessReg(BPMEM_PRELOAD_TMEMODD);
// TODO: Description
break;
case BPMEM_PRELOAD_MODE: // 0x63
SetRegName(BPMEM_PRELOAD_MODE);
// TODO: Description
break;
return std::make_pair(RegName(BPMEM_PRELOAD_MODE),
fmt::to_string(BPU_PreloadTileInfo{.hex = cmddata}));
case BPMEM_LOADTLUT0: // 0x64
SetRegName(BPMEM_LOADTLUT0);
return DescriptionlessReg(BPMEM_LOADTLUT0);
// TODO: Description
break;
case BPMEM_LOADTLUT1: // 0x65
SetRegName(BPMEM_LOADTLUT1);
return DescriptionlessReg(BPMEM_LOADTLUT1);
// TODO: Description
break;
case BPMEM_TEXINVALIDATE: // 0x66
SetRegName(BPMEM_TEXINVALIDATE);
return DescriptionlessReg(BPMEM_TEXINVALIDATE);
// TODO: Description
break;
case BPMEM_PERF1: // 0x67
SetRegName(BPMEM_PERF1);
return DescriptionlessReg(BPMEM_PERF1);
// TODO: Description
break;
case BPMEM_FIELDMODE: // 0x68
SetRegName(BPMEM_FIELDMODE);
// TODO: Description
break;
return std::make_pair(RegName(BPMEM_FIELDMODE), fmt::to_string(FieldMode{.hex = cmddata}));
case BPMEM_BUSCLOCK1: // 0x69
SetRegName(BPMEM_BUSCLOCK1);
return DescriptionlessReg(BPMEM_BUSCLOCK1);
// TODO: Description
break;
case BPMEM_TX_SETMODE0: // 0x80
case BPMEM_TX_SETMODE0 + 1:
case BPMEM_TX_SETMODE0 + 2:
case BPMEM_TX_SETMODE0 + 3:
SetRegName(BPMEM_TX_SETMODE0);
// TODO: Description
break;
return std::make_pair(fmt::format("BPMEM_TX_SETMODE0 Texture Unit {}", cmd - BPMEM_TX_SETMODE0),
fmt::to_string(TexMode0{.hex = cmddata}));
case BPMEM_TX_SETMODE1: // 0x84
case BPMEM_TX_SETMODE1 + 1:
case BPMEM_TX_SETMODE1 + 2:
case BPMEM_TX_SETMODE1 + 3:
SetRegName(BPMEM_TX_SETMODE1);
// TODO: Description
break;
return std::make_pair(fmt::format("BPMEM_TX_SETMODE1 Texture Unit {}", cmd - BPMEM_TX_SETMODE1),
fmt::to_string(TexMode1{.hex = cmddata}));
case BPMEM_TX_SETIMAGE0: // 0x88
case BPMEM_TX_SETIMAGE0 + 1:
case BPMEM_TX_SETIMAGE0 + 2:
case BPMEM_TX_SETIMAGE0 + 3:
case BPMEM_TX_SETIMAGE0_4: // 0xA8
case BPMEM_TX_SETIMAGE0_4 + 1:
case BPMEM_TX_SETIMAGE0_4 + 2:
case BPMEM_TX_SETIMAGE0_4 + 3:
{
SetRegName(BPMEM_TX_SETIMAGE0);
int texnum =
(cmd < BPMEM_TX_SETIMAGE0_4) ? cmd - BPMEM_TX_SETIMAGE0 : cmd - BPMEM_TX_SETIMAGE0_4 + 4;
TexImage0 teximg;
teximg.hex = cmddata;
*desc = fmt::format("Texture Unit: {}\n"
"Width: {}\n"
"Height: {}\n"
"Format: {}\n",
texnum, u32(teximg.width) + 1, u32(teximg.height) + 1, teximg.format);
}
break;
return std::make_pair(
fmt::format("BPMEM_TX_SETIMAGE0 Texture Unit {}", cmd - BPMEM_TX_SETIMAGE0),
fmt::to_string(TexImage0{.hex = cmddata}));
case BPMEM_TX_SETIMAGE1: // 0x8C
case BPMEM_TX_SETIMAGE1 + 1:
case BPMEM_TX_SETIMAGE1 + 2:
case BPMEM_TX_SETIMAGE1 + 3:
case BPMEM_TX_SETIMAGE1_4: // 0xAC
case BPMEM_TX_SETIMAGE1_4 + 1:
case BPMEM_TX_SETIMAGE1_4 + 2:
case BPMEM_TX_SETIMAGE1_4 + 3:
{
SetRegName(BPMEM_TX_SETIMAGE1);
int texnum =
(cmd < BPMEM_TX_SETIMAGE1_4) ? cmd - BPMEM_TX_SETIMAGE1 : cmd - BPMEM_TX_SETIMAGE1_4 + 4;
TexImage1 teximg;
teximg.hex = cmddata;
*desc = fmt::format("Texture Unit: {}\n"
"Even TMEM Offset: {:x}\n"
"Even TMEM Width: {}\n"
"Even TMEM Height: {}\n"
"Cache is manually managed: {}\n",
texnum, u32(teximg.tmem_even), u32(teximg.cache_width),
u32(teximg.cache_height), no_yes[teximg.cache_manually_managed]);
}
break;
return std::make_pair(
fmt::format("BPMEM_TX_SETIMAGE1 Texture Unit {}", cmd - BPMEM_TX_SETIMAGE1),
fmt::to_string(TexImage1{.hex = cmddata}));
case BPMEM_TX_SETIMAGE2: // 0x90
case BPMEM_TX_SETIMAGE2 + 1:
case BPMEM_TX_SETIMAGE2 + 2:
case BPMEM_TX_SETIMAGE2 + 3:
case BPMEM_TX_SETIMAGE2_4: // 0xB0
case BPMEM_TX_SETIMAGE2_4 + 1:
case BPMEM_TX_SETIMAGE2_4 + 2:
case BPMEM_TX_SETIMAGE2_4 + 3:
{
SetRegName(BPMEM_TX_SETIMAGE2);
int texnum =
(cmd < BPMEM_TX_SETIMAGE2_4) ? cmd - BPMEM_TX_SETIMAGE2 : cmd - BPMEM_TX_SETIMAGE2_4 + 4;
TexImage2 teximg;
teximg.hex = cmddata;
*desc = fmt::format("Texture Unit: {}\n"
"Odd TMEM Offset: {:x}\n"
"Odd TMEM Width: {}\n"
"Odd TMEM Height: {}\n",
texnum, u32(teximg.tmem_odd), u32(teximg.cache_width),
u32(teximg.cache_height));
}
break;
return std::make_pair(
fmt::format("BPMEM_TX_SETIMAGE2 Texture Unit {}", cmd - BPMEM_TX_SETIMAGE2),
fmt::to_string(TexImage2{.hex = cmddata}));
case BPMEM_TX_SETIMAGE3: // 0x94
case BPMEM_TX_SETIMAGE3 + 1:
case BPMEM_TX_SETIMAGE3 + 2:
case BPMEM_TX_SETIMAGE3 + 3:
case BPMEM_TX_SETIMAGE3_4: // 0xB4
case BPMEM_TX_SETIMAGE3_4 + 1:
case BPMEM_TX_SETIMAGE3_4 + 2:
case BPMEM_TX_SETIMAGE3_4 + 3:
{
SetRegName(BPMEM_TX_SETIMAGE3);
int texnum =
(cmd < BPMEM_TX_SETIMAGE3_4) ? cmd - BPMEM_TX_SETIMAGE3 : cmd - BPMEM_TX_SETIMAGE3_4 + 4;
TexImage3 teximg;
teximg.hex = cmddata;
*desc = fmt::format("Texture {} source address (32 byte aligned): 0x{:06X}", texnum,
teximg.image_base << 5);
}
break;
return std::make_pair(
fmt::format("BPMEM_TX_SETIMAGE3 Texture Unit {}", cmd - BPMEM_TX_SETIMAGE3),
fmt::to_string(TexImage3{.hex = cmddata}));
case BPMEM_TX_SETTLUT: // 0x98
case BPMEM_TX_SETTLUT + 1:
case BPMEM_TX_SETTLUT + 2:
case BPMEM_TX_SETTLUT + 3:
return std::make_pair(fmt::format("BPMEM_TX_SETTLUT Texture Unit {}", cmd - BPMEM_TX_SETTLUT),
fmt::to_string(TexTLUT{.hex = cmddata}));
case BPMEM_TX_SETMODE0_4: // 0xA0
case BPMEM_TX_SETMODE0_4 + 1:
case BPMEM_TX_SETMODE0_4 + 2:
case BPMEM_TX_SETMODE0_4 + 3:
return std::make_pair(
fmt::format("BPMEM_TX_SETMODE0_4 Texture Unit {}", cmd - BPMEM_TX_SETMODE0_4 + 4),
fmt::to_string(TexMode0{.hex = cmddata}));
case BPMEM_TX_SETMODE1_4: // 0xA4
case BPMEM_TX_SETMODE1_4 + 1:
case BPMEM_TX_SETMODE1_4 + 2:
case BPMEM_TX_SETMODE1_4 + 3:
return std::make_pair(
fmt::format("BPMEM_TX_SETMODE1_4 Texture Unit {}", cmd - BPMEM_TX_SETMODE1_4 + 4),
fmt::to_string(TexMode1{.hex = cmddata}));
case BPMEM_TX_SETIMAGE0_4: // 0xA8
case BPMEM_TX_SETIMAGE0_4 + 1:
case BPMEM_TX_SETIMAGE0_4 + 2:
case BPMEM_TX_SETIMAGE0_4 + 3:
return std::make_pair(
fmt::format("BPMEM_TX_SETIMAGE0_4 Texture Unit {}", cmd - BPMEM_TX_SETIMAGE0_4 + 4),
fmt::to_string(TexImage0{.hex = cmddata}));
case BPMEM_TX_SETIMAGE1_4: // 0xAC
case BPMEM_TX_SETIMAGE1_4 + 1:
case BPMEM_TX_SETIMAGE1_4 + 2:
case BPMEM_TX_SETIMAGE1_4 + 3:
return std::make_pair(
fmt::format("BPMEM_TX_SETIMAGE1_4 Texture Unit {}", cmd - BPMEM_TX_SETIMAGE1_4 + 4),
fmt::to_string(TexImage1{.hex = cmddata}));
case BPMEM_TX_SETIMAGE2_4: // 0xB0
case BPMEM_TX_SETIMAGE2_4 + 1:
case BPMEM_TX_SETIMAGE2_4 + 2:
case BPMEM_TX_SETIMAGE2_4 + 3:
return std::make_pair(
fmt::format("BPMEM_TX_SETIMAGE2_4 Texture Unit {}", cmd - BPMEM_TX_SETIMAGE2_4 + 4),
fmt::to_string(TexImage2{.hex = cmddata}));
case BPMEM_TX_SETIMAGE3_4: // 0xB4
case BPMEM_TX_SETIMAGE3_4 + 1:
case BPMEM_TX_SETIMAGE3_4 + 2:
case BPMEM_TX_SETIMAGE3_4 + 3:
return std::make_pair(
fmt::format("BPMEM_TX_SETIMAGE3_4 Texture Unit {}", cmd - BPMEM_TX_SETIMAGE3_4 + 4),
fmt::to_string(TexImage3{.hex = cmddata}));
case BPMEM_TX_SETTLUT_4: // 0xB8
case BPMEM_TX_SETTLUT_4 + 1:
case BPMEM_TX_SETTLUT_4 + 2:
case BPMEM_TX_SETTLUT_4 + 3:
SetRegName(BPMEM_TX_SETTLUT);
// TODO: Description
break;
return std::make_pair(
fmt::format("BPMEM_TX_SETTLUT_4 Texture Unit {}", cmd - BPMEM_TX_SETTLUT_4 + 4),
fmt::to_string(TexTLUT{.hex = cmddata}));
case BPMEM_TEV_COLOR_ENV: // 0xC0
case BPMEM_TEV_COLOR_ENV + 2:
case BPMEM_TEV_COLOR_ENV + 4:
case BPMEM_TEV_COLOR_ENV + 6:
case BPMEM_TEV_COLOR_ENV + 8:
case BPMEM_TEV_COLOR_ENV + 10:
case BPMEM_TEV_COLOR_ENV + 12:
@ -1258,24 +1176,9 @@ void GetBPRegInfo(const u8* data, std::string* name, std::string* desc)
case BPMEM_TEV_COLOR_ENV + 26:
case BPMEM_TEV_COLOR_ENV + 28:
case BPMEM_TEV_COLOR_ENV + 30:
{
SetRegName(BPMEM_TEV_COLOR_ENV);
TevStageCombiner::ColorCombiner cc;
cc.hex = cmddata;
*desc = fmt::format("Tev stage: {}\n"
"a: {}\n"
"b: {}\n"
"c: {}\n"
"d: {}\n"
"Bias: {}\n"
"Op: {}\n"
"Clamp: {}\n"
"Scale factor: {}\n"
"Dest: {}\n",
(data[0] - BPMEM_TEV_COLOR_ENV) / 2, cc.a, cc.b, cc.c, cc.d, cc.bias, cc.op,
no_yes[cc.clamp], cc.scale, cc.dest);
break;
}
return std::make_pair(
fmt::format("BPMEM_TEV_COLOR_ENV Tev stage {}", (cmd - BPMEM_TEV_COLOR_ENV) / 2),
fmt::to_string(TevStageCombiner::ColorCombiner{.hex = cmddata}));
case BPMEM_TEV_ALPHA_ENV: // 0xC1
case BPMEM_TEV_ALPHA_ENV + 2:
@ -1293,99 +1196,65 @@ void GetBPRegInfo(const u8* data, std::string* name, std::string* desc)
case BPMEM_TEV_ALPHA_ENV + 26:
case BPMEM_TEV_ALPHA_ENV + 28:
case BPMEM_TEV_ALPHA_ENV + 30:
{
SetRegName(BPMEM_TEV_ALPHA_ENV);
TevStageCombiner::AlphaCombiner ac;
ac.hex = cmddata;
*desc = fmt::format("Tev stage: {}\n"
"a: {}\n"
"b: {}\n"
"c: {}\n"
"d: {}\n"
"Bias: {}\n"
"Op: {}\n"
"Clamp: {}\n"
"Scale factor: {}\n"
"Dest: {}\n"
"Ras sel: {}\n"
"Tex sel: {}\n",
(data[0] - BPMEM_TEV_ALPHA_ENV) / 2, ac.a, ac.b, ac.c, ac.d, ac.bias, ac.op,
no_yes[ac.clamp], ac.scale, ac.dest, ac.rswap.Value(), ac.tswap.Value());
break;
}
return std::make_pair(
fmt::format("BPMEM_TEV_ALPHA_ENV Tev stage {}", (cmd - BPMEM_TEV_ALPHA_ENV) / 2),
fmt::to_string(TevStageCombiner::AlphaCombiner{.hex = cmddata}));
case BPMEM_TEV_COLOR_RA: // 0xE0
case BPMEM_TEV_COLOR_RA + 2: // 0xE2
case BPMEM_TEV_COLOR_RA + 4: // 0xE4
case BPMEM_TEV_COLOR_RA + 6: // 0xE6
SetRegName(BPMEM_TEV_COLOR_RA);
// TODO: Description
break;
return std::make_pair(
fmt::format("BPMEM_TEV_COLOR_RA Tev register {}", (cmd - BPMEM_TEV_COLOR_RA) / 2),
fmt::to_string(TevReg::RA{.hex = cmddata}));
case BPMEM_TEV_COLOR_BG: // 0xE1
case BPMEM_TEV_COLOR_BG + 2: // 0xE3
case BPMEM_TEV_COLOR_BG + 4: // 0xE5
case BPMEM_TEV_COLOR_BG + 6: // 0xE7
SetRegName(BPMEM_TEV_COLOR_BG);
// TODO: Description
break;
return std::make_pair(
fmt::format("BPMEM_TEV_COLOR_BG Tev register {}", (cmd - BPMEM_TEV_COLOR_BG) / 2),
fmt::to_string(TevReg::BG{.hex = cmddata}));
case BPMEM_FOGRANGE: // 0xE8
return std::make_pair("BPMEM_FOGRANGE Base",
fmt::to_string(FogRangeParams::RangeBase{.hex = cmddata}));
case BPMEM_FOGRANGE + 1:
case BPMEM_FOGRANGE + 2:
case BPMEM_FOGRANGE + 3:
case BPMEM_FOGRANGE + 4:
case BPMEM_FOGRANGE + 5:
SetRegName(BPMEM_FOGRANGE);
// TODO: Description
break;
return std::make_pair(fmt::format("BPMEM_FOGRANGE K element {}", cmd - BPMEM_FOGRANGE),
fmt::to_string(FogRangeKElement{.HEX = cmddata}));
case BPMEM_FOGPARAM0: // 0xEE
SetRegName(BPMEM_FOGPARAM0);
// TODO: Description
break;
return std::make_pair(RegName(BPMEM_FOGPARAM0), fmt::to_string(FogParam0{.hex = cmddata}));
case BPMEM_FOGBMAGNITUDE: // 0xEF
SetRegName(BPMEM_FOGBMAGNITUDE);
return DescriptionlessReg(BPMEM_FOGBMAGNITUDE);
// TODO: Description
break;
case BPMEM_FOGBEXPONENT: // 0xF0
SetRegName(BPMEM_FOGBEXPONENT);
return DescriptionlessReg(BPMEM_FOGBEXPONENT);
// TODO: Description
break;
case BPMEM_FOGPARAM3: // 0xF1
SetRegName(BPMEM_FOGPARAM3);
// TODO: Description
break;
return std::make_pair(RegName(BPMEM_FOGPARAM3), fmt::to_string(FogParam3{.hex = cmddata}));
case BPMEM_FOGCOLOR: // 0xF2
SetRegName(BPMEM_FOGCOLOR);
// TODO: Description
break;
return std::make_pair(RegName(BPMEM_FOGCOLOR),
fmt::to_string(FogParams::FogColor{.hex = cmddata}));
case BPMEM_ALPHACOMPARE: // 0xF3
{
SetRegName(BPMEM_ALPHACOMPARE);
AlphaTest test;
test.hex = cmddata;
*desc = fmt::format("Test 1: {} (ref: 0x{:02x})\n"
"Test 2: {} (ref: 0x{:02x})\n"
"Logic: {}\n",
test.comp0, test.ref0.Value(), test.comp1, test.ref1.Value(), test.logic);
break;
}
return std::make_pair(RegName(BPMEM_ALPHACOMPARE), fmt::to_string(AlphaTest{.hex = cmddata}));
case BPMEM_BIAS: // 0xF4
SetRegName(BPMEM_BIAS);
return DescriptionlessReg(BPMEM_BIAS);
// TODO: Description
break;
case BPMEM_ZTEX2: // 0xF5
SetRegName(BPMEM_ZTEX2);
// TODO: Description
break;
return std::make_pair(RegName(BPMEM_ZTEX2), fmt::to_string(ZTex2{.hex = cmddata}));
case BPMEM_TEV_KSEL: // 0xF6
case BPMEM_TEV_KSEL + 1:
@ -1395,11 +1264,20 @@ void GetBPRegInfo(const u8* data, std::string* name, std::string* desc)
case BPMEM_TEV_KSEL + 5:
case BPMEM_TEV_KSEL + 6:
case BPMEM_TEV_KSEL + 7:
SetRegName(BPMEM_TEV_KSEL);
// TODO: Description
break;
return std::make_pair(fmt::format("BPMEM_TEV_KSEL number {}", cmd - BPMEM_TEV_KSEL),
fmt::to_string(TevKSel{.hex = cmddata}));
#undef SetRegName
case BPMEM_BP_MASK: // 0xFE
return std::make_pair(RegName(BPMEM_BP_MASK),
fmt::format("The next BP command will only update these bits; others "
"will retain their prior values: {:06x}",
cmddata));
default:
return std::make_pair(fmt::format("Unknown BP Reg: {:02x}={:06x}", cmd, cmddata), "");
#undef DescriptionlessReg
#undef RegName
}
}