// retroDE_ps2 — tb_gs_swizzle_psmt8 (Ch131) // // Source-locked focused contract for `gs_swizzle_psmt8_stub`. // Mirrors the Ch125 PSMCT16 TB shape — 5-phase verification with // independent source-table locks for both the column and block // tables, plus a full-page bijectivity sweep over 128×64 = 8192 // pixels. Per Codex's Ch131 framing: PSMT8 is the third PSM // swizzle math primitive (after Ch119 PSMCT32 + Ch125 PSMCT16); // byte-aligned (1 byte/pixel) so simpler than PSMT4's nibble // packing, but with a wider 128 px page (vs 64 px for direct- // color PSMs) and the new FBW>>1 page-stride constant. // // SOURCE-TABLE PROVENANCE (per Codex's Ch125/Ch131 guidance): // - PCSX2 master HEAD commit // 3000e113e2b3a76357c08dfa80d3c747f40e2706 (current at TB // creation). // - File pcsx2/GS/GSTables.cpp, blob SHA // 3581209b8217378f473f9de22a9dbc8c45ca49b6. // - blockTable8 at lines 53–59 (4 rows × 8 cols, indexed // [block_y_in_page][block_x_in_page]). // - columnTable8 at lines 111–145 (16 rows × 16 cols, indexed // [yb][xb], values are byte-within-block 0..255). // - Cross-check: GSLocalMemory.h:551 BlockNumber8 + // pxOffset template at GSTables.cpp:247–258 (blockSize=256, // pageSize=8192, pageWidth=128) + GSLocalMemory.h:553 asserts // `(bw & 1) == 0` for PSMT8 (FBW must be even). // // Phase layout: // 1 — spot-checks at hand-computed corners (origin, intra- // block, block-grid origins, page boundaries, FBP shift). // 2a — INDEPENDENT column-table source lock: 256 hard-coded // check() calls (one per (yb, xb) inside block (0,0)) where // the expected byte index is taken VERBATIM from PCSX2 // columnTable8 with `1 * ` arithmetic, NOT derived // from the in-TB ref_col_idx8 function. Catches any case // where DUT and ref_col_idx8 happen to share the same // miscopy (the same kind of trap Ch125 added Phase 2a for // with PSMCT16's column table). // 2b — within-block 16×16 walk via the in-TB ref_col_idx8. // Self-check that ref_col_idx8 agrees with the DUT (the // bijectivity sweep below relies on ref_col_idx8 being // correct). // 3 — INDEPENDENT block-table source lock: 32 hard-coded // check() calls (one per block in page 0). Expected block // index taken VERBATIM from PCSX2 blockTable8. // 4 — block-swizzle walk via the in-TB ref_block_idx8. // 5 — bijectivity sweep over the 128×64 page (8192 pixels). // Every pixel must hit a unique byte address in [0, 8192) // and agree with ref_addr8. // + multi-page sanity at FBW=4 (bw_pg=2) crossing both page-x // and page-y, plus non-page-aligned FBP coverage. // // Standalone — no other modules in the dependency chain. `timescale 1ns/1ps module tb_gs_swizzle_psmt8; // ----------------------------------------------------------- // DUT // ----------------------------------------------------------- logic [8:0] fbp; logic [5:0] fbw; logic [11:0] x; logic [11:0] y; logic [31:0] addr; gs_swizzle_psmt8_stub u_dut ( .fbp(fbp), .fbw(fbw), .x(x), .y(y), .addr(addr) ); int errors; initial errors = 0; // ----------------------------------------------------------- // Helpers. // ----------------------------------------------------------- task automatic compute( input logic [8:0] fbp_v, input logic [5:0] fbw_v, input logic [11:0] x_v, input logic [11:0] y_v, output logic [31:0] addr_o); fbp = fbp_v; fbw = fbw_v; x = x_v; y = y_v; #1; addr_o = addr; endtask task automatic check( input logic [8:0] fbp_v, input logic [5:0] fbw_v, input logic [11:0] x_v, input logic [11:0] y_v, input logic [31:0] expected, input string tag); logic [31:0] got; compute(fbp_v, fbw_v, x_v, y_v, got); if (got !== expected) begin $error("[%s] fbp=%0d fbw=%0d (x=%0d,y=%0d) got 0x%08x expected 0x%08x", tag, fbp_v, fbw_v, x_v, y_v, got, expected); errors = errors + 1; end endtask // ----------------------------------------------------------- // Reference tables (verbatim from pcsx2/GS/GSTables.cpp). // ----------------------------------------------------------- function automatic int ref_block_idx8(input int by, input int bx); // _blockTable8[4][8]: // by=0: { 0, 1, 4, 5,16,17,20,21} // by=1: { 2, 3, 6, 7,18,19,22,23} // by=2: { 8, 9,12,13,24,25,28,29} // by=3: {10,11,14,15,26,27,30,31} case ({by[1:0], bx[2:0]}) // by=0 5'd0: return 0; 5'd1: return 1; 5'd2: return 4; 5'd3: return 5; 5'd4: return 16; 5'd5: return 17; 5'd6: return 20; 5'd7: return 21; // by=1 5'd8: return 2; 5'd9: return 3; 5'd10: return 6; 5'd11: return 7; 5'd12: return 18; 5'd13: return 19; 5'd14: return 22; 5'd15: return 23; // by=2 5'd16: return 8; 5'd17: return 9; 5'd18: return 12; 5'd19: return 13; 5'd20: return 24; 5'd21: return 25; 5'd22: return 28; 5'd23: return 29; // by=3 5'd24: return 10; 5'd25: return 11; 5'd26: return 14; 5'd27: return 15; 5'd28: return 26; 5'd29: return 27; 5'd30: return 30; default: return 31; endcase endfunction function automatic int ref_col_idx8(input int yb, input int xb); // columnTable8[16][16] (PCSX2 master GSTables.cpp lines 111–145): // yb=0: 0 4 16 20 32 36 48 52 2 6 18 22 34 38 50 54 // yb=1: 8 12 24 28 40 44 56 60 10 14 26 30 42 46 58 62 // yb=2: 33 37 49 53 1 5 17 21 35 39 51 55 3 7 19 23 // yb=3: 41 45 57 61 9 13 25 29 43 47 59 63 11 15 27 31 // yb=4: 96 100 112 116 64 68 80 84 98 102 114 118 66 70 82 86 // yb=5: 104 108 120 124 72 76 88 92 106 110 122 126 74 78 90 94 // yb=6: 65 69 81 85 97 101 113 117 67 71 83 87 99 103 115 119 // yb=7: 73 77 89 93 105 109 121 125 75 79 91 95 107 111 123 127 // yb=8: 128 132 144 148 160 164 176 180 130 134 146 150 162 166 178 182 // yb=9: 136 140 152 156 168 172 184 188 138 142 154 158 170 174 186 190 // yb=10: 161 165 177 181 129 133 145 149 163 167 179 183 131 135 147 151 // yb=11: 169 173 185 189 137 141 153 157 171 175 187 191 139 143 155 159 // yb=12: 224 228 240 244 192 196 208 212 226 230 242 246 194 198 210 214 // yb=13: 232 236 248 252 200 204 216 220 234 238 250 254 202 206 218 222 // yb=14: 193 197 209 213 225 229 241 245 195 199 211 215 227 231 243 247 // yb=15: 201 205 217 221 233 237 249 253 203 207 219 223 235 239 251 255 case ({yb[3:0], xb[3:0]}) // yb=0 8'd0: return 0; 8'd1: return 4; 8'd2: return 16; 8'd3: return 20; 8'd4: return 32; 8'd5: return 36; 8'd6: return 48; 8'd7: return 52; 8'd8: return 2; 8'd9: return 6; 8'd10: return 18; 8'd11: return 22; 8'd12: return 34; 8'd13: return 38; 8'd14: return 50; 8'd15: return 54; // yb=1 8'd16: return 8; 8'd17: return 12; 8'd18: return 24; 8'd19: return 28; 8'd20: return 40; 8'd21: return 44; 8'd22: return 56; 8'd23: return 60; 8'd24: return 10; 8'd25: return 14; 8'd26: return 26; 8'd27: return 30; 8'd28: return 42; 8'd29: return 46; 8'd30: return 58; 8'd31: return 62; // yb=2 8'd32: return 33; 8'd33: return 37; 8'd34: return 49; 8'd35: return 53; 8'd36: return 1; 8'd37: return 5; 8'd38: return 17; 8'd39: return 21; 8'd40: return 35; 8'd41: return 39; 8'd42: return 51; 8'd43: return 55; 8'd44: return 3; 8'd45: return 7; 8'd46: return 19; 8'd47: return 23; // yb=3 8'd48: return 41; 8'd49: return 45; 8'd50: return 57; 8'd51: return 61; 8'd52: return 9; 8'd53: return 13; 8'd54: return 25; 8'd55: return 29; 8'd56: return 43; 8'd57: return 47; 8'd58: return 59; 8'd59: return 63; 8'd60: return 11; 8'd61: return 15; 8'd62: return 27; 8'd63: return 31; // yb=4 8'd64: return 96; 8'd65: return 100; 8'd66: return 112; 8'd67: return 116; 8'd68: return 64; 8'd69: return 68; 8'd70: return 80; 8'd71: return 84; 8'd72: return 98; 8'd73: return 102; 8'd74: return 114; 8'd75: return 118; 8'd76: return 66; 8'd77: return 70; 8'd78: return 82; 8'd79: return 86; // yb=5 8'd80: return 104; 8'd81: return 108; 8'd82: return 120; 8'd83: return 124; 8'd84: return 72; 8'd85: return 76; 8'd86: return 88; 8'd87: return 92; 8'd88: return 106; 8'd89: return 110; 8'd90: return 122; 8'd91: return 126; 8'd92: return 74; 8'd93: return 78; 8'd94: return 90; 8'd95: return 94; // yb=6 8'd96: return 65; 8'd97: return 69; 8'd98: return 81; 8'd99: return 85; 8'd100: return 97; 8'd101: return 101; 8'd102: return 113; 8'd103: return 117; 8'd104: return 67; 8'd105: return 71; 8'd106: return 83; 8'd107: return 87; 8'd108: return 99; 8'd109: return 103; 8'd110: return 115; 8'd111: return 119; // yb=7 8'd112: return 73; 8'd113: return 77; 8'd114: return 89; 8'd115: return 93; 8'd116: return 105; 8'd117: return 109; 8'd118: return 121; 8'd119: return 125; 8'd120: return 75; 8'd121: return 79; 8'd122: return 91; 8'd123: return 95; 8'd124: return 107; 8'd125: return 111; 8'd126: return 123; 8'd127: return 127; // yb=8 8'd128: return 128; 8'd129: return 132; 8'd130: return 144; 8'd131: return 148; 8'd132: return 160; 8'd133: return 164; 8'd134: return 176; 8'd135: return 180; 8'd136: return 130; 8'd137: return 134; 8'd138: return 146; 8'd139: return 150; 8'd140: return 162; 8'd141: return 166; 8'd142: return 178; 8'd143: return 182; // yb=9 8'd144: return 136; 8'd145: return 140; 8'd146: return 152; 8'd147: return 156; 8'd148: return 168; 8'd149: return 172; 8'd150: return 184; 8'd151: return 188; 8'd152: return 138; 8'd153: return 142; 8'd154: return 154; 8'd155: return 158; 8'd156: return 170; 8'd157: return 174; 8'd158: return 186; 8'd159: return 190; // yb=10 8'd160: return 161; 8'd161: return 165; 8'd162: return 177; 8'd163: return 181; 8'd164: return 129; 8'd165: return 133; 8'd166: return 145; 8'd167: return 149; 8'd168: return 163; 8'd169: return 167; 8'd170: return 179; 8'd171: return 183; 8'd172: return 131; 8'd173: return 135; 8'd174: return 147; 8'd175: return 151; // yb=11 8'd176: return 169; 8'd177: return 173; 8'd178: return 185; 8'd179: return 189; 8'd180: return 137; 8'd181: return 141; 8'd182: return 153; 8'd183: return 157; 8'd184: return 171; 8'd185: return 175; 8'd186: return 187; 8'd187: return 191; 8'd188: return 139; 8'd189: return 143; 8'd190: return 155; 8'd191: return 159; // yb=12 8'd192: return 224; 8'd193: return 228; 8'd194: return 240; 8'd195: return 244; 8'd196: return 192; 8'd197: return 196; 8'd198: return 208; 8'd199: return 212; 8'd200: return 226; 8'd201: return 230; 8'd202: return 242; 8'd203: return 246; 8'd204: return 194; 8'd205: return 198; 8'd206: return 210; 8'd207: return 214; // yb=13 8'd208: return 232; 8'd209: return 236; 8'd210: return 248; 8'd211: return 252; 8'd212: return 200; 8'd213: return 204; 8'd214: return 216; 8'd215: return 220; 8'd216: return 234; 8'd217: return 238; 8'd218: return 250; 8'd219: return 254; 8'd220: return 202; 8'd221: return 206; 8'd222: return 218; 8'd223: return 222; // yb=14 8'd224: return 193; 8'd225: return 197; 8'd226: return 209; 8'd227: return 213; 8'd228: return 225; 8'd229: return 229; 8'd230: return 241; 8'd231: return 245; 8'd232: return 195; 8'd233: return 199; 8'd234: return 211; 8'd235: return 215; 8'd236: return 227; 8'd237: return 231; 8'd238: return 243; 8'd239: return 247; // yb=15 8'd240: return 201; 8'd241: return 205; 8'd242: return 217; 8'd243: return 221; 8'd244: return 233; 8'd245: return 237; 8'd246: return 249; 8'd247: return 253; 8'd248: return 203; 8'd249: return 207; 8'd250: return 219; 8'd251: return 223; 8'd252: return 235; 8'd253: return 239; 8'd254: return 251; default: return 255; endcase endfunction function automatic logic [31:0] ref_addr8( input int fbp_v, input int fbw_v, input int x_v, input int y_v); int page_x, page_y, bw_pg_v, page_idx, page_base; int by, bx, blk_idx, xb, yb, byte_idx; int addr_v; page_x = x_v / 128; page_y = y_v / 64; bw_pg_v = fbw_v / 2; page_idx = page_y * bw_pg_v + page_x; page_base = fbp_v * 2048 + page_idx * 8192; by = (y_v % 64) / 16; bx = (x_v % 128) / 16; blk_idx = ref_block_idx8(by, bx); xb = x_v % 16; yb = y_v % 16; byte_idx = ref_col_idx8(yb, xb); addr_v = page_base + blk_idx * 256 + byte_idx; return addr_v[31:0]; endfunction initial begin fbp = 9'd0; fbw = 6'd2; // PSMT8: FBW must be even (PCSX2 asserts (bw & 1) == 0) x = 12'd0; y = 12'd0; #1; // ----------------------------------------------------------- // Phase 1 — spot-checks (hand-computed corners). FBW=2 → // bw_pg=1, so a single page per row of pages. // ----------------------------------------------------------- // (0, 0) → block (0,0)=0, byte=0 → addr 0. check(9'd0, 6'd2, 12'd0, 12'd0, 32'd0, "origin"); // (1, 0) → block 0, xb=1 yb=0 → byte=4 → addr 4. check(9'd0, 6'd2, 12'd1, 12'd0, 32'd4, "intra-block-x1"); // (4, 0) → block 0, xb=4 yb=0 → byte=32. check(9'd0, 6'd2, 12'd4, 12'd0, 32'd32, "intra-block-x4"); // (8, 0) → block 0, xb=8 yb=0 → byte=2. check(9'd0, 6'd2, 12'd8, 12'd0, 32'd2, "intra-block-x8"); // (0, 1) → block 0, xb=0 yb=1 → byte=8. check(9'd0, 6'd2, 12'd0, 12'd1, 32'd8, "intra-block-y1"); // (15, 15) → last byte of block (0,0): xb=15 yb=15 → byte=255. check(9'd0, 6'd2, 12'd15, 12'd15, 32'd255, "block-(0,0)-last"); // (16, 0) → block (0,1) (by=0, bx=1) → blockTable8[0][1]=1 → // block_base=256. xb=0 yb=0 → byte=0 → addr 256. check(9'd0, 6'd2, 12'd16, 12'd0, 32'd256, "block-(0,1)-origin"); // (0, 16) → block (1,0) (by=1, bx=0) → blockTable8[1][0]=2 → // block_base=512. check(9'd0, 6'd2, 12'd0, 12'd16, 32'd512, "block-(1,0)-origin"); // (32, 0) → block (0,2) → blockTable8[0][2]=4 → block_base=1024. check(9'd0, 6'd2, 12'd32, 12'd0, 32'd1024, "block-(0,2)-origin"); // (0, 32) → block (2,0) → blockTable8[2][0]=8 → block_base=2048. check(9'd0, 6'd2, 12'd0, 12'd32, 32'd2048, "block-(2,0)-origin"); // (64, 0) → block (0,4) → blockTable8[0][4]=16 → block_base=4096. check(9'd0, 6'd2, 12'd64, 12'd0, 32'd4096, "block-(0,4)-origin"); // (127, 63) → last pixel of last block of page 0: // block (3,7) → blockTable8[3][7]=31 → block_base=7936. // xb=15 yb=15 → byte=255 → addr = 7936 + 255 = 8191. check(9'd0, 6'd2, 12'd127, 12'd63, 32'd8191, "page0-last-pixel"); // (128, 0) → start of page 1 (FBW=2, bw_pg=1) → page_idx=1, // page_base=8192 → addr 8192. check(9'd0, 6'd2, 12'd128, 12'd0, 32'd8192, "page1-x-origin"); // (0, 64) → start of page-row 1 (bw_pg=1) → page_idx=1, // page_base=8192. check(9'd0, 6'd2, 12'd0, 12'd64, 32'd8192, "page1-y-origin"); // FBP=4 → FBP*2048=8192 = 1 page. (0,0) → addr 8192. check(9'd4, 6'd2, 12'd0, 12'd0, 32'd8192, "fbp4-origin"); // ----------------------------------------------------------- // Phase 2a — INDEPENDENT column-table source lock. 256 hard- // coded address checks (one per (yb, xb) inside block (0,0)) // where the expected byte index is taken VERBATIM from PCSX2 // columnTable8, NOT derived from the in-TB ref_col_idx8. // pixel (xb, yb) at FBP=0, FBW=2 lands in page (0,0), block // (0,0) → swizzle 0 → block_base 0; expected addr = byte. // ----------------------------------------------------------- // yb=0: 0 4 16 20 32 36 48 52 2 6 18 22 34 38 50 54 check(9'd0, 6'd2, 12'd0, 12'd0, 32'd0, "col-yb0-xb0"); check(9'd0, 6'd2, 12'd1, 12'd0, 32'd4, "col-yb0-xb1"); check(9'd0, 6'd2, 12'd2, 12'd0, 32'd16, "col-yb0-xb2"); check(9'd0, 6'd2, 12'd3, 12'd0, 32'd20, "col-yb0-xb3"); check(9'd0, 6'd2, 12'd4, 12'd0, 32'd32, "col-yb0-xb4"); check(9'd0, 6'd2, 12'd5, 12'd0, 32'd36, "col-yb0-xb5"); check(9'd0, 6'd2, 12'd6, 12'd0, 32'd48, "col-yb0-xb6"); check(9'd0, 6'd2, 12'd7, 12'd0, 32'd52, "col-yb0-xb7"); check(9'd0, 6'd2, 12'd8, 12'd0, 32'd2, "col-yb0-xb8"); check(9'd0, 6'd2, 12'd9, 12'd0, 32'd6, "col-yb0-xb9"); check(9'd0, 6'd2, 12'd10, 12'd0, 32'd18, "col-yb0-xb10"); check(9'd0, 6'd2, 12'd11, 12'd0, 32'd22, "col-yb0-xb11"); check(9'd0, 6'd2, 12'd12, 12'd0, 32'd34, "col-yb0-xb12"); check(9'd0, 6'd2, 12'd13, 12'd0, 32'd38, "col-yb0-xb13"); check(9'd0, 6'd2, 12'd14, 12'd0, 32'd50, "col-yb0-xb14"); check(9'd0, 6'd2, 12'd15, 12'd0, 32'd54, "col-yb0-xb15"); // yb=1: 8 12 24 28 40 44 56 60 10 14 26 30 42 46 58 62 check(9'd0, 6'd2, 12'd0, 12'd1, 32'd8, "col-yb1-xb0"); check(9'd0, 6'd2, 12'd1, 12'd1, 32'd12, "col-yb1-xb1"); check(9'd0, 6'd2, 12'd2, 12'd1, 32'd24, "col-yb1-xb2"); check(9'd0, 6'd2, 12'd3, 12'd1, 32'd28, "col-yb1-xb3"); check(9'd0, 6'd2, 12'd4, 12'd1, 32'd40, "col-yb1-xb4"); check(9'd0, 6'd2, 12'd5, 12'd1, 32'd44, "col-yb1-xb5"); check(9'd0, 6'd2, 12'd6, 12'd1, 32'd56, "col-yb1-xb6"); check(9'd0, 6'd2, 12'd7, 12'd1, 32'd60, "col-yb1-xb7"); check(9'd0, 6'd2, 12'd8, 12'd1, 32'd10, "col-yb1-xb8"); check(9'd0, 6'd2, 12'd9, 12'd1, 32'd14, "col-yb1-xb9"); check(9'd0, 6'd2, 12'd10, 12'd1, 32'd26, "col-yb1-xb10"); check(9'd0, 6'd2, 12'd11, 12'd1, 32'd30, "col-yb1-xb11"); check(9'd0, 6'd2, 12'd12, 12'd1, 32'd42, "col-yb1-xb12"); check(9'd0, 6'd2, 12'd13, 12'd1, 32'd46, "col-yb1-xb13"); check(9'd0, 6'd2, 12'd14, 12'd1, 32'd58, "col-yb1-xb14"); check(9'd0, 6'd2, 12'd15, 12'd1, 32'd62, "col-yb1-xb15"); // yb=2: 33 37 49 53 1 5 17 21 35 39 51 55 3 7 19 23 check(9'd0, 6'd2, 12'd0, 12'd2, 32'd33, "col-yb2-xb0"); check(9'd0, 6'd2, 12'd1, 12'd2, 32'd37, "col-yb2-xb1"); check(9'd0, 6'd2, 12'd2, 12'd2, 32'd49, "col-yb2-xb2"); check(9'd0, 6'd2, 12'd3, 12'd2, 32'd53, "col-yb2-xb3"); check(9'd0, 6'd2, 12'd4, 12'd2, 32'd1, "col-yb2-xb4"); check(9'd0, 6'd2, 12'd5, 12'd2, 32'd5, "col-yb2-xb5"); check(9'd0, 6'd2, 12'd6, 12'd2, 32'd17, "col-yb2-xb6"); check(9'd0, 6'd2, 12'd7, 12'd2, 32'd21, "col-yb2-xb7"); check(9'd0, 6'd2, 12'd8, 12'd2, 32'd35, "col-yb2-xb8"); check(9'd0, 6'd2, 12'd9, 12'd2, 32'd39, "col-yb2-xb9"); check(9'd0, 6'd2, 12'd10, 12'd2, 32'd51, "col-yb2-xb10"); check(9'd0, 6'd2, 12'd11, 12'd2, 32'd55, "col-yb2-xb11"); check(9'd0, 6'd2, 12'd12, 12'd2, 32'd3, "col-yb2-xb12"); check(9'd0, 6'd2, 12'd13, 12'd2, 32'd7, "col-yb2-xb13"); check(9'd0, 6'd2, 12'd14, 12'd2, 32'd19, "col-yb2-xb14"); check(9'd0, 6'd2, 12'd15, 12'd2, 32'd23, "col-yb2-xb15"); // yb=3: 41 45 57 61 9 13 25 29 43 47 59 63 11 15 27 31 check(9'd0, 6'd2, 12'd0, 12'd3, 32'd41, "col-yb3-xb0"); check(9'd0, 6'd2, 12'd1, 12'd3, 32'd45, "col-yb3-xb1"); check(9'd0, 6'd2, 12'd2, 12'd3, 32'd57, "col-yb3-xb2"); check(9'd0, 6'd2, 12'd3, 12'd3, 32'd61, "col-yb3-xb3"); check(9'd0, 6'd2, 12'd4, 12'd3, 32'd9, "col-yb3-xb4"); check(9'd0, 6'd2, 12'd5, 12'd3, 32'd13, "col-yb3-xb5"); check(9'd0, 6'd2, 12'd6, 12'd3, 32'd25, "col-yb3-xb6"); check(9'd0, 6'd2, 12'd7, 12'd3, 32'd29, "col-yb3-xb7"); check(9'd0, 6'd2, 12'd8, 12'd3, 32'd43, "col-yb3-xb8"); check(9'd0, 6'd2, 12'd9, 12'd3, 32'd47, "col-yb3-xb9"); check(9'd0, 6'd2, 12'd10, 12'd3, 32'd59, "col-yb3-xb10"); check(9'd0, 6'd2, 12'd11, 12'd3, 32'd63, "col-yb3-xb11"); check(9'd0, 6'd2, 12'd12, 12'd3, 32'd11, "col-yb3-xb12"); check(9'd0, 6'd2, 12'd13, 12'd3, 32'd15, "col-yb3-xb13"); check(9'd0, 6'd2, 12'd14, 12'd3, 32'd27, "col-yb3-xb14"); check(9'd0, 6'd2, 12'd15, 12'd3, 32'd31, "col-yb3-xb15"); // yb=4: 96 100 112 116 64 68 80 84 98 102 114 118 66 70 82 86 check(9'd0, 6'd2, 12'd0, 12'd4, 32'd96, "col-yb4-xb0"); check(9'd0, 6'd2, 12'd1, 12'd4, 32'd100, "col-yb4-xb1"); check(9'd0, 6'd2, 12'd2, 12'd4, 32'd112, "col-yb4-xb2"); check(9'd0, 6'd2, 12'd3, 12'd4, 32'd116, "col-yb4-xb3"); check(9'd0, 6'd2, 12'd4, 12'd4, 32'd64, "col-yb4-xb4"); check(9'd0, 6'd2, 12'd5, 12'd4, 32'd68, "col-yb4-xb5"); check(9'd0, 6'd2, 12'd6, 12'd4, 32'd80, "col-yb4-xb6"); check(9'd0, 6'd2, 12'd7, 12'd4, 32'd84, "col-yb4-xb7"); check(9'd0, 6'd2, 12'd8, 12'd4, 32'd98, "col-yb4-xb8"); check(9'd0, 6'd2, 12'd9, 12'd4, 32'd102, "col-yb4-xb9"); check(9'd0, 6'd2, 12'd10, 12'd4, 32'd114, "col-yb4-xb10"); check(9'd0, 6'd2, 12'd11, 12'd4, 32'd118, "col-yb4-xb11"); check(9'd0, 6'd2, 12'd12, 12'd4, 32'd66, "col-yb4-xb12"); check(9'd0, 6'd2, 12'd13, 12'd4, 32'd70, "col-yb4-xb13"); check(9'd0, 6'd2, 12'd14, 12'd4, 32'd82, "col-yb4-xb14"); check(9'd0, 6'd2, 12'd15, 12'd4, 32'd86, "col-yb4-xb15"); // yb=5: 104 108 120 124 72 76 88 92 106 110 122 126 74 78 90 94 check(9'd0, 6'd2, 12'd0, 12'd5, 32'd104, "col-yb5-xb0"); check(9'd0, 6'd2, 12'd1, 12'd5, 32'd108, "col-yb5-xb1"); check(9'd0, 6'd2, 12'd2, 12'd5, 32'd120, "col-yb5-xb2"); check(9'd0, 6'd2, 12'd3, 12'd5, 32'd124, "col-yb5-xb3"); check(9'd0, 6'd2, 12'd4, 12'd5, 32'd72, "col-yb5-xb4"); check(9'd0, 6'd2, 12'd5, 12'd5, 32'd76, "col-yb5-xb5"); check(9'd0, 6'd2, 12'd6, 12'd5, 32'd88, "col-yb5-xb6"); check(9'd0, 6'd2, 12'd7, 12'd5, 32'd92, "col-yb5-xb7"); check(9'd0, 6'd2, 12'd8, 12'd5, 32'd106, "col-yb5-xb8"); check(9'd0, 6'd2, 12'd9, 12'd5, 32'd110, "col-yb5-xb9"); check(9'd0, 6'd2, 12'd10, 12'd5, 32'd122, "col-yb5-xb10"); check(9'd0, 6'd2, 12'd11, 12'd5, 32'd126, "col-yb5-xb11"); check(9'd0, 6'd2, 12'd12, 12'd5, 32'd74, "col-yb5-xb12"); check(9'd0, 6'd2, 12'd13, 12'd5, 32'd78, "col-yb5-xb13"); check(9'd0, 6'd2, 12'd14, 12'd5, 32'd90, "col-yb5-xb14"); check(9'd0, 6'd2, 12'd15, 12'd5, 32'd94, "col-yb5-xb15"); // yb=6: 65 69 81 85 97 101 113 117 67 71 83 87 99 103 115 119 check(9'd0, 6'd2, 12'd0, 12'd6, 32'd65, "col-yb6-xb0"); check(9'd0, 6'd2, 12'd1, 12'd6, 32'd69, "col-yb6-xb1"); check(9'd0, 6'd2, 12'd2, 12'd6, 32'd81, "col-yb6-xb2"); check(9'd0, 6'd2, 12'd3, 12'd6, 32'd85, "col-yb6-xb3"); check(9'd0, 6'd2, 12'd4, 12'd6, 32'd97, "col-yb6-xb4"); check(9'd0, 6'd2, 12'd5, 12'd6, 32'd101, "col-yb6-xb5"); check(9'd0, 6'd2, 12'd6, 12'd6, 32'd113, "col-yb6-xb6"); check(9'd0, 6'd2, 12'd7, 12'd6, 32'd117, "col-yb6-xb7"); check(9'd0, 6'd2, 12'd8, 12'd6, 32'd67, "col-yb6-xb8"); check(9'd0, 6'd2, 12'd9, 12'd6, 32'd71, "col-yb6-xb9"); check(9'd0, 6'd2, 12'd10, 12'd6, 32'd83, "col-yb6-xb10"); check(9'd0, 6'd2, 12'd11, 12'd6, 32'd87, "col-yb6-xb11"); check(9'd0, 6'd2, 12'd12, 12'd6, 32'd99, "col-yb6-xb12"); check(9'd0, 6'd2, 12'd13, 12'd6, 32'd103, "col-yb6-xb13"); check(9'd0, 6'd2, 12'd14, 12'd6, 32'd115, "col-yb6-xb14"); check(9'd0, 6'd2, 12'd15, 12'd6, 32'd119, "col-yb6-xb15"); // yb=7: 73 77 89 93 105 109 121 125 75 79 91 95 107 111 123 127 check(9'd0, 6'd2, 12'd0, 12'd7, 32'd73, "col-yb7-xb0"); check(9'd0, 6'd2, 12'd1, 12'd7, 32'd77, "col-yb7-xb1"); check(9'd0, 6'd2, 12'd2, 12'd7, 32'd89, "col-yb7-xb2"); check(9'd0, 6'd2, 12'd3, 12'd7, 32'd93, "col-yb7-xb3"); check(9'd0, 6'd2, 12'd4, 12'd7, 32'd105, "col-yb7-xb4"); check(9'd0, 6'd2, 12'd5, 12'd7, 32'd109, "col-yb7-xb5"); check(9'd0, 6'd2, 12'd6, 12'd7, 32'd121, "col-yb7-xb6"); check(9'd0, 6'd2, 12'd7, 12'd7, 32'd125, "col-yb7-xb7"); check(9'd0, 6'd2, 12'd8, 12'd7, 32'd75, "col-yb7-xb8"); check(9'd0, 6'd2, 12'd9, 12'd7, 32'd79, "col-yb7-xb9"); check(9'd0, 6'd2, 12'd10, 12'd7, 32'd91, "col-yb7-xb10"); check(9'd0, 6'd2, 12'd11, 12'd7, 32'd95, "col-yb7-xb11"); check(9'd0, 6'd2, 12'd12, 12'd7, 32'd107, "col-yb7-xb12"); check(9'd0, 6'd2, 12'd13, 12'd7, 32'd111, "col-yb7-xb13"); check(9'd0, 6'd2, 12'd14, 12'd7, 32'd123, "col-yb7-xb14"); check(9'd0, 6'd2, 12'd15, 12'd7, 32'd127, "col-yb7-xb15"); // yb=8: 128 132 144 148 160 164 176 180 130 134 146 150 162 166 178 182 check(9'd0, 6'd2, 12'd0, 12'd8, 32'd128, "col-yb8-xb0"); check(9'd0, 6'd2, 12'd1, 12'd8, 32'd132, "col-yb8-xb1"); check(9'd0, 6'd2, 12'd2, 12'd8, 32'd144, "col-yb8-xb2"); check(9'd0, 6'd2, 12'd3, 12'd8, 32'd148, "col-yb8-xb3"); check(9'd0, 6'd2, 12'd4, 12'd8, 32'd160, "col-yb8-xb4"); check(9'd0, 6'd2, 12'd5, 12'd8, 32'd164, "col-yb8-xb5"); check(9'd0, 6'd2, 12'd6, 12'd8, 32'd176, "col-yb8-xb6"); check(9'd0, 6'd2, 12'd7, 12'd8, 32'd180, "col-yb8-xb7"); check(9'd0, 6'd2, 12'd8, 12'd8, 32'd130, "col-yb8-xb8"); check(9'd0, 6'd2, 12'd9, 12'd8, 32'd134, "col-yb8-xb9"); check(9'd0, 6'd2, 12'd10, 12'd8, 32'd146, "col-yb8-xb10"); check(9'd0, 6'd2, 12'd11, 12'd8, 32'd150, "col-yb8-xb11"); check(9'd0, 6'd2, 12'd12, 12'd8, 32'd162, "col-yb8-xb12"); check(9'd0, 6'd2, 12'd13, 12'd8, 32'd166, "col-yb8-xb13"); check(9'd0, 6'd2, 12'd14, 12'd8, 32'd178, "col-yb8-xb14"); check(9'd0, 6'd2, 12'd15, 12'd8, 32'd182, "col-yb8-xb15"); // yb=9: 136 140 152 156 168 172 184 188 138 142 154 158 170 174 186 190 check(9'd0, 6'd2, 12'd0, 12'd9, 32'd136, "col-yb9-xb0"); check(9'd0, 6'd2, 12'd1, 12'd9, 32'd140, "col-yb9-xb1"); check(9'd0, 6'd2, 12'd2, 12'd9, 32'd152, "col-yb9-xb2"); check(9'd0, 6'd2, 12'd3, 12'd9, 32'd156, "col-yb9-xb3"); check(9'd0, 6'd2, 12'd4, 12'd9, 32'd168, "col-yb9-xb4"); check(9'd0, 6'd2, 12'd5, 12'd9, 32'd172, "col-yb9-xb5"); check(9'd0, 6'd2, 12'd6, 12'd9, 32'd184, "col-yb9-xb6"); check(9'd0, 6'd2, 12'd7, 12'd9, 32'd188, "col-yb9-xb7"); check(9'd0, 6'd2, 12'd8, 12'd9, 32'd138, "col-yb9-xb8"); check(9'd0, 6'd2, 12'd9, 12'd9, 32'd142, "col-yb9-xb9"); check(9'd0, 6'd2, 12'd10, 12'd9, 32'd154, "col-yb9-xb10"); check(9'd0, 6'd2, 12'd11, 12'd9, 32'd158, "col-yb9-xb11"); check(9'd0, 6'd2, 12'd12, 12'd9, 32'd170, "col-yb9-xb12"); check(9'd0, 6'd2, 12'd13, 12'd9, 32'd174, "col-yb9-xb13"); check(9'd0, 6'd2, 12'd14, 12'd9, 32'd186, "col-yb9-xb14"); check(9'd0, 6'd2, 12'd15, 12'd9, 32'd190, "col-yb9-xb15"); // yb=10: 161 165 177 181 129 133 145 149 163 167 179 183 131 135 147 151 check(9'd0, 6'd2, 12'd0, 12'd10, 32'd161, "col-yb10-xb0"); check(9'd0, 6'd2, 12'd1, 12'd10, 32'd165, "col-yb10-xb1"); check(9'd0, 6'd2, 12'd2, 12'd10, 32'd177, "col-yb10-xb2"); check(9'd0, 6'd2, 12'd3, 12'd10, 32'd181, "col-yb10-xb3"); check(9'd0, 6'd2, 12'd4, 12'd10, 32'd129, "col-yb10-xb4"); check(9'd0, 6'd2, 12'd5, 12'd10, 32'd133, "col-yb10-xb5"); check(9'd0, 6'd2, 12'd6, 12'd10, 32'd145, "col-yb10-xb6"); check(9'd0, 6'd2, 12'd7, 12'd10, 32'd149, "col-yb10-xb7"); check(9'd0, 6'd2, 12'd8, 12'd10, 32'd163, "col-yb10-xb8"); check(9'd0, 6'd2, 12'd9, 12'd10, 32'd167, "col-yb10-xb9"); check(9'd0, 6'd2, 12'd10, 12'd10, 32'd179, "col-yb10-xb10"); check(9'd0, 6'd2, 12'd11, 12'd10, 32'd183, "col-yb10-xb11"); check(9'd0, 6'd2, 12'd12, 12'd10, 32'd131, "col-yb10-xb12"); check(9'd0, 6'd2, 12'd13, 12'd10, 32'd135, "col-yb10-xb13"); check(9'd0, 6'd2, 12'd14, 12'd10, 32'd147, "col-yb10-xb14"); check(9'd0, 6'd2, 12'd15, 12'd10, 32'd151, "col-yb10-xb15"); // yb=11: 169 173 185 189 137 141 153 157 171 175 187 191 139 143 155 159 check(9'd0, 6'd2, 12'd0, 12'd11, 32'd169, "col-yb11-xb0"); check(9'd0, 6'd2, 12'd1, 12'd11, 32'd173, "col-yb11-xb1"); check(9'd0, 6'd2, 12'd2, 12'd11, 32'd185, "col-yb11-xb2"); check(9'd0, 6'd2, 12'd3, 12'd11, 32'd189, "col-yb11-xb3"); check(9'd0, 6'd2, 12'd4, 12'd11, 32'd137, "col-yb11-xb4"); check(9'd0, 6'd2, 12'd5, 12'd11, 32'd141, "col-yb11-xb5"); check(9'd0, 6'd2, 12'd6, 12'd11, 32'd153, "col-yb11-xb6"); check(9'd0, 6'd2, 12'd7, 12'd11, 32'd157, "col-yb11-xb7"); check(9'd0, 6'd2, 12'd8, 12'd11, 32'd171, "col-yb11-xb8"); check(9'd0, 6'd2, 12'd9, 12'd11, 32'd175, "col-yb11-xb9"); check(9'd0, 6'd2, 12'd10, 12'd11, 32'd187, "col-yb11-xb10"); check(9'd0, 6'd2, 12'd11, 12'd11, 32'd191, "col-yb11-xb11"); check(9'd0, 6'd2, 12'd12, 12'd11, 32'd139, "col-yb11-xb12"); check(9'd0, 6'd2, 12'd13, 12'd11, 32'd143, "col-yb11-xb13"); check(9'd0, 6'd2, 12'd14, 12'd11, 32'd155, "col-yb11-xb14"); check(9'd0, 6'd2, 12'd15, 12'd11, 32'd159, "col-yb11-xb15"); // yb=12: 224 228 240 244 192 196 208 212 226 230 242 246 194 198 210 214 check(9'd0, 6'd2, 12'd0, 12'd12, 32'd224, "col-yb12-xb0"); check(9'd0, 6'd2, 12'd1, 12'd12, 32'd228, "col-yb12-xb1"); check(9'd0, 6'd2, 12'd2, 12'd12, 32'd240, "col-yb12-xb2"); check(9'd0, 6'd2, 12'd3, 12'd12, 32'd244, "col-yb12-xb3"); check(9'd0, 6'd2, 12'd4, 12'd12, 32'd192, "col-yb12-xb4"); check(9'd0, 6'd2, 12'd5, 12'd12, 32'd196, "col-yb12-xb5"); check(9'd0, 6'd2, 12'd6, 12'd12, 32'd208, "col-yb12-xb6"); check(9'd0, 6'd2, 12'd7, 12'd12, 32'd212, "col-yb12-xb7"); check(9'd0, 6'd2, 12'd8, 12'd12, 32'd226, "col-yb12-xb8"); check(9'd0, 6'd2, 12'd9, 12'd12, 32'd230, "col-yb12-xb9"); check(9'd0, 6'd2, 12'd10, 12'd12, 32'd242, "col-yb12-xb10"); check(9'd0, 6'd2, 12'd11, 12'd12, 32'd246, "col-yb12-xb11"); check(9'd0, 6'd2, 12'd12, 12'd12, 32'd194, "col-yb12-xb12"); check(9'd0, 6'd2, 12'd13, 12'd12, 32'd198, "col-yb12-xb13"); check(9'd0, 6'd2, 12'd14, 12'd12, 32'd210, "col-yb12-xb14"); check(9'd0, 6'd2, 12'd15, 12'd12, 32'd214, "col-yb12-xb15"); // yb=13: 232 236 248 252 200 204 216 220 234 238 250 254 202 206 218 222 check(9'd0, 6'd2, 12'd0, 12'd13, 32'd232, "col-yb13-xb0"); check(9'd0, 6'd2, 12'd1, 12'd13, 32'd236, "col-yb13-xb1"); check(9'd0, 6'd2, 12'd2, 12'd13, 32'd248, "col-yb13-xb2"); check(9'd0, 6'd2, 12'd3, 12'd13, 32'd252, "col-yb13-xb3"); check(9'd0, 6'd2, 12'd4, 12'd13, 32'd200, "col-yb13-xb4"); check(9'd0, 6'd2, 12'd5, 12'd13, 32'd204, "col-yb13-xb5"); check(9'd0, 6'd2, 12'd6, 12'd13, 32'd216, "col-yb13-xb6"); check(9'd0, 6'd2, 12'd7, 12'd13, 32'd220, "col-yb13-xb7"); check(9'd0, 6'd2, 12'd8, 12'd13, 32'd234, "col-yb13-xb8"); check(9'd0, 6'd2, 12'd9, 12'd13, 32'd238, "col-yb13-xb9"); check(9'd0, 6'd2, 12'd10, 12'd13, 32'd250, "col-yb13-xb10"); check(9'd0, 6'd2, 12'd11, 12'd13, 32'd254, "col-yb13-xb11"); check(9'd0, 6'd2, 12'd12, 12'd13, 32'd202, "col-yb13-xb12"); check(9'd0, 6'd2, 12'd13, 12'd13, 32'd206, "col-yb13-xb13"); check(9'd0, 6'd2, 12'd14, 12'd13, 32'd218, "col-yb13-xb14"); check(9'd0, 6'd2, 12'd15, 12'd13, 32'd222, "col-yb13-xb15"); // yb=14: 193 197 209 213 225 229 241 245 195 199 211 215 227 231 243 247 check(9'd0, 6'd2, 12'd0, 12'd14, 32'd193, "col-yb14-xb0"); check(9'd0, 6'd2, 12'd1, 12'd14, 32'd197, "col-yb14-xb1"); check(9'd0, 6'd2, 12'd2, 12'd14, 32'd209, "col-yb14-xb2"); check(9'd0, 6'd2, 12'd3, 12'd14, 32'd213, "col-yb14-xb3"); check(9'd0, 6'd2, 12'd4, 12'd14, 32'd225, "col-yb14-xb4"); check(9'd0, 6'd2, 12'd5, 12'd14, 32'd229, "col-yb14-xb5"); check(9'd0, 6'd2, 12'd6, 12'd14, 32'd241, "col-yb14-xb6"); check(9'd0, 6'd2, 12'd7, 12'd14, 32'd245, "col-yb14-xb7"); check(9'd0, 6'd2, 12'd8, 12'd14, 32'd195, "col-yb14-xb8"); check(9'd0, 6'd2, 12'd9, 12'd14, 32'd199, "col-yb14-xb9"); check(9'd0, 6'd2, 12'd10, 12'd14, 32'd211, "col-yb14-xb10"); check(9'd0, 6'd2, 12'd11, 12'd14, 32'd215, "col-yb14-xb11"); check(9'd0, 6'd2, 12'd12, 12'd14, 32'd227, "col-yb14-xb12"); check(9'd0, 6'd2, 12'd13, 12'd14, 32'd231, "col-yb14-xb13"); check(9'd0, 6'd2, 12'd14, 12'd14, 32'd243, "col-yb14-xb14"); check(9'd0, 6'd2, 12'd15, 12'd14, 32'd247, "col-yb14-xb15"); // yb=15: 201 205 217 221 233 237 249 253 203 207 219 223 235 239 251 255 check(9'd0, 6'd2, 12'd0, 12'd15, 32'd201, "col-yb15-xb0"); check(9'd0, 6'd2, 12'd1, 12'd15, 32'd205, "col-yb15-xb1"); check(9'd0, 6'd2, 12'd2, 12'd15, 32'd217, "col-yb15-xb2"); check(9'd0, 6'd2, 12'd3, 12'd15, 32'd221, "col-yb15-xb3"); check(9'd0, 6'd2, 12'd4, 12'd15, 32'd233, "col-yb15-xb4"); check(9'd0, 6'd2, 12'd5, 12'd15, 32'd237, "col-yb15-xb5"); check(9'd0, 6'd2, 12'd6, 12'd15, 32'd249, "col-yb15-xb6"); check(9'd0, 6'd2, 12'd7, 12'd15, 32'd253, "col-yb15-xb7"); check(9'd0, 6'd2, 12'd8, 12'd15, 32'd203, "col-yb15-xb8"); check(9'd0, 6'd2, 12'd9, 12'd15, 32'd207, "col-yb15-xb9"); check(9'd0, 6'd2, 12'd10, 12'd15, 32'd219, "col-yb15-xb10"); check(9'd0, 6'd2, 12'd11, 12'd15, 32'd223, "col-yb15-xb11"); check(9'd0, 6'd2, 12'd12, 12'd15, 32'd235, "col-yb15-xb12"); check(9'd0, 6'd2, 12'd13, 12'd15, 32'd239, "col-yb15-xb13"); check(9'd0, 6'd2, 12'd14, 12'd15, 32'd251, "col-yb15-xb14"); check(9'd0, 6'd2, 12'd15, 12'd15, 32'd255, "col-yb15-xb15"); // ----------------------------------------------------------- // Phase 2b — within-block 16×16 walk via the in-TB // ref_col_idx8. Self-check that ref_col_idx8 agrees with // the DUT. // ----------------------------------------------------------- for (int yb_i = 0; yb_i < 16; yb_i++) begin for (int xb_i = 0; xb_i < 16; xb_i++) begin logic [31:0] expected; expected = 32'(ref_col_idx8(yb_i, xb_i)); check(9'd0, 6'd2, 12'(xb_i), 12'(yb_i), expected, "within-block-col-table"); end end // ----------------------------------------------------------- // Phase 3 — INDEPENDENT block-table source lock. 32 hard- // coded address checks, one per block in page 0. Expected // block index taken VERBATIM from PCSX2 blockTable8 (NOT // derived from ref_block_idx8). For each block (block_y, // block_x), we use the pixel (16*block_x, 16*block_y) which // lands at xb=yb=0 → byte=0 within the block; // total addr = block_idx * 256. // // blockTable8[4][8] (PCSX2 master GSTables.cpp lines 53–59): // by=0: 0 1 4 5 16 17 20 21 // by=1: 2 3 6 7 18 19 22 23 // by=2: 8 9 12 13 24 25 28 29 // by=3: 10 11 14 15 26 27 30 31 // ----------------------------------------------------------- // by=0 check(9'd0, 6'd2, 12'(0*16), 12'(0*16), 32'(0*256), "src-lock-by0bx0"); check(9'd0, 6'd2, 12'(1*16), 12'(0*16), 32'(1*256), "src-lock-by0bx1"); check(9'd0, 6'd2, 12'(2*16), 12'(0*16), 32'(4*256), "src-lock-by0bx2"); check(9'd0, 6'd2, 12'(3*16), 12'(0*16), 32'(5*256), "src-lock-by0bx3"); check(9'd0, 6'd2, 12'(4*16), 12'(0*16), 32'(16*256), "src-lock-by0bx4"); check(9'd0, 6'd2, 12'(5*16), 12'(0*16), 32'(17*256), "src-lock-by0bx5"); check(9'd0, 6'd2, 12'(6*16), 12'(0*16), 32'(20*256), "src-lock-by0bx6"); check(9'd0, 6'd2, 12'(7*16), 12'(0*16), 32'(21*256), "src-lock-by0bx7"); // by=1 check(9'd0, 6'd2, 12'(0*16), 12'(1*16), 32'(2*256), "src-lock-by1bx0"); check(9'd0, 6'd2, 12'(1*16), 12'(1*16), 32'(3*256), "src-lock-by1bx1"); check(9'd0, 6'd2, 12'(2*16), 12'(1*16), 32'(6*256), "src-lock-by1bx2"); check(9'd0, 6'd2, 12'(3*16), 12'(1*16), 32'(7*256), "src-lock-by1bx3"); check(9'd0, 6'd2, 12'(4*16), 12'(1*16), 32'(18*256), "src-lock-by1bx4"); check(9'd0, 6'd2, 12'(5*16), 12'(1*16), 32'(19*256), "src-lock-by1bx5"); check(9'd0, 6'd2, 12'(6*16), 12'(1*16), 32'(22*256), "src-lock-by1bx6"); check(9'd0, 6'd2, 12'(7*16), 12'(1*16), 32'(23*256), "src-lock-by1bx7"); // by=2 check(9'd0, 6'd2, 12'(0*16), 12'(2*16), 32'(8*256), "src-lock-by2bx0"); check(9'd0, 6'd2, 12'(1*16), 12'(2*16), 32'(9*256), "src-lock-by2bx1"); check(9'd0, 6'd2, 12'(2*16), 12'(2*16), 32'(12*256), "src-lock-by2bx2"); check(9'd0, 6'd2, 12'(3*16), 12'(2*16), 32'(13*256), "src-lock-by2bx3"); check(9'd0, 6'd2, 12'(4*16), 12'(2*16), 32'(24*256), "src-lock-by2bx4"); check(9'd0, 6'd2, 12'(5*16), 12'(2*16), 32'(25*256), "src-lock-by2bx5"); check(9'd0, 6'd2, 12'(6*16), 12'(2*16), 32'(28*256), "src-lock-by2bx6"); check(9'd0, 6'd2, 12'(7*16), 12'(2*16), 32'(29*256), "src-lock-by2bx7"); // by=3 check(9'd0, 6'd2, 12'(0*16), 12'(3*16), 32'(10*256), "src-lock-by3bx0"); check(9'd0, 6'd2, 12'(1*16), 12'(3*16), 32'(11*256), "src-lock-by3bx1"); check(9'd0, 6'd2, 12'(2*16), 12'(3*16), 32'(14*256), "src-lock-by3bx2"); check(9'd0, 6'd2, 12'(3*16), 12'(3*16), 32'(15*256), "src-lock-by3bx3"); check(9'd0, 6'd2, 12'(4*16), 12'(3*16), 32'(26*256), "src-lock-by3bx4"); check(9'd0, 6'd2, 12'(5*16), 12'(3*16), 32'(27*256), "src-lock-by3bx5"); check(9'd0, 6'd2, 12'(6*16), 12'(3*16), 32'(30*256), "src-lock-by3bx6"); check(9'd0, 6'd2, 12'(7*16), 12'(3*16), 32'(31*256), "src-lock-by3bx7"); // ----------------------------------------------------------- // Phase 4 — block-swizzle walk. Cross-checks the in-TB // ref_block_idx8 against the DUT (the bijectivity sweep // below relies on ref_block_idx8 being correct). // ----------------------------------------------------------- for (int by_i = 0; by_i < 4; by_i++) begin for (int bx_i = 0; bx_i < 8; bx_i++) begin logic [31:0] expected; expected = 32'(ref_block_idx8(by_i, bx_i) * 256); check(9'd0, 6'd2, 12'(bx_i*16), 12'(by_i*16), expected, "block-swizzle-walk"); end end // ----------------------------------------------------------- // Phase 5 — bijectivity sweep over the 128×64 page (8192 // pixels = 8192 byte slots since PSMT8 is 1 byte/pixel). // Every pixel must hit a unique byte address in [0, 8192) // and agree with ref_addr8. Catches any swap in either table. // ----------------------------------------------------------- begin : sweep logic seen [0:8191]; for (int i = 0; i < 8192; i++) seen[i] = 1'b0; for (int yy = 0; yy < 64; yy++) begin for (int xx = 0; xx < 128; xx++) begin logic [31:0] got, ref_; int byte_slot; compute(9'd0, 6'd2, 12'(xx), 12'(yy), got); ref_ = ref_addr8(0, 2, xx, yy); if (got !== ref_) begin $error("sweep: (%0d,%0d) DUT=0x%08x ref=0x%08x", xx, yy, got, ref_); errors = errors + 1; end if (got >= 32'd8192) begin $error("sweep: (%0d,%0d) addr=0x%08x out of page bounds", xx, yy, got); errors = errors + 1; end byte_slot = got[12:0]; if (seen[byte_slot]) begin $error("sweep: (%0d,%0d) addr=0x%08x duplicate (slot=%0d)", xx, yy, got, byte_slot); errors = errors + 1; end seen[byte_slot] = 1'b1; end end for (int i = 0; i < 8192; i++) begin if (!seen[i]) begin $error("sweep: byte_slot %0d never reached", i); errors = errors + 1; end end end // ----------------------------------------------------------- // Multi-page sanity at FBW=4 (bw_pg=2): pixel (192, 16) → // page (1, 0) horizontally. // page_x = 192/128 = 1, page_y = 0, page_idx = 0*2+1 = 1, // page_base = 1 * 8192 = 8192. // bx = (192 % 128) / 16 = 64/16 = 4. // by = (16 % 64) / 16 = 16/16 = 1. // block (by=1, bx=4) → blockTable8[1][4] = 18 → // block_base = 8192 + 18*256 = 12800. // xb = 192%16 = 0, yb = 16%16 = 0 → byte = 0. // addr = 12800. // ----------------------------------------------------------- check(9'd0, 6'd4, 12'd192, 12'd16, 32'd12800, "fbw4-multi-page-x"); // FBW=4 + page-y crossing: (0, 64) → page (0, 1), // page_idx = 1*2 + 0 = 2, page_base = 16384. check(9'd0, 6'd4, 12'd0, 12'd64, 32'd16384, "fbw4-page-y-origin"); // ----------------------------------------------------------- // Non-page-aligned FBP coverage (real PS2 supports any // 2048-byte-aligned FBP). FBP=1 → base 2048; FBP=2 → 4096; // FBP=3 → 6144. (0,0) → addr = FBP*2048. // ----------------------------------------------------------- check(9'd1, 6'd2, 12'd0, 12'd0, 32'd2048, "fbp1-mid-page-origin"); check(9'd2, 6'd2, 12'd0, 12'd0, 32'd4096, "fbp2-mid-page-origin"); check(9'd3, 6'd2, 12'd0, 12'd0, 32'd6144, "fbp3-mid-page-origin"); // FBP=3 + FBW=4 + intra-block + page-(1,1) crossing: // (129, 65) → page (1, 1), page_idx = 1*2+1 = 3, // page_base = 6144 + 3*8192 = 30720. // bx = (129 % 128) / 16 = 1/16 = 0. // by = (65 % 64) / 16 = 1/16 = 0. // block (0,0) → swizzle 0 → block_base = 30720. // xb = 129%16 = 1, yb = 65%16 = 1. // byte = ref_col_idx8(1,1) = 12 → addr = 30732. check(9'd3, 6'd4, 12'd129, 12'd65, 32'd30732, "fbp3-fbw4-page1-1-intra"); $display("[tb_gs_swizzle_psmt8] errors=%0d", errors); if (errors == 0) $display("[tb_gs_swizzle_psmt8] PASS"); else $display("[tb_gs_swizzle_psmt8] FAIL"); $finish; end initial begin #500000; $error("[tb_gs_swizzle_psmt8] timeout"); $finish; end endmodule : tb_gs_swizzle_psmt8