Nugget
Loading...
Searching...
No Matches
uv-boundary.c
Go to the documentation of this file.
1/*
2
3MIT License
4
5Copyright (c) 2026 PCSX-Redux authors
6
7Permission is hereby granted, free of charge, to any person obtaining a copy
8of this software and associated documentation files (the "Software"), to deal
9in the Software without restriction, including without limitation the rights
10to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11copies of the Software, and to permit persons to whom the Software is
12furnished to do so, subject to the following conditions:
13
14The above copyright notice and this permission notice shall be included in all
15copies or substantial portions of the Software.
16
17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23SOFTWARE.
24
25*/
26
27// U/V boundary probes. Each test renders a 1-pixel-wide textured
28// rect at the chosen UV and reads back the texel. UVs that exceed
29// the depth-dependent page width are the interesting cases.
30
32
33static void drawTex8At(uint8_t u, uint8_t v) {
34 rasterReset();
35 rasterClearTestRegion(0, 0, 32, 8);
36 setTexpage(TEX8_TX, TEX8_TY, 1);
37 setTextureWindow(0, 0, 0, 0);
38 rasterTexRect(TEX_MOD_NEUTRAL, 0, 0, u, v, 1, 1, CLUT8_FIELD);
39 rasterFlushPrimitive();
40}
41
42static void drawTex15At(uint8_t u, uint8_t v) {
43 rasterReset();
44 rasterClearTestRegion(0, 0, 32, 8);
45 setTexpage(TEX15_TX, TEX15_TY, 2);
46 setTextureWindow(0, 0, 0, 0);
47 rasterTexRect(TEX_MOD_NEUTRAL, 0, 0, u, v, 1, 1, CLUT15_FIELD);
48 rasterFlushPrimitive();
49}
50
51static void drawTex4At(uint8_t u, uint8_t v) {
52 rasterReset();
53 rasterClearTestRegion(0, 0, 32, 8);
54 setTexpage(TEX4_TX, TEX4_TY, 0);
55 setTextureWindow(0, 0, 0, 0);
56 rasterTexRect(TEX_MOD_NEUTRAL, 0, 0, u, v, 1, 1, CLUT4_FIELD);
57 rasterFlushPrimitive();
58}
59
60) // CESTER_BODY
61
62// ============================================================================
63// 8-bit page (128 wide × 256 tall in texel coords). U > 127 is the
64// boundary. Captured value lets us infer wrap-mod / clamp / extend.
65// ============================================================================
66
67CESTER_TEST(uv8_u0_v0, gpu_raster_phase16,
68 drawTex8At(0, 0);
69 /* Baseline: u=0 -> CLUT8[0]. */
70 ASSERT_PIXEL_EQ(expectedClut8Color(0), 0, 0);
71)
72
73CESTER_TEST(uv8_u127_v0, gpu_raster_phase16,
74 drawTex8At(127, 0);
75 /* Last in-page texel for 8-bit (page width = 128). */
76 ASSERT_PIXEL_EQ(expectedClut8Color(127), 0, 0);
77)
78
79CESTER_TEST(uv8_u128_v0, gpu_raster_phase16,
80 drawTex8At(128, 0);
81 /* First off-page texel. If hardware wraps mod 128 -> CLUT8[0].
82 If hardware extends into the next VRAM region -> something
83 else. */
85)
86
87CESTER_TEST(uv8_u200_v0, gpu_raster_phase16,
88 drawTex8At(200, 0);
89 /* Deep off-page. */
91)
92
93CESTER_TEST(uv8_u255_v0, gpu_raster_phase16,
94 drawTex8At(255, 0);
95 /* Last representable U. */
97)
98
99// ============================================================================
100// 15-bit page (64 wide × 256 tall). U > 63 is the boundary.
101// ============================================================================
102
103CESTER_TEST(uv15_u0_v0, gpu_raster_phase16,
104 drawTex15At(0, 0);
105 /* Baseline: texel(0, 0) = vram555(0, 0, 0) = 0x0000 - transparent
106 per the phase-9 finding. Sentinel preserved. */
108)
109
110CESTER_TEST(uv15_u1_v0, gpu_raster_phase16,
111 drawTex15At(1, 0);
112 /* texel(1, 0) = vram555(1, 0, 1) = 1 | (1<<10) = 0x0401 */
113 ASSERT_PIXEL_EQ(expectedTex15Color(1, 0), 0, 0);
114)
115
116CESTER_TEST(uv15_u63_v0, gpu_raster_phase16,
117 drawTex15At(63, 0);
118 /* Last in-page texel for 15-bit. */
119 ASSERT_PIXEL_EQ(expectedTex15Color(63 & 0x1f, 0), 0, 0);
120)
121
122CESTER_TEST(uv15_u64_v0, gpu_raster_phase16,
123 drawTex15At(64, 0);
124 /* First off-page. Wrap mod 64 -> texel(0, 0) = transparent? Or
125 extend into next texpage? */
127)
128
129CESTER_TEST(uv15_u128_v0, gpu_raster_phase16,
130 drawTex15At(128, 0);
131 /* Two pages over. */
133)
134
135CESTER_TEST(uv15_u255_v0, gpu_raster_phase16,
136 drawTex15At(255, 0);
138)
139
140// ============================================================================
141// V wrap. V=255 vs V=256 (8-bit wraps mod 256 to V=0).
142// Note: V is uint8_t in the GP0 command word, so V=256 isn't even
143// representable - it's truncated to 0. But the rasterizer's
144// per-pixel V interpolation could exceed 255 if the triangle is
145// large; that's a separate concern (rect path doesn't interpolate
146// the same way).
147//
148// For rects, V starts at the command UV and increments per row. So
149// V=255 with a 2-row rect would touch V=255 (drawn) and V=256
150// (which wraps via uint8 truncation back to V=0).
151// ============================================================================
152
153/* Reads row 255 of the TEX8 page, which is uninitialized VRAM on
154 real hardware (boot junk left over from BIOS / prior tests).
155 That value can't be reproduced under emulation, so the assertion
156 only holds when running against silicon. Skip in the emulator
157 build (PCSX_TESTS=1) and let the hardware harness gate it. */
158CESTER_MAYBE_TEST(uv8_u0_v255, gpu_raster_phase16,
159 drawTex8At(0, 255);
161)
162
163CESTER_TEST(uv4_u0_v0, gpu_raster_phase16,
164 drawTex4At(0, 0);
165 /* 4-bit baseline. Texel u=0 -> CLUT4[0] = vram555(0, 31, 0). */
166 ASSERT_PIXEL_EQ(expectedClut4Color(0), 0, 0);
167)
168
169CESTER_TEST(uv4_u15_v0, gpu_raster_phase16,
170 drawTex4At(15, 0);
171 /* In-pattern: CLUT4[15] = vram555(15, 16, 0). */
172 ASSERT_PIXEL_EQ(expectedClut4Color(15), 0, 0);
173)
174
175/* Reads u=16 of the TEX4 page, just past the fixture pattern
176 (which only writes u=0..15). The texel comes from uninitialized
177 VRAM, same boot-junk story as uv8_u0_v255. Skip in the emulator
178 build (PCSX_TESTS=1) and let the hardware harness gate it. */
179CESTER_MAYBE_TEST(uv4_u16_v0, gpu_raster_phase16,
180 drawTex4At(16, 0);
182)
183
184CESTER_TEST(uv4_u255_v0, gpu_raster_phase16,
185 drawTex4At(255, 0);
186 /* Last representable U at 4-bit. Still within the 4-bit page
187 (256 wide). Outside fixture data. */
189)
CESTER_BODY(static int s_got40;static int s_got80;static uint32_t s_cause;static uint32_t s_epc;static uint32_t s_from;static uint32_t *s_resume;static uint32_t *s_regs;static uint32_t(*s_customhandler)()=NULL;static uint32_t s_oldIMASK;static uint32_t s_oldDPCR;static uint32_t s_oldDICR;uint32_t handler(uint32_t *regs, uint32_t from) { if(from==0x40) s_got40=1;if(from==0x80) s_got80=1;uint32_t cause;uint32_t epc;s_from=from;asm("mfc0 %0, $13\nnop\nmfc0 %1, $14\nnop" :"=r"(cause), "=r"(epc));s_cause=cause;s_epc=epc;if(s_customhandler) { return s_customhandler();} else { return s_resume ?((uint32_t) s_resume) :(epc+4);} } void installExceptionHandlers(uint32_t(*handler)(uint32_t *regs, uint32_t from));void uninstallExceptionHandlers();uint32_t branchbranch1();uint32_t branchbranch2();uint32_t jumpjump1();uint32_t jumpjump2();uint32_t cpu_LWR_LWL_half(uint32_t buff[], uint32_t initial);uint32_t cpu_LWR_LWL_nodelay(uint32_t buff[], uint32_t initial);uint32_t cpu_LWR_LWL_delayed(uint32_t buff[], uint32_t initial);uint32_t cpu_LWR_LWL_load_different(uint32_t buff[], uint32_t initial);uint32_t cpu_LW_LWR(uint32_t buff[], uint32_t initial);uint32_t cpu_delayed_load(uint32_t buff[], uint32_t override);uint32_t cpu_delayed_load_cancelled(uint32_t buff[], uint32_t override);uint64_t cpu_delayed_load_load(uint32_t buff[], uint32_t override);uint32_t linkandload();uint32_t lwandlink();uint32_t nolink();static int s_interruptsWereEnabled;) CESTER_BEFORE_EACH(cpu_tests
CESTER_TEST(cpu_cop0_basic_write_bp, cpu_tests, uint32_t expectedEPC;uint32_t t;volatile uint32_t *ptr=(volatile uint32_t *) 0x58; *ptr=1;__asm__ volatile("" " lui %0, 0b1100101010000000\n" " mtc0 %0, $7\n" " li %0, 0x58\n" " mtc0 %0, $5\n" " li %0, 0xfffffff0\n" " mtc0 %0, $9\n" :"=r"(t));cester_assert_uint_eq(1, *ptr);__asm__ volatile("la %0, 1f\n1:\nsw $0, 0x58($0)" :"=r"(expectedEPC));__asm__ volatile("mtc0 $0, $7\n");cester_assert_uint_eq(0, *ptr);cester_assert_uint_eq(1, s_got40);cester_assert_uint_eq(0, s_got80);cester_assert_uint_eq(0x40, s_from);cester_assert_uint_eq(expectedEPC, s_epc);) CESTER_TEST(cpu_cop0_kseg_write_bp
#define CESTER_MAYBE_TEST
Definition cop0.c:34
#define UV8_U0_V255
Definition raster-expected-phase16.h:57
#define UV4_U16_V0
Definition raster-expected-phase16.h:70
#define UV15_U128_V0
Definition raster-expected-phase16.h:64
#define UV8_U128_V0
Definition raster-expected-phase16.h:54
#define UV8_U200_V0
Definition raster-expected-phase16.h:55
#define UV15_U64_V0
Definition raster-expected-phase16.h:63
#define UV8_U255_V0
Definition raster-expected-phase16.h:56
#define UV15_U255_V0
Definition raster-expected-phase16.h:65
#define UV4_U255_V0
Definition raster-expected-phase16.h:71
#define ASSERT_PIXEL_UNTOUCHED(x_, y_)
Definition raster-helpers.h:485
#define ASSERT_PIXEL_EQ(expected, x_, y_)
Definition raster-helpers.h:472
#define CLUT8_FIELD
Definition texture-fixtures.h:84
#define TEX15_TY
Definition texture-fixtures.h:66
#define TEX8_TY
Definition texture-fixtures.h:61
#define CLUT4_FIELD
Definition texture-fixtures.h:83
#define CLUT15_FIELD
Definition texture-fixtures.h:85
#define TEX15_TX
Definition texture-fixtures.h:65
#define TEX8_TX
Definition texture-fixtures.h:60
#define TEX_MOD_NEUTRAL
Definition texture-fixtures.h:328
#define TEX4_TY
Definition texture-fixtures.h:56
#define TEX4_TX
Definition texture-fixtures.h:55