Merge pull request #12286 from Pokechu22/more-bp-register-descriptions

Add descriptions for more BP registers
This commit is contained in:
Tilka 2023-11-12 07:59:32 +00:00 committed by GitHub
commit e7b922ee62
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 122 additions and 74 deletions

View File

@ -605,7 +605,7 @@ void FifoPlayer::ClearEfb()
wh.x = EFB_WIDTH - 1; wh.x = EFB_WIDTH - 1;
wh.y = EFB_HEIGHT - 1; wh.y = EFB_HEIGHT - 1;
LoadBPReg(BPMEM_EFB_WH, wh.hex); LoadBPReg(BPMEM_EFB_WH, wh.hex);
LoadBPReg(BPMEM_MIPMAP_STRIDE, 0x140); LoadBPReg(BPMEM_EFB_STRIDE, 0x140);
// The clear color and Z value have already been loaded via LoadRegisters() // The clear color and Z value have already been loaded via LoadRegisters()
LoadBPReg(BPMEM_EFB_ADDR, 0); LoadBPReg(BPMEM_EFB_ADDR, 0);
UPE_Copy copy = bpmem.triggerEFBCopy; UPE_Copy copy = bpmem.triggerEFBCopy;
@ -627,7 +627,7 @@ void FifoPlayer::ClearEfb()
// probably a good idea. // probably a good idea.
LoadBPReg(BPMEM_EFB_TL, m_File->GetBPMem()[BPMEM_EFB_TL]); LoadBPReg(BPMEM_EFB_TL, m_File->GetBPMem()[BPMEM_EFB_TL]);
LoadBPReg(BPMEM_EFB_WH, m_File->GetBPMem()[BPMEM_EFB_WH]); LoadBPReg(BPMEM_EFB_WH, m_File->GetBPMem()[BPMEM_EFB_WH]);
LoadBPReg(BPMEM_MIPMAP_STRIDE, m_File->GetBPMem()[BPMEM_MIPMAP_STRIDE]); LoadBPReg(BPMEM_EFB_STRIDE, m_File->GetBPMem()[BPMEM_EFB_STRIDE]);
LoadBPReg(BPMEM_EFB_ADDR, m_File->GetBPMem()[BPMEM_EFB_ADDR]); LoadBPReg(BPMEM_EFB_ADDR, m_File->GetBPMem()[BPMEM_EFB_ADDR]);
// Wait for the EFB copy to finish. That way, the EFB copy (which will be performed at a later // Wait for the EFB copy to finish. That way, the EFB copy (which will be performed at a later
// time) won't clobber any memory updates. // time) won't clobber any memory updates.

View File

@ -231,7 +231,7 @@ static void SetSpans(int sBlkSize, int tBlkSize, s32* tSpan, s32* sBlkSpan, s32*
*tBlkSpan = ((640 * tBlkSize) - alignedWidth) * *tBlkSpan = ((640 * tBlkSize) - alignedWidth) *
readStride; // bytes to advance src pointer after each row of blocks readStride; // bytes to advance src pointer after each row of blocks
*writeStride = bpmem.copyMipMapStrideChannels * 32; *writeStride = bpmem.copyDestStride << 5;
} }
#define ENCODE_LOOP_BLOCKS \ #define ENCODE_LOOP_BLOCKS \

View File

@ -56,7 +56,7 @@ enum
BPMEM_EFB_TL = 0x49, BPMEM_EFB_TL = 0x49,
BPMEM_EFB_WH = 0x4A, BPMEM_EFB_WH = 0x4A,
BPMEM_EFB_ADDR = 0x4B, BPMEM_EFB_ADDR = 0x4B,
BPMEM_MIPMAP_STRIDE = 0x4D, BPMEM_EFB_STRIDE = 0x4D,
BPMEM_COPYYSCALE = 0x4E, BPMEM_COPYYSCALE = 0x4E,
BPMEM_CLEAR_AR = 0x4F, BPMEM_CLEAR_AR = 0x4F,
BPMEM_CLEAR_GB = 0x50, BPMEM_CLEAR_GB = 0x50,
@ -1037,12 +1037,12 @@ struct fmt::formatter<TexImage1>
auto format(const TexImage1& teximg, FormatContext& ctx) const auto format(const TexImage1& teximg, FormatContext& ctx) const
{ {
return fmt::format_to(ctx.out(), return fmt::format_to(ctx.out(),
"Even TMEM Offset: {:x}\n" "Even TMEM Line: 0x{:04x} (byte 0x{:05x})\n"
"Even TMEM Width: {}\n" "Even TMEM Width: {}\n"
"Even TMEM Height: {}\n" "Even TMEM Height: {}\n"
"Cache is manually managed: {}", "Cache is manually managed: {}",
teximg.tmem_even, teximg.cache_width, teximg.cache_height, teximg.tmem_even, teximg.tmem_even * 32, teximg.cache_width,
teximg.cache_manually_managed ? "Yes" : "No"); teximg.cache_height, teximg.cache_manually_managed ? "Yes" : "No");
} }
}; };
@ -1061,10 +1061,11 @@ struct fmt::formatter<TexImage2>
auto format(const TexImage2& teximg, FormatContext& ctx) const auto format(const TexImage2& teximg, FormatContext& ctx) const
{ {
return fmt::format_to(ctx.out(), return fmt::format_to(ctx.out(),
"Odd TMEM Offset: {:x}\n" "Odd TMEM Line: 0x{:04x} (byte 0x{:05x})\n"
"Odd TMEM Width: {}\n" "Odd TMEM Width: {}\n"
"Odd TMEM Height: {}", "Odd TMEM Height: {}",
teximg.tmem_odd, teximg.cache_width, teximg.cache_height); teximg.tmem_odd, teximg.tmem_odd * 32, teximg.cache_width,
teximg.cache_height);
} }
}; };
@ -1080,7 +1081,7 @@ struct fmt::formatter<TexImage3>
template <typename FormatContext> template <typename FormatContext>
auto format(const TexImage3& teximg, FormatContext& ctx) const auto format(const TexImage3& teximg, FormatContext& ctx) const
{ {
return fmt::format_to(ctx.out(), "Source address (32 byte aligned): 0x{:06X}", return fmt::format_to(ctx.out(), "Source address (32 byte aligned): 0x{:06x}",
teximg.image_base << 5); teximg.image_base << 5);
} }
}; };
@ -1098,7 +1099,7 @@ struct fmt::formatter<TexTLUT>
template <typename FormatContext> template <typename FormatContext>
auto format(const TexTLUT& tlut, FormatContext& ctx) const auto format(const TexTLUT& tlut, FormatContext& ctx) const
{ {
return fmt::format_to(ctx.out(), "Address: {:08x}\nFormat: {}", tlut.tmem_offset << 9, return fmt::format_to(ctx.out(), "Tmem address: 0x{:05x}\nFormat: {}", tlut.tmem_offset << 9,
tlut.tlut_format); tlut.tlut_format);
} }
}; };
@ -1108,6 +1109,16 @@ union ZTex1
BitField<0, 24, u32> bias; BitField<0, 24, u32> bias;
u32 hex; u32 hex;
}; };
template <>
struct fmt::formatter<ZTex1>
{
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
template <typename FormatContext>
auto format(const ZTex1& ztex1, FormatContext& ctx) const
{
return fmt::format_to(ctx.out(), "Bias: 0x{:06x}", ztex1.bias);
}
};
union ZTex2 union ZTex2
{ {
@ -2218,7 +2229,7 @@ union CopyFilterCoefficients
union BPU_PreloadTileInfo union BPU_PreloadTileInfo
{ {
BitField<0, 15, u32> count; BitField<0, 15, u32> count;
BitField<15, 2, u32> type; BitField<15, 2, u32> type; // TODO: enum for this?
u32 hex; u32 hex;
}; };
template <> template <>
@ -2228,7 +2239,33 @@ struct fmt::formatter<BPU_PreloadTileInfo>
template <typename FormatContext> template <typename FormatContext>
auto format(const BPU_PreloadTileInfo& info, FormatContext& ctx) const auto format(const BPU_PreloadTileInfo& info, FormatContext& ctx) const
{ {
return fmt::format_to(ctx.out(), "Type: {}\nCount: {}", info.type, info.count); if (info.count == 0 && info.type == 0)
{
return fmt::format_to(ctx.out(), "GX_TexModeSync (type and count are both 0)");
}
else
{
return fmt::format_to(ctx.out(), "Type: {}\nCount: 0x{:x} lines (0x{:x} bytes)", info.type,
info.count, info.count * 32);
}
}
};
union BPU_LoadTlutInfo
{
BitField<0, 10, u32> tmem_addr;
BitField<10, 11, u32> tmem_line_count;
u32 hex;
};
template <>
struct fmt::formatter<BPU_LoadTlutInfo>
{
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
template <typename FormatContext>
auto format(const BPU_LoadTlutInfo& info, FormatContext& ctx) const
{
return fmt::format_to(ctx.out(), "Tmem address: 0x{:05x}\nCount: 0x{:x} lines (0x{:x} bytes)",
info.tmem_addr << 9, info.tmem_line_count, info.tmem_line_count * 32);
} }
}; };
@ -2239,7 +2276,7 @@ struct BPS_TmemConfig
u32 preload_tmem_odd; u32 preload_tmem_odd;
BPU_PreloadTileInfo preload_tile_info; BPU_PreloadTileInfo preload_tile_info;
u32 tlut_src; u32 tlut_src;
u32 tlut_dest; BPU_LoadTlutInfo tlut_dest;
u32 texinvalidate; u32 texinvalidate;
}; };
@ -2426,35 +2463,32 @@ struct BPMemory
// the 3 offset matrices can either be indirect type, S-type, or T-type // the 3 offset matrices can either be indirect type, S-type, or T-type
// 6bit scale factor s is distributed across IND_MTXA/B/C. // 6bit scale factor s is distributed across IND_MTXA/B/C.
// before using matrices scale by 2^-(s-17) // before using matrices scale by 2^-(s-17)
IND_MTX indmtx[3]; // 0x06-0x0e: GXSetIndTexMtx, 2x3 matrices IND_MTX indmtx[3]; // 0x06-0x0e: GXSetIndTexMtx, 2x3 matrices
IND_IMASK imask; // 0x0f IND_IMASK imask; // 0x0f
TevStageIndirect tevind[16]; // 0x10-0x1f: GXSetTevIndirect TevStageIndirect tevind[16]; // 0x10-0x1f: GXSetTevIndirect
ScissorPos scissorTL; // 0x20 ScissorPos scissorTL; // 0x20
ScissorPos scissorBR; // 0x21 ScissorPos scissorBR; // 0x21
LPSize lineptwidth; // 0x22 LPSize lineptwidth; // 0x22
u32 sucounter; // 0x23 u32 sucounter; // 0x23
u32 rascounter; // 0x24 u32 rascounter; // 0x24
TEXSCALE texscale[2]; // 0x25,0x26: GXSetIndTexCoordScale TEXSCALE texscale[2]; // 0x25,0x26: GXSetIndTexCoordScale
RAS1_IREF tevindref; // 0x27: GXSetIndTexOrder RAS1_IREF tevindref; // 0x27: GXSetIndTexOrder
TwoTevStageOrders tevorders[8]; // 0x28-0x2f TwoTevStageOrders tevorders[8]; // 0x28-0x2f
TCoordInfo texcoords[8]; // 0x30-0x4f: s,t,s,t,s,t,s,t... TCoordInfo texcoords[8]; // 0x30-0x3f: s,t,s,t,s,t,s,t...
ZMode zmode; // 0x40 ZMode zmode; // 0x40
BlendMode blendmode; // 0x41 BlendMode blendmode; // 0x41
ConstantAlpha dstalpha; // 0x42 ConstantAlpha dstalpha; // 0x42
PEControl zcontrol; // 0x43: GXSetZCompLoc, GXPixModeSync PEControl zcontrol; // 0x43: GXSetZCompLoc, GXPixModeSync
FieldMask fieldmask; // 0x44 FieldMask fieldmask; // 0x44
u32 drawdone; // 0x45: bit1=1 if end of list u32 drawdone; // 0x45: bit1=1 if end of list
u32 unknown5; // 0x46: clock? u32 unknown5; // 0x46: clock?
u32 petoken; // 0x47 u32 petoken; // 0x47
u32 petokenint; // 0x48 u32 petokenint; // 0x48
X10Y10 copyTexSrcXY; // 0x49 X10Y10 copyTexSrcXY; // 0x49
X10Y10 copyTexSrcWH; // 0x4a X10Y10 copyTexSrcWH; // 0x4a
u32 copyTexDest; // 0x4b: CopyAddress (GXDispCopy and GXTexCopy use it) u32 copyTexDest; // 0x4b: CopyAddress (GXDispCopy and GXTexCopy use it)
u32 unknown6; // 0x4c u32 unknown6; // 0x4c
// usually set to 4 when dest is single channel, 8 when dest is 2 channel, 16 when dest is RGBA u32 copyDestStride; // 0x4d
// also, doubles whenever mipmap box filter option is set (excent on RGBA). Probably to do
// with number of bytes to look at when smoothing
u32 copyMipMapStrideChannels; // 0x4d
u32 dispcopyyscale; // 0x4e u32 dispcopyyscale; // 0x4e
u32 clearcolorAR; // 0x4f u32 clearcolorAR; // 0x4f
u32 clearcolorGB; // 0x50 u32 clearcolorGB; // 0x50

View File

@ -246,7 +246,7 @@ static void BPWritten(PixelShaderManager& pixel_shader_manager,
// this function // this function
u32 destAddr = bpmem.copyTexDest << 5; u32 destAddr = bpmem.copyTexDest << 5;
u32 destStride = bpmem.copyMipMapStrideChannels << 5; u32 destStride = bpmem.copyDestStride << 5;
MathUtil::Rectangle<s32> srcRect; MathUtil::Rectangle<s32> srcRect;
srcRect.left = bpmem.copyTexSrcXY.x; srcRect.left = bpmem.copyTexSrcXY.x;
@ -380,24 +380,32 @@ static void BPWritten(PixelShaderManager& pixel_shader_manager,
return; return;
} }
case BPMEM_LOADTLUT0: // This one updates bpmem.tlutXferSrc, no need to do anything here. case BPMEM_LOADTLUT0: // This updates bpmem.tmem_config.tlut_src, no need to do anything here.
return; return;
case BPMEM_LOADTLUT1: // Load a Texture Look Up Table case BPMEM_LOADTLUT1: // Load a Texture Look Up Table
{ {
u32 tlutTMemAddr = (bp.newvalue & 0x3FF) << 9; u32 tmem_addr = bpmem.tmem_config.tlut_dest.tmem_addr << 9;
u32 tlutXferCount = (bp.newvalue & 0x1FFC00) >> 5; u32 tmem_transfer_count = bpmem.tmem_config.tlut_dest.tmem_line_count * TMEM_LINE_SIZE;
u32 addr = bpmem.tmem_config.tlut_src << 5; u32 addr = bpmem.tmem_config.tlut_src << 5;
// The GameCube ignores the upper bits of this address. Some games (WW, MKDD) set them. // The GameCube ignores the upper bits of this address. Some games (WW, MKDD) set them.
if (!SConfig::GetInstance().bWii) if (!SConfig::GetInstance().bWii)
addr = addr & 0x01FFFFFF; addr = addr & 0x01FFFFFF;
// The copy below will always be in bounds as tmem is bigger than the maximum address a TLUT can
// be loaded to.
static constexpr u32 MAX_LOADABLE_TMEM_ADDR =
(1 << bpmem.tmem_config.tlut_dest.tmem_addr.NumBits()) << 9;
static constexpr u32 MAX_TMEM_LINE_COUNT =
(1 << bpmem.tmem_config.tlut_dest.tmem_line_count.NumBits()) * TMEM_LINE_SIZE;
static_assert(MAX_LOADABLE_TMEM_ADDR + MAX_TMEM_LINE_COUNT < TMEM_SIZE);
auto& system = Core::System::GetInstance(); auto& system = Core::System::GetInstance();
auto& memory = system.GetMemory(); auto& memory = system.GetMemory();
memory.CopyFromEmu(texMem + tlutTMemAddr, addr, tlutXferCount); memory.CopyFromEmu(texMem + tmem_addr, addr, tmem_transfer_count);
if (OpcodeDecoder::g_record_fifo_data) if (OpcodeDecoder::g_record_fifo_data)
FifoRecorder::GetInstance().UseMemory(addr, tlutXferCount, MemoryUpdate::Type::TMEM); FifoRecorder::GetInstance().UseMemory(addr, tmem_transfer_count, MemoryUpdate::Type::TMEM);
TMEM::InvalidateAll(); TMEM::InvalidateAll();
@ -515,8 +523,8 @@ static void BPWritten(PixelShaderManager& pixel_shader_manager,
pixel_shader_manager.SetZModeControl(); pixel_shader_manager.SetZModeControl();
return; return;
case BPMEM_MIPMAP_STRIDE: // MipMap Stride Channel case BPMEM_EFB_STRIDE: // Display Copy Stride
case BPMEM_COPYYSCALE: // Display Copy Y Scale case BPMEM_COPYYSCALE: // Display Copy Y Scale
/* 24 RID /* 24 RID
* 21 BC3 - Ind. Tex Stage 3 NTexCoord * 21 BC3 - Ind. Tex Stage 3 NTexCoord
@ -982,9 +990,10 @@ std::pair<std::string, std::string> GetBPRegInfo(u8 cmd, u32 cmddata)
RegName(BPMEM_EFB_ADDR), RegName(BPMEM_EFB_ADDR),
fmt::format("EFB Target address (32 byte aligned): 0x{:06X}", cmddata << 5)); fmt::format("EFB Target address (32 byte aligned): 0x{:06X}", cmddata << 5));
case BPMEM_MIPMAP_STRIDE: // 0x4D case BPMEM_EFB_STRIDE: // 0x4D
return DescriptionlessReg(BPMEM_MIPMAP_STRIDE); return std::make_pair(
// TODO: Description RegName(BPMEM_EFB_STRIDE),
fmt::format("EFB destination stride (32 byte aligned): 0x{:06X}", cmddata << 5));
case BPMEM_COPYYSCALE: // 0x4E case BPMEM_COPYYSCALE: // 0x4E
return std::make_pair( return std::make_pair(
@ -1030,12 +1039,14 @@ std::pair<std::string, std::string> GetBPRegInfo(u8 cmd, u32 cmddata)
} }
case BPMEM_CLEARBBOX1: // 0x55 case BPMEM_CLEARBBOX1: // 0x55
return DescriptionlessReg(BPMEM_CLEARBBOX1); return std::make_pair(RegName(BPMEM_CLEARBBOX1),
// TODO: Description fmt::format("Bounding Box index 0: {}\nBounding Box index 1: {}",
cmddata & 0x3ff, (cmddata >> 10) & 0x3ff));
case BPMEM_CLEARBBOX2: // 0x56 case BPMEM_CLEARBBOX2: // 0x56
return DescriptionlessReg(BPMEM_CLEARBBOX2); return std::make_pair(RegName(BPMEM_CLEARBBOX2),
// TODO: Description fmt::format("Bounding Box index 2: {}\nBounding Box index 3: {}",
cmddata & 0x3ff, (cmddata >> 10) & 0x3ff));
case BPMEM_CLEAR_PIXEL_PERF: // 0x57 case BPMEM_CLEAR_PIXEL_PERF: // 0x57
return DescriptionlessReg(BPMEM_CLEAR_PIXEL_PERF); return DescriptionlessReg(BPMEM_CLEAR_PIXEL_PERF);
@ -1050,28 +1061,33 @@ std::pair<std::string, std::string> GetBPRegInfo(u8 cmd, u32 cmddata)
fmt::to_string(ScissorOffset{.hex = cmddata})); fmt::to_string(ScissorOffset{.hex = cmddata}));
case BPMEM_PRELOAD_ADDR: // 0x60 case BPMEM_PRELOAD_ADDR: // 0x60
return DescriptionlessReg(BPMEM_PRELOAD_ADDR); return std::make_pair(
// TODO: Description RegName(BPMEM_PRELOAD_ADDR),
fmt::format("Tmem preload address (32 byte aligned, in main memory): 0x{:06x}",
cmddata << 5));
case BPMEM_PRELOAD_TMEMEVEN: // 0x61 case BPMEM_PRELOAD_TMEMEVEN: // 0x61
return DescriptionlessReg(BPMEM_PRELOAD_TMEMEVEN); return std::make_pair(RegName(BPMEM_PRELOAD_TMEMEVEN),
// TODO: Description fmt::format("Tmem preload even line: 0x{:04x} (byte 0x{:05x})", cmddata,
cmddata * TMEM_LINE_SIZE));
case BPMEM_PRELOAD_TMEMODD: // 0x62 case BPMEM_PRELOAD_TMEMODD: // 0x62
return DescriptionlessReg(BPMEM_PRELOAD_TMEMODD); return std::make_pair(RegName(BPMEM_PRELOAD_TMEMODD),
// TODO: Description fmt::format("Tmem preload odd line: 0x{:04x} (byte 0x{:05x})", cmddata,
cmddata * TMEM_LINE_SIZE));
case BPMEM_PRELOAD_MODE: // 0x63 case BPMEM_PRELOAD_MODE: // 0x63
return std::make_pair(RegName(BPMEM_PRELOAD_MODE), return std::make_pair(RegName(BPMEM_PRELOAD_MODE),
fmt::to_string(BPU_PreloadTileInfo{.hex = cmddata})); fmt::to_string(BPU_PreloadTileInfo{.hex = cmddata}));
case BPMEM_LOADTLUT0: // 0x64 case BPMEM_LOADTLUT0: // 0x64
return DescriptionlessReg(BPMEM_LOADTLUT0); return std::make_pair(
// TODO: Description RegName(BPMEM_LOADTLUT0),
fmt::format("TLUT load address (32 byte aligned, in main memory): 0x{:06x}", cmddata << 5));
case BPMEM_LOADTLUT1: // 0x65 case BPMEM_LOADTLUT1: // 0x65
return DescriptionlessReg(BPMEM_LOADTLUT1); return std::make_pair(RegName(BPMEM_LOADTLUT1),
// TODO: Description fmt::to_string(BPU_LoadTlutInfo{.hex = cmddata}));
case BPMEM_TEXINVALIDATE: // 0x66 case BPMEM_TEXINVALIDATE: // 0x66
return DescriptionlessReg(BPMEM_TEXINVALIDATE); return DescriptionlessReg(BPMEM_TEXINVALIDATE);
@ -1269,12 +1285,11 @@ std::pair<std::string, std::string> GetBPRegInfo(u8 cmd, u32 cmddata)
return std::make_pair(RegName(BPMEM_FOGPARAM0), fmt::to_string(FogParam0{.hex = cmddata})); return std::make_pair(RegName(BPMEM_FOGPARAM0), fmt::to_string(FogParam0{.hex = cmddata}));
case BPMEM_FOGBMAGNITUDE: // 0xEF case BPMEM_FOGBMAGNITUDE: // 0xEF
return DescriptionlessReg(BPMEM_FOGBMAGNITUDE); return std::make_pair(RegName(BPMEM_FOGBMAGNITUDE), fmt::format("B magnitude: {}", cmddata));
// TODO: Description
case BPMEM_FOGBEXPONENT: // 0xF0 case BPMEM_FOGBEXPONENT: // 0xF0
return DescriptionlessReg(BPMEM_FOGBEXPONENT); return std::make_pair(RegName(BPMEM_FOGBEXPONENT),
// TODO: Description fmt::format("B shift: 1>>{} (1/{})", cmddata, 1 << cmddata));
case BPMEM_FOGPARAM3: // 0xF1 case BPMEM_FOGPARAM3: // 0xF1
return std::make_pair(RegName(BPMEM_FOGPARAM3), fmt::to_string(FogParam3{.hex = cmddata})); return std::make_pair(RegName(BPMEM_FOGPARAM3), fmt::to_string(FogParam3{.hex = cmddata}));
@ -1287,8 +1302,7 @@ std::pair<std::string, std::string> GetBPRegInfo(u8 cmd, u32 cmddata)
return std::make_pair(RegName(BPMEM_ALPHACOMPARE), fmt::to_string(AlphaTest{.hex = cmddata})); return std::make_pair(RegName(BPMEM_ALPHACOMPARE), fmt::to_string(AlphaTest{.hex = cmddata}));
case BPMEM_BIAS: // 0xF4 case BPMEM_BIAS: // 0xF4
return DescriptionlessReg(BPMEM_BIAS); return std::make_pair(RegName(BPMEM_BIAS), fmt::to_string(ZTex1{.hex = cmddata}));
// TODO: Description
case BPMEM_ZTEX2: // 0xF5 case BPMEM_ZTEX2: // 0xF5
return std::make_pair(RegName(BPMEM_ZTEX2), fmt::to_string(ZTex2{.hex = cmddata})); return std::make_pair(RegName(BPMEM_ZTEX2), fmt::to_string(ZTex2{.hex = cmddata}));