Nugget
Bare-metal libraries and examples for the original PlayStation
Loading...
Searching...
No Matches
gte-encoding.c
Go to the documentation of this file.
1// GTE instruction encoding tests: systematic sweep of bitfield parameters.
2//
3// Helper macros for unrolled MVMVA sweeps. Defined at file scope so they
4// survive cester's double-include of __BASE_FILE__.
5
6#define MVMVA_T(mx, v, cv) \
7 do { \
8 if ((v) == 3) { \
9 cop2_put(9, 0x100); \
10 cop2_put(10, 0x200); \
11 cop2_put(11, 0x300); \
12 } \
13 gte_clear_flag(); \
14 cop2_cmd(COP2_MVMVA(1, mx, v, cv, 0)); \
15 } while (0)
16
17#define MVMVA_MX3_V(v) \
18 do { \
19 if ((v) == 3) { \
20 cop2_put(9, 0x400); \
21 cop2_put(10, 0x500); \
22 cop2_put(11, 0x600); \
23 } \
24 gte_clear_flag(); \
25 cop2_cmd(COP2_MVMVA(1, 3, v, 3, 0)); \
26 int32_t _m1, _m2, _m3; \
27 cop2_get(25, _m1); \
28 cop2_get(26, _m2); \
29 cop2_get(27, _m3); \
30 ramsyscall_printf("MVMVA mx=3 v=%d: MAC=(%d,%d,%d)\n", v, _m1, _m2, _m3); \
31 } while (0)
32
33#define MVMVA_CV2_MX(mx) \
34 do { \
35 cop2_put(9, 0x100); \
36 cop2_put(10, 0x200); \
37 cop2_put(11, 0x300); \
38 gte_clear_flag(); \
39 cop2_cmd(COP2_MVMVA(1, mx, 0, 2, 0)); \
40 int32_t _m1, _m2, _m3; \
41 uint32_t _fl; \
42 cop2_get(25, _m1); \
43 cop2_get(26, _m2); \
44 cop2_get(27, _m3); \
45 _fl = gte_read_flag(); \
46 ramsyscall_printf("MVMVA mx=%d cv=2: MAC=(%d,%d,%d) FLAG=0x%08x\n", mx, _m1, _m2, _m3, _fl); \
47 } while (0)
48//
49// The GTE command word is a 25-bit immediate with fields:
50// [fake:5][sf:1][mx:2][v:2][cv:2][pad:2][lm:1][pad:4][fn:6]
51//
52// These tests verify:
53// 1. The "fake" field (bits 24-20) is ignored by hardware
54// 2. sf=0 vs sf=1 behavior for each function code
55// 3. lm=0 vs lm=1 behavior for each function code
56// 4. All MVMVA mx/v/cv combinations produce results
57// 5. Unused bitfield values don't crash
58
59// ==========================================================================
60// Fake field is ignored by hardware
61// ==========================================================================
62
63// Run RTPS with fake=0 (non-standard) and verify same result as fake=1
64// clang-format off
65
66CESTER_TEST(enc_fake_field_ignored_rtps, gte_tests,
68 gte_set_translation(0, 0, 1000);
69 gte_set_screen(160 << 16, 120 << 16, 200);
70 cop2_put(0, 0);
71 cop2_put(1, 0);
72
73 // Standard encoding: fake=1, sf=1
75 cop2_cmd(COP2_RTPS(1, 0));
76 uint32_t sxy2_std;
77 cop2_get(14, sxy2_std);
78
79 // Non-standard: fake=0, same sf/fn
80 cop2_put(0, 0);
81 cop2_put(1, 0);
83 cop2_cmd(COP2_OP(0, 1, 0, 0, 0, 0, COP2_FN_RTPS));
84 uint32_t sxy2_alt;
85 cop2_get(14, sxy2_alt);
86
87 cester_assert_uint_eq(sxy2_std, sxy2_alt);
88)
89
90// Run GPF with fake=31 (max) vs standard fake=25
91CESTER_TEST(enc_fake_field_ignored_gpf, gte_tests,
92 cop2_put(8, 0x1000);
93 cop2_put(9, 100);
94 cop2_put(10, 200);
95 cop2_put(11, 300);
96 cop2_put(6, 0x00808080);
97
99 cop2_cmd(COP2_GPF(1, 0));
100 int32_t mac1_std;
101 cop2_get(25, mac1_std);
102
103 cop2_put(8, 0x1000);
104 cop2_put(9, 100);
105 cop2_put(10, 200);
106 cop2_put(11, 300);
107 cop2_put(6, 0x00808080);
109 cop2_cmd(COP2_OP(31, 1, 0, 0, 0, 0, COP2_FN_GPF));
110 int32_t mac1_alt;
111 cop2_get(25, mac1_alt);
112
113 cester_assert_int_eq(mac1_std, mac1_alt);
114)
115
116// ==========================================================================
117// sf=0 vs sf=1 for each instruction
118// ==========================================================================
119
120// GPF: sf changes shift behavior
121CESTER_TEST(enc_gpf_sf_difference, gte_tests,
122 cop2_put(8, 0x1000);
123 cop2_put(9, 0x1000);
124 cop2_put(10, 0x1000);
125 cop2_put(11, 0x1000);
126 cop2_put(6, 0x00808080);
127
128 // sf=1: MAC = (IR0*IR) >> 12 = (0x1000*0x1000)>>12 = 0x1000
130 cop2_cmd(COP2_GPF(1, 0));
131 int32_t mac1_sf1;
132 cop2_get(25, mac1_sf1);
133
134 cop2_put(8, 0x1000);
135 cop2_put(9, 0x1000);
136 cop2_put(10, 0x1000);
137 cop2_put(11, 0x1000);
138 cop2_put(6, 0x00808080);
139
140 // sf=0: MAC = IR0*IR = 0x1000*0x1000 = 0x1000000
142 cop2_cmd(COP2_GPF(0, 0));
143 int32_t mac1_sf0;
144 cop2_get(25, mac1_sf0);
145
146 cester_assert_int_eq(0x1000, mac1_sf1);
147 cester_assert_int_eq(0x1000000, mac1_sf0);
148)
149
150// SQR: sf changes shift
151CESTER_TEST(enc_sqr_sf_difference, gte_tests,
152 cop2_put(9, 0x100);
153 cop2_put(10, 0x100);
154 cop2_put(11, 0x100);
155
157 cop2_cmd(COP2_SQR(1, 0));
158 int32_t mac1_sf1;
159 cop2_get(25, mac1_sf1);
160
161 cop2_put(9, 0x100);
162 cop2_put(10, 0x100);
163 cop2_put(11, 0x100);
165 cop2_cmd(COP2_SQR(0, 0));
166 int32_t mac1_sf0;
167 cop2_get(25, mac1_sf0);
168
169 // sf=1: (0x100*0x100)>>12 = 0x10000>>12 = 0x10
170 // sf=0: 0x100*0x100 = 0x10000
171 cester_assert_int_eq(0x10, mac1_sf1);
172 cester_assert_int_eq(0x10000, mac1_sf0);
173)
174
175// OP: sf changes shift
176CESTER_TEST(enc_op_sf_difference, gte_tests,
177 cop2_putc(0, 0x00001000);
178 cop2_putc(2, 0x00002000);
179 cop2_putc(4, 0x1000);
180 cop2_put(9, 100);
181 cop2_put(10, 0);
182 cop2_put(11, 0);
183
185 cop2_cmd(COP2_OP_CP(1, 0));
186 int32_t mac2_sf1;
187 cop2_get(26, mac2_sf1);
188
189 cop2_put(9, 100);
190 cop2_put(10, 0);
191 cop2_put(11, 0);
193 cop2_cmd(COP2_OP_CP(0, 0));
194 int32_t mac2_sf0;
195 cop2_get(26, mac2_sf0);
196
197 // sf=1: MAC2 = (R33*IR1 - R11*IR3)>>12 = (0x1000*100 - 0x1000*0)>>12 = 100
198 // sf=0: MAC2 = R33*IR1 - R11*IR3 = 0x1000*100 = 409600
199 cester_assert_int_eq(100, mac2_sf1);
200 cester_assert_int_eq(409600, mac2_sf0);
201)
202
203// ==========================================================================
204// lm=0 vs lm=1 for each instruction
205// ==========================================================================
206
207// SQR: lm=1 clamps IR to [0, 0x7fff]
208CESTER_TEST(enc_sqr_lm_difference, gte_tests,
209 cop2_put(9, 0x2000); // 2.0
210 cop2_put(10, 0x2000);
211 cop2_put(11, 0x2000);
212
213 // sf=1, lm=0: 2.0^2 = 4.0 = 0x4000 (in range for signed)
215 cop2_cmd(COP2_SQR(1, 0));
216 uint32_t ir1_lm0;
217 cop2_get(9, ir1_lm0);
218
219 cop2_put(9, 0x2000);
220 cop2_put(10, 0x2000);
221 cop2_put(11, 0x2000);
222
223 // sf=1, lm=1: same result since 0x4000 > 0 (lm=1 only clamps negative to 0)
225 cop2_cmd(COP2_SQR(1, 1));
226 uint32_t ir1_lm1;
227 cop2_get(9, ir1_lm1);
228
229 // Both should be 0x4000 since result is positive
230 cester_assert_uint_eq(0x4000, ir1_lm0);
231 cester_assert_uint_eq(0x4000, ir1_lm1);
232)
233
234// ==========================================================================
235// MVMVA: all mx/v/cv combinations (4 x 4 x 4 = 64 combos)
236// ==========================================================================
237
238// Sweep all 64 MVMVA parameter combinations and verify no crash.
239// Log MAC results for ground truth capture.
240CESTER_TEST(enc_mvmva_full_sweep, gte_tests,
241 // Set up all matrices and vectors with known non-zero values
242 // RT matrix
243 cop2_putc(0, 0x08001000);
244 cop2_putc(1, 0x02000400);
245 cop2_putc(2, 0x08001000);
246 cop2_putc(3, 0x02000400);
247 cop2_putc(4, 0x1000);
248 // LL matrix
249 cop2_putc(8, 0x04000800);
250 cop2_putc(9, 0x01000200);
251 cop2_putc(10, 0x04000800);
252 cop2_putc(11, 0x01000200);
253 cop2_putc(12, 0x0800);
254 // LC matrix
255 cop2_putc(16, 0x02000400);
256 cop2_putc(17, 0x00800100);
257 cop2_putc(18, 0x02000400);
258 cop2_putc(19, 0x00800100);
259 cop2_putc(20, 0x0400);
260 // Vectors
261 cop2_put(0, (0x200 << 16) | 0x100); // V0
262 cop2_put(1, 0x300);
263 cop2_put(2, (0x500 << 16) | 0x400); // V1
264 cop2_put(3, 0x600);
265 cop2_put(4, (0x800 << 16) | 0x700); // V2
266 cop2_put(5, 0x900);
267 cop2_put(9, 0x100); // IR1
268 cop2_put(10, 0x200); // IR2
269 cop2_put(11, 0x300); // IR3
270 cop2_put(8, 0x0800); // IR0
271 // Control vectors
272 gte_set_translation(100, 200, 300);
273 cop2_putc(13, 400);
274 cop2_putc(14, 500);
275 cop2_putc(15, 600);
276 gte_set_far_color(700, 800, 900);
277
278 // All 64 MVMVA combos unrolled (cop2_cmd requires compile-time constants).
279 MVMVA_T(0,0,0); MVMVA_T(0,0,1); MVMVA_T(0,0,2); MVMVA_T(0,0,3);
280 MVMVA_T(0,1,0); MVMVA_T(0,1,1); MVMVA_T(0,1,2); MVMVA_T(0,1,3);
281 MVMVA_T(0,2,0); MVMVA_T(0,2,1); MVMVA_T(0,2,2); MVMVA_T(0,2,3);
282 MVMVA_T(0,3,0); MVMVA_T(0,3,1); MVMVA_T(0,3,2); MVMVA_T(0,3,3);
283 MVMVA_T(1,0,0); MVMVA_T(1,0,1); MVMVA_T(1,0,2); MVMVA_T(1,0,3);
284 MVMVA_T(1,1,0); MVMVA_T(1,1,1); MVMVA_T(1,1,2); MVMVA_T(1,1,3);
285 MVMVA_T(1,2,0); MVMVA_T(1,2,1); MVMVA_T(1,2,2); MVMVA_T(1,2,3);
286 MVMVA_T(1,3,0); MVMVA_T(1,3,1); MVMVA_T(1,3,2); MVMVA_T(1,3,3);
287 MVMVA_T(2,0,0); MVMVA_T(2,0,1); MVMVA_T(2,0,2); MVMVA_T(2,0,3);
288 MVMVA_T(2,1,0); MVMVA_T(2,1,1); MVMVA_T(2,1,2); MVMVA_T(2,1,3);
289 MVMVA_T(2,2,0); MVMVA_T(2,2,1); MVMVA_T(2,2,2); MVMVA_T(2,2,3);
290 MVMVA_T(2,3,0); MVMVA_T(2,3,1); MVMVA_T(2,3,2); MVMVA_T(2,3,3);
291 MVMVA_T(3,0,0); MVMVA_T(3,0,1); MVMVA_T(3,0,2); MVMVA_T(3,0,3);
292 MVMVA_T(3,1,0); MVMVA_T(3,1,1); MVMVA_T(3,1,2); MVMVA_T(3,1,3);
293 MVMVA_T(3,2,0); MVMVA_T(3,2,1); MVMVA_T(3,2,2); MVMVA_T(3,2,3);
294 MVMVA_T(3,3,0); MVMVA_T(3,3,1); MVMVA_T(3,3,2); MVMVA_T(3,3,3);
295 cester_assert_int_eq(1, 1); // if we got here, none crashed
296)
297
298// ==========================================================================
299// MVMVA mx=3 (garbage matrix) with all vector/cv combinations
300// ==========================================================================
301
302CESTER_TEST(enc_mvmva_mx3_all_vectors, gte_tests,
303 cop2_putc(0, 0x20001000);
304 cop2_putc(1, 0x40003000);
305 cop2_putc(2, 0x60005000);
306 cop2_putc(3, 0x80007000);
307 cop2_putc(4, 0x1000);
308 cop2_put(8, 0x0800);
309 cop2_put(0, (0x100 << 16) | 0x100);
310 cop2_put(1, 0x100);
311 cop2_put(2, (0x200 << 16) | 0x200);
312 cop2_put(3, 0x200);
313 cop2_put(4, (0x300 << 16) | 0x300);
314 cop2_put(5, 0x300);
315 cop2_put(9, 0x400);
316 cop2_put(10, 0x500);
317 cop2_put(11, 0x600);
318
321)
322
323// ==========================================================================
324// MVMVA cv=2 (FC bug) with all matrix/vector combinations
325// ==========================================================================
326
327CESTER_TEST(enc_mvmva_cv2_all_matrices, gte_tests,
331 gte_set_far_color(0x1000, 0x2000, 0x3000);
332 cop2_put(0, (0x200 << 16) | 0x100);
333 cop2_put(1, 0x300);
334 cop2_put(9, 0x100);
335 cop2_put(10, 0x200);
336 cop2_put(11, 0x300);
337
340)
341
342// ==========================================================================
343// Instructions that ignore sf/lm should produce identical results
344// ==========================================================================
345
346// NCLIP ignores sf and lm
347CESTER_TEST(enc_nclip_ignores_sf_lm, gte_tests,
348 cop2_put(12, 0x00000000);
349 cop2_put(13, 0x00000064);
350 cop2_put(14, 0x00640000);
351
353 cop2_cmd(COP2_OP(20, 0, 0, 0, 0, 0, COP2_FN_NCLIP)); // standard
354 int32_t mac0_std;
355 cop2_get(24, mac0_std);
356
357 cop2_put(12, 0x00000000);
358 cop2_put(13, 0x00000064);
359 cop2_put(14, 0x00640000);
361 cop2_cmd(COP2_OP(0, 1, 3, 3, 3, 1, COP2_FN_NCLIP)); // all bits set
362 int32_t mac0_alt;
363 cop2_get(24, mac0_alt);
364
365 cester_assert_int_eq(mac0_std, mac0_alt);
366)
367
368// AVSZ3 ignores sf and lm (uses fixed >>12)
369CESTER_TEST(enc_avsz3_ignores_sf_lm, gte_tests,
370 cop2_put(17, 100);
371 cop2_put(18, 200);
372 cop2_put(19, 300);
373 cop2_putc(29, 0x555);
374
377 int32_t mac0_std;
378 cop2_get(24, mac0_std);
379
380 cop2_put(17, 100);
381 cop2_put(18, 200);
382 cop2_put(19, 300);
383 cop2_putc(29, 0x555);
385 cop2_cmd(COP2_OP(0, 0, 3, 3, 3, 1, COP2_FN_AVSZ3));
386 int32_t mac0_alt;
387 cop2_get(24, mac0_alt);
388
389 cester_assert_int_eq(mac0_std, mac0_alt);
390)
CESTER_TEST(cddaLevelHalf, test_instances, static const uint8_t atv[4]={0x40, 0x00, 0x40, 0x00};unsigned changes=0;int peak=cddaPeak(atv, 1, &changes);ramsyscall_printf("CD-DA level at half ATV: peak %i, %u sign changes\n", peak, changes);cester_assert_int_ge(peak, 11300);cester_assert_int_le(peak, 11800);cester_assert_uint_ge(changes, 4);) CESTER_TEST(cddaLevelClipped
cester_assert_uint_eq(5, cause1)
#define COP2_FN_GPF
Definition cop2.h:105
#define COP2_OP_CP(sf, lm)
Definition cop2.h:136
#define cop2_cmd(op)
Definition cop2.h:175
#define cop2_put(reg, val)
Definition cop2.h:191
#define COP2_SQR(sf, lm)
Definition cop2.h:161
#define COP2_GPF(sf, lm)
Definition cop2.h:168
#define cop2_putc(reg, val)
Definition cop2.h:205
#define COP2_RTPS(sf, lm)
Definition cop2.h:129
#define COP2_AVSZ3
Definition cop2.h:164
#define COP2_FN_RTPS
Definition cop2.h:86
#define cop2_get(reg, dest)
Definition cop2.h:198
#define COP2_FN_NCLIP
Definition cop2.h:87
#define COP2_OP(fake, sf, mx, v, cv, lm, fn)
Definition cop2.h:116
#define COP2_FN_AVSZ3
Definition cop2.h:102
gte_set_far_color(0xff00, 0xff00, 0xff00)
gte_tests
Definition gte-depthcue.c:31
gte_clear_flag()
gte_set_identity_rotation()
gte_set_translation(0, 0, 0)
gte_set_screen(0, 0, 0)
#define MVMVA_T(mx, v, cv)
Definition gte-encoding.c:6
#define MVMVA_CV2_MX(mx)
Definition gte-encoding.c:33
#define MVMVA_MX3_V(v)
Definition gte-encoding.c:17
gte_set_white_light_color()
gte_set_simple_light()
cester_assert_int_eq(3, xaCommand(CDL_SETMODE, &mode, 1, NULL, NULL))