-
Notifications
You must be signed in to change notification settings - Fork 2.6k
/
CPMemory.cpp
217 lines (187 loc) · 7.03 KB
/
CPMemory.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
// Copyright 2008 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "VideoCommon/CPMemory.h"
#include <cstring>
#include "Common/ChunkFile.h"
#include "Common/Logging/Log.h"
#include "Core/DolphinAnalytics.h"
#include "VideoCommon/CommandProcessor.h"
#include "VideoCommon/VertexLoaderManager.h"
// CP state
CPState g_main_cp_state;
CPState g_preprocess_cp_state;
void CopyPreprocessCPStateFromMain()
{
std::memcpy(&g_preprocess_cp_state, &g_main_cp_state, sizeof(CPState));
}
std::pair<std::string, std::string> GetCPRegInfo(u8 cmd, u32 value)
{
switch (cmd & CP_COMMAND_MASK)
{
case MATINDEX_A:
return std::make_pair("MATINDEX_A", fmt::to_string(TMatrixIndexA{.Hex = value}));
case MATINDEX_B:
return std::make_pair("MATINDEX_B", fmt::to_string(TMatrixIndexB{.Hex = value}));
case VCD_LO:
return std::make_pair("VCD_LO", fmt::to_string(TVtxDesc::Low{.Hex = value}));
case VCD_HI:
return std::make_pair("VCD_HI", fmt::to_string(TVtxDesc::High{.Hex = value}));
case CP_VAT_REG_A:
if (cmd - CP_VAT_REG_A >= CP_NUM_VAT_REG)
return std::make_pair("CP_VAT_REG_A invalid", "");
return std::make_pair(fmt::format("CP_VAT_REG_A - Format {}", cmd & CP_VAT_MASK),
fmt::to_string(UVAT_group0{.Hex = value}));
case CP_VAT_REG_B:
if (cmd - CP_VAT_REG_B >= CP_NUM_VAT_REG)
return std::make_pair("CP_VAT_REG_B invalid", "");
return std::make_pair(fmt::format("CP_VAT_REG_B - Format {}", cmd & CP_VAT_MASK),
fmt::to_string(UVAT_group1{.Hex = value}));
case CP_VAT_REG_C:
if (cmd - CP_VAT_REG_C >= CP_NUM_VAT_REG)
return std::make_pair("CP_VAT_REG_C invalid", "");
return std::make_pair(fmt::format("CP_VAT_REG_C - Format {}", cmd & CP_VAT_MASK),
fmt::to_string(UVAT_group2{.Hex = value}));
case ARRAY_BASE:
return std::make_pair(
fmt::format("ARRAY_BASE Array {}", static_cast<CPArray>(cmd & CP_ARRAY_MASK)),
fmt::format("Base address {:08x}", value));
case ARRAY_STRIDE:
return std::make_pair(
fmt::format("ARRAY_STRIDE Array {}", static_cast<CPArray>(cmd & CP_ARRAY_MASK)),
fmt::format("Stride {:02x}", value & 0xff));
default:
return std::make_pair(fmt::format("Invalid CP register {:02x} = {:08x}", cmd, value), "");
}
}
CPState::CPState(const u32* memory) : CPState()
{
matrix_index_a.Hex = memory[MATINDEX_A];
matrix_index_b.Hex = memory[MATINDEX_B];
vtx_desc.low.Hex = memory[VCD_LO];
vtx_desc.high.Hex = memory[VCD_HI];
for (u32 i = 0; i < CP_NUM_VAT_REG; i++)
{
vtx_attr[i].g0.Hex = memory[CP_VAT_REG_A + i];
vtx_attr[i].g1.Hex = memory[CP_VAT_REG_B + i];
vtx_attr[i].g2.Hex = memory[CP_VAT_REG_C + i];
}
for (u32 i = 0; i < CP_NUM_ARRAYS; i++)
{
array_bases[static_cast<CPArray>(i)] = memory[ARRAY_BASE + i];
array_strides[static_cast<CPArray>(i)] = memory[ARRAY_STRIDE + i];
}
}
void CPState::LoadCPReg(u8 sub_cmd, u32 value)
{
switch (sub_cmd & CP_COMMAND_MASK)
{
case UNKNOWN_00:
case UNKNOWN_10:
case UNKNOWN_20:
if (!(sub_cmd == UNKNOWN_20 && value == 0))
{
// All titles using libogc or the official SDK issue 0x20 with value=0 on startup
DolphinAnalytics::Instance().ReportGameQuirk(GameQuirk::USES_CP_PERF_COMMAND);
DEBUG_LOG_FMT(VIDEO, "Unknown CP command possibly relating to perf queries used: {:02x}",
sub_cmd);
}
break;
case MATINDEX_A:
if (sub_cmd != MATINDEX_A)
{
DolphinAnalytics::Instance().ReportGameQuirk(GameQuirk::USES_MAYBE_INVALID_CP_COMMAND);
WARN_LOG_FMT(VIDEO,
"CP MATINDEX_A: an exact value of {:02x} was expected "
"but instead a value of {:02x} was seen",
MATINDEX_A, sub_cmd);
}
matrix_index_a.Hex = value;
break;
case MATINDEX_B:
if (sub_cmd != MATINDEX_B)
{
DolphinAnalytics::Instance().ReportGameQuirk(GameQuirk::USES_MAYBE_INVALID_CP_COMMAND);
WARN_LOG_FMT(VIDEO,
"CP MATINDEX_B: an exact value of {:02x} was expected "
"but instead a value of {:02x} was seen",
MATINDEX_B, sub_cmd);
}
matrix_index_b.Hex = value;
break;
case VCD_LO:
if (sub_cmd != VCD_LO) // Stricter than YAGCD
{
DolphinAnalytics::Instance().ReportGameQuirk(GameQuirk::USES_MAYBE_INVALID_CP_COMMAND);
WARN_LOG_FMT(VIDEO,
"CP VCD_LO: an exact value of {:02x} was expected "
"but instead a value of {:02x} was seen",
VCD_LO, sub_cmd);
}
vtx_desc.low.Hex = value;
break;
case VCD_HI:
if (sub_cmd != VCD_HI) // Stricter than YAGCD
{
DolphinAnalytics::Instance().ReportGameQuirk(GameQuirk::USES_MAYBE_INVALID_CP_COMMAND);
WARN_LOG_FMT(VIDEO,
"CP VCD_HI: an exact value of {:02x} was expected "
"but instead a value of {:02x} was seen",
VCD_HI, sub_cmd);
}
vtx_desc.high.Hex = value;
break;
case CP_VAT_REG_A:
if ((sub_cmd - CP_VAT_REG_A) >= CP_NUM_VAT_REG)
{
DolphinAnalytics::Instance().ReportGameQuirk(GameQuirk::USES_MAYBE_INVALID_CP_COMMAND);
WARN_LOG_FMT(VIDEO, "CP_VAT_REG_A: Invalid VAT {}", sub_cmd - CP_VAT_REG_A);
}
vtx_attr[sub_cmd & CP_VAT_MASK].g0.Hex = value;
break;
case CP_VAT_REG_B:
if ((sub_cmd - CP_VAT_REG_B) >= CP_NUM_VAT_REG)
{
DolphinAnalytics::Instance().ReportGameQuirk(GameQuirk::USES_MAYBE_INVALID_CP_COMMAND);
WARN_LOG_FMT(VIDEO, "CP_VAT_REG_B: Invalid VAT {}", sub_cmd - CP_VAT_REG_B);
}
vtx_attr[sub_cmd & CP_VAT_MASK].g1.Hex = value;
break;
case CP_VAT_REG_C:
if ((sub_cmd - CP_VAT_REG_C) >= CP_NUM_VAT_REG)
{
DolphinAnalytics::Instance().ReportGameQuirk(GameQuirk::USES_MAYBE_INVALID_CP_COMMAND);
WARN_LOG_FMT(VIDEO, "CP_VAT_REG_C: Invalid VAT {}", sub_cmd - CP_VAT_REG_C);
}
vtx_attr[sub_cmd & CP_VAT_MASK].g2.Hex = value;
break;
// Pointers to vertex arrays in GC RAM
case ARRAY_BASE:
array_bases[static_cast<CPArray>(sub_cmd & CP_ARRAY_MASK)] =
value & CommandProcessor::GetPhysicalAddressMask();
break;
case ARRAY_STRIDE:
array_strides[static_cast<CPArray>(sub_cmd & CP_ARRAY_MASK)] = value & 0xFF;
break;
default:
DolphinAnalytics::Instance().ReportGameQuirk(GameQuirk::USES_UNKNOWN_CP_COMMAND);
WARN_LOG_FMT(VIDEO, "Unknown CP register {:02x} set to {:08x}", sub_cmd, value);
}
}
void CPState::FillCPMemoryArray(u32* memory) const
{
memory[MATINDEX_A] = matrix_index_a.Hex;
memory[MATINDEX_B] = matrix_index_b.Hex;
memory[VCD_LO] = vtx_desc.low.Hex;
memory[VCD_HI] = vtx_desc.high.Hex;
for (int i = 0; i < CP_NUM_VAT_REG; ++i)
{
memory[CP_VAT_REG_A + i] = vtx_attr[i].g0.Hex;
memory[CP_VAT_REG_B + i] = vtx_attr[i].g1.Hex;
memory[CP_VAT_REG_C + i] = vtx_attr[i].g2.Hex;
}
for (int i = 0; i < CP_NUM_ARRAYS; ++i)
{
memory[ARRAY_BASE + i] = array_bases[static_cast<CPArray>(i)];
memory[ARRAY_STRIDE + i] = array_strides[static_cast<CPArray>(i)];
}
}