Files
retroDE_ps2/sim/tb/gif_gs/tb_gs_swizzle_psmt4.sv
thejayman77 ec82764bef Initial commit: retroDE_ps2 — first-of-its-kind PS2 GS FPGA core (DE25-Nano / Agilex 5)
RTL (GS rasterizer, EE core stub, platform bridge, LPDDR4B path), sim regression
(272 TBs), docs, and tooling. Copyrighted PS2 content (BIOS, game code, GS dumps,
and all dump-derived textures/traces) is excluded via .gitignore and stays local.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 20:10:50 -04:00

1133 lines
73 KiB
Systemverilog
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// retroDE_ps2 — tb_gs_swizzle_psmt4 (Ch137)
//
// Source-locked focused contract for `gs_swizzle_psmt4_stub`.
// Mirrors the Ch125 PSMCT16 / Ch131 PSMT8 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×128 = 16384 nibble slots. Per Codex's Ch137 framing:
// PSMT4 is the fourth (and final) common GS PSM swizzle math
// primitive (after Ch119 PSMCT32 + Ch125 PSMCT16 + Ch131 PSMT8);
// most complex of the four because each PSMT4 pixel is a NIBBLE
// (half a byte), so the swizzle module must output both the byte
// address AND a `nibble_hi` selector. The block grid happens to
// be identical to PSMCT16's blockTable16 (4 cols × 8 rows of
// blocks), but the within-block layout is a 32×16 nibble
// permutation (vs CT16's 16×8 halfword permutation).
//
// SOURCE-TABLE PROVENANCE (per Codex's Ch125/Ch131/Ch137 guidance):
// - PCSX2 master HEAD commit
// 3000e113e2b3a76357c08dfa80d3c747f40e2706 (current at TB
// creation; same commit Ch131 pinned).
// - File pcsx2/GS/GSTables.cpp, blob SHA
// 3581209b8217378f473f9de22a9dbc8c45ca49b6 (same blob).
// - blockTable4 at lines 6169 (8 rows × 4 cols, indexed
// [block_y_in_page][block_x_in_page]).
// - columnTable4 at lines 147213 (16 rows × 32 cols, indexed
// [yb][xb], values are NIBBLE-within-block 0..511).
// - Cross-check: GSLocalMemory.h:558 BlockNumber4 +
// pxOffset template at GSTables.cpp:247258 (blockSize=512
// in nibble units, pageSize=16384 nibble units = 8192 bytes,
// pageWidth=128 px) + GSLocalMemory.h:560 asserts
// `(bw & 1) == 0` for PSMT4 (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: 512 hard-coded
// check() calls (one per (yb, xb) inside block (0,0))
// where the expected nibble index is taken VERBATIM from
// PCSX2 columnTable4. Catches a consistent miscopy of
// the column table.
// 2b — within-block 16×32 walk via the in-TB ref_col_idx4
// (self-check for the ref function).
// 3 — INDEPENDENT block-table source lock: 32 hard-coded
// check() calls (one per block in page 0) with expected
// block index taken VERBATIM from PCSX2 blockTable4.
// 4 — block-swizzle walk via the in-TB ref_block_idx4.
// 5 — bijectivity sweep over the 128×128 page: 16384 nibble
// slots, every pixel must hit a unique (byte_addr,
// nibble_hi) pair in `[0, 16384)` and agree with the
// in-TB reference.
// + multi-page sanity at FBW=4 (bw_pg=2) + non-page-aligned
// FBP coverage at FBP ∈ {1, 2, 3}.
//
// Standalone — no other modules in the dependency chain.
`timescale 1ns/1ps
module tb_gs_swizzle_psmt4;
// -----------------------------------------------------------
// DUT
// -----------------------------------------------------------
logic [8:0] fbp;
logic [5:0] fbw;
logic [11:0] x;
logic [11:0] y;
logic [31:0] addr;
logic nibble_hi;
gs_swizzle_psmt4_stub u_dut (
.fbp(fbp), .fbw(fbw), .x(x), .y(y),
.addr(addr), .nibble_hi(nibble_hi)
);
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,
output logic nib_o);
fbp = fbp_v; fbw = fbw_v; x = x_v; y = y_v;
#1;
addr_o = addr;
nib_o = nibble_hi;
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_addr,
input logic expected_nib,
input string tag);
logic [31:0] got_addr;
logic got_nib;
compute(fbp_v, fbw_v, x_v, y_v, got_addr, got_nib);
if (got_addr !== expected_addr) begin
$error("[%s] fbp=%0d fbw=%0d (x=%0d,y=%0d) addr got 0x%08x expected 0x%08x",
tag, fbp_v, fbw_v, x_v, y_v, got_addr, expected_addr);
errors = errors + 1;
end
if (got_nib !== expected_nib) begin
$error("[%s] fbp=%0d fbw=%0d (x=%0d,y=%0d) nibble_hi got %0b expected %0b",
tag, fbp_v, fbw_v, x_v, y_v, got_nib, expected_nib);
errors = errors + 1;
end
endtask
// Convenience: check by literal nibble index (the column-table
// value); we derive byte addr + nibble_hi internally. Used by
// Phase 2a so the call sites carry the verbatim PCSX2 value.
task automatic check_nibble(
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 int block_byte_base,
input int nibble_idx_v,
input string tag);
check(fbp_v, fbw_v, x_v, y_v,
32'(block_byte_base + (nibble_idx_v >> 1)),
1'(nibble_idx_v & 1),
tag);
endtask
// -----------------------------------------------------------
// Reference tables (verbatim from pcsx2/GS/GSTables.cpp).
// -----------------------------------------------------------
function automatic int ref_block_idx4(input int by, input int bx);
// _blockTable4[8][4]:
// by=0: { 0, 2, 8, 10 }
// by=1: { 1, 3, 9, 11 }
// by=2: { 4, 6, 12, 14 }
// by=3: { 5, 7, 13, 15 }
// by=4: { 16, 18, 24, 26 }
// by=5: { 17, 19, 25, 27 }
// by=6: { 20, 22, 28, 30 }
// by=7: { 21, 23, 29, 31 }
case ({by[2:0], bx[1:0]})
5'd0: return 0; 5'd1: return 2; 5'd2: return 8; 5'd3: return 10;
5'd4: return 1; 5'd5: return 3; 5'd6: return 9; 5'd7: return 11;
5'd8: return 4; 5'd9: return 6; 5'd10: return 12; 5'd11: return 14;
5'd12: return 5; 5'd13: return 7; 5'd14: return 13; 5'd15: return 15;
5'd16: return 16; 5'd17: return 18; 5'd18: return 24; 5'd19: return 26;
5'd20: return 17; 5'd21: return 19; 5'd22: return 25; 5'd23: return 27;
5'd24: return 20; 5'd25: return 22; 5'd26: return 28; 5'd27: return 30;
5'd28: return 21; 5'd29: return 23; 5'd30: return 29; default: return 31;
endcase
endfunction
function automatic int ref_col_idx4(input int yb, input int xb);
// 512-entry columnTable4 (PCSX2 master GSTables.cpp:147213).
// Mirrors gs_swizzle_psmt4_stub.col_idx_psmt4 — the
// bijectivity sweep below relies on this being correct;
// Phase 2a hard-codes the values independently.
case ({yb[3:0], xb[4:0]})
// yb=0
9'd0: return 0; 9'd1: return 8; 9'd2: return 32; 9'd3: return 40;
9'd4: return 64; 9'd5: return 72; 9'd6: return 96; 9'd7: return 104;
9'd8: return 2; 9'd9: return 10; 9'd10: return 34; 9'd11: return 42;
9'd12: return 66; 9'd13: return 74; 9'd14: return 98; 9'd15: return 106;
9'd16: return 4; 9'd17: return 12; 9'd18: return 36; 9'd19: return 44;
9'd20: return 68; 9'd21: return 76; 9'd22: return 100; 9'd23: return 108;
9'd24: return 6; 9'd25: return 14; 9'd26: return 38; 9'd27: return 46;
9'd28: return 70; 9'd29: return 78; 9'd30: return 102; 9'd31: return 110;
// yb=1
9'd32: return 16; 9'd33: return 24; 9'd34: return 48; 9'd35: return 56;
9'd36: return 80; 9'd37: return 88; 9'd38: return 112; 9'd39: return 120;
9'd40: return 18; 9'd41: return 26; 9'd42: return 50; 9'd43: return 58;
9'd44: return 82; 9'd45: return 90; 9'd46: return 114; 9'd47: return 122;
9'd48: return 20; 9'd49: return 28; 9'd50: return 52; 9'd51: return 60;
9'd52: return 84; 9'd53: return 92; 9'd54: return 116; 9'd55: return 124;
9'd56: return 22; 9'd57: return 30; 9'd58: return 54; 9'd59: return 62;
9'd60: return 86; 9'd61: return 94; 9'd62: return 118; 9'd63: return 126;
// yb=2
9'd64: return 65; 9'd65: return 73; 9'd66: return 97; 9'd67: return 105;
9'd68: return 1; 9'd69: return 9; 9'd70: return 33; 9'd71: return 41;
9'd72: return 67; 9'd73: return 75; 9'd74: return 99; 9'd75: return 107;
9'd76: return 3; 9'd77: return 11; 9'd78: return 35; 9'd79: return 43;
9'd80: return 69; 9'd81: return 77; 9'd82: return 101; 9'd83: return 109;
9'd84: return 5; 9'd85: return 13; 9'd86: return 37; 9'd87: return 45;
9'd88: return 71; 9'd89: return 79; 9'd90: return 103; 9'd91: return 111;
9'd92: return 7; 9'd93: return 15; 9'd94: return 39; 9'd95: return 47;
// yb=3
9'd96: return 81; 9'd97: return 89; 9'd98: return 113; 9'd99: return 121;
9'd100: return 17; 9'd101: return 25; 9'd102: return 49; 9'd103: return 57;
9'd104: return 83; 9'd105: return 91; 9'd106: return 115; 9'd107: return 123;
9'd108: return 19; 9'd109: return 27; 9'd110: return 51; 9'd111: return 59;
9'd112: return 85; 9'd113: return 93; 9'd114: return 117; 9'd115: return 125;
9'd116: return 21; 9'd117: return 29; 9'd118: return 53; 9'd119: return 61;
9'd120: return 87; 9'd121: return 95; 9'd122: return 119; 9'd123: return 127;
9'd124: return 23; 9'd125: return 31; 9'd126: return 55; 9'd127: return 63;
// yb=4
9'd128: return 192; 9'd129: return 200; 9'd130: return 224; 9'd131: return 232;
9'd132: return 128; 9'd133: return 136; 9'd134: return 160; 9'd135: return 168;
9'd136: return 194; 9'd137: return 202; 9'd138: return 226; 9'd139: return 234;
9'd140: return 130; 9'd141: return 138; 9'd142: return 162; 9'd143: return 170;
9'd144: return 196; 9'd145: return 204; 9'd146: return 228; 9'd147: return 236;
9'd148: return 132; 9'd149: return 140; 9'd150: return 164; 9'd151: return 172;
9'd152: return 198; 9'd153: return 206; 9'd154: return 230; 9'd155: return 238;
9'd156: return 134; 9'd157: return 142; 9'd158: return 166; 9'd159: return 174;
// yb=5
9'd160: return 208; 9'd161: return 216; 9'd162: return 240; 9'd163: return 248;
9'd164: return 144; 9'd165: return 152; 9'd166: return 176; 9'd167: return 184;
9'd168: return 210; 9'd169: return 218; 9'd170: return 242; 9'd171: return 250;
9'd172: return 146; 9'd173: return 154; 9'd174: return 178; 9'd175: return 186;
9'd176: return 212; 9'd177: return 220; 9'd178: return 244; 9'd179: return 252;
9'd180: return 148; 9'd181: return 156; 9'd182: return 180; 9'd183: return 188;
9'd184: return 214; 9'd185: return 222; 9'd186: return 246; 9'd187: return 254;
9'd188: return 150; 9'd189: return 158; 9'd190: return 182; 9'd191: return 190;
// yb=6
9'd192: return 129; 9'd193: return 137; 9'd194: return 161; 9'd195: return 169;
9'd196: return 193; 9'd197: return 201; 9'd198: return 225; 9'd199: return 233;
9'd200: return 131; 9'd201: return 139; 9'd202: return 163; 9'd203: return 171;
9'd204: return 195; 9'd205: return 203; 9'd206: return 227; 9'd207: return 235;
9'd208: return 133; 9'd209: return 141; 9'd210: return 165; 9'd211: return 173;
9'd212: return 197; 9'd213: return 205; 9'd214: return 229; 9'd215: return 237;
9'd216: return 135; 9'd217: return 143; 9'd218: return 167; 9'd219: return 175;
9'd220: return 199; 9'd221: return 207; 9'd222: return 231; 9'd223: return 239;
// yb=7
9'd224: return 145; 9'd225: return 153; 9'd226: return 177; 9'd227: return 185;
9'd228: return 209; 9'd229: return 217; 9'd230: return 241; 9'd231: return 249;
9'd232: return 147; 9'd233: return 155; 9'd234: return 179; 9'd235: return 187;
9'd236: return 211; 9'd237: return 219; 9'd238: return 243; 9'd239: return 251;
9'd240: return 149; 9'd241: return 157; 9'd242: return 181; 9'd243: return 189;
9'd244: return 213; 9'd245: return 221; 9'd246: return 245; 9'd247: return 253;
9'd248: return 151; 9'd249: return 159; 9'd250: return 183; 9'd251: return 191;
9'd252: return 215; 9'd253: return 223; 9'd254: return 247; 9'd255: return 255;
// yb=8
9'd256: return 256; 9'd257: return 264; 9'd258: return 288; 9'd259: return 296;
9'd260: return 320; 9'd261: return 328; 9'd262: return 352; 9'd263: return 360;
9'd264: return 258; 9'd265: return 266; 9'd266: return 290; 9'd267: return 298;
9'd268: return 322; 9'd269: return 330; 9'd270: return 354; 9'd271: return 362;
9'd272: return 260; 9'd273: return 268; 9'd274: return 292; 9'd275: return 300;
9'd276: return 324; 9'd277: return 332; 9'd278: return 356; 9'd279: return 364;
9'd280: return 262; 9'd281: return 270; 9'd282: return 294; 9'd283: return 302;
9'd284: return 326; 9'd285: return 334; 9'd286: return 358; 9'd287: return 366;
// yb=9
9'd288: return 272; 9'd289: return 280; 9'd290: return 304; 9'd291: return 312;
9'd292: return 336; 9'd293: return 344; 9'd294: return 368; 9'd295: return 376;
9'd296: return 274; 9'd297: return 282; 9'd298: return 306; 9'd299: return 314;
9'd300: return 338; 9'd301: return 346; 9'd302: return 370; 9'd303: return 378;
9'd304: return 276; 9'd305: return 284; 9'd306: return 308; 9'd307: return 316;
9'd308: return 340; 9'd309: return 348; 9'd310: return 372; 9'd311: return 380;
9'd312: return 278; 9'd313: return 286; 9'd314: return 310; 9'd315: return 318;
9'd316: return 342; 9'd317: return 350; 9'd318: return 374; 9'd319: return 382;
// yb=10
9'd320: return 321; 9'd321: return 329; 9'd322: return 353; 9'd323: return 361;
9'd324: return 257; 9'd325: return 265; 9'd326: return 289; 9'd327: return 297;
9'd328: return 323; 9'd329: return 331; 9'd330: return 355; 9'd331: return 363;
9'd332: return 259; 9'd333: return 267; 9'd334: return 291; 9'd335: return 299;
9'd336: return 325; 9'd337: return 333; 9'd338: return 357; 9'd339: return 365;
9'd340: return 261; 9'd341: return 269; 9'd342: return 293; 9'd343: return 301;
9'd344: return 327; 9'd345: return 335; 9'd346: return 359; 9'd347: return 367;
9'd348: return 263; 9'd349: return 271; 9'd350: return 295; 9'd351: return 303;
// yb=11
9'd352: return 337; 9'd353: return 345; 9'd354: return 369; 9'd355: return 377;
9'd356: return 273; 9'd357: return 281; 9'd358: return 305; 9'd359: return 313;
9'd360: return 339; 9'd361: return 347; 9'd362: return 371; 9'd363: return 379;
9'd364: return 275; 9'd365: return 283; 9'd366: return 307; 9'd367: return 315;
9'd368: return 341; 9'd369: return 349; 9'd370: return 373; 9'd371: return 381;
9'd372: return 277; 9'd373: return 285; 9'd374: return 309; 9'd375: return 317;
9'd376: return 343; 9'd377: return 351; 9'd378: return 375; 9'd379: return 383;
9'd380: return 279; 9'd381: return 287; 9'd382: return 311; 9'd383: return 319;
// yb=12
9'd384: return 448; 9'd385: return 456; 9'd386: return 480; 9'd387: return 488;
9'd388: return 384; 9'd389: return 392; 9'd390: return 416; 9'd391: return 424;
9'd392: return 450; 9'd393: return 458; 9'd394: return 482; 9'd395: return 490;
9'd396: return 386; 9'd397: return 394; 9'd398: return 418; 9'd399: return 426;
9'd400: return 452; 9'd401: return 460; 9'd402: return 484; 9'd403: return 492;
9'd404: return 388; 9'd405: return 396; 9'd406: return 420; 9'd407: return 428;
9'd408: return 454; 9'd409: return 462; 9'd410: return 486; 9'd411: return 494;
9'd412: return 390; 9'd413: return 398; 9'd414: return 422; 9'd415: return 430;
// yb=13
9'd416: return 464; 9'd417: return 472; 9'd418: return 496; 9'd419: return 504;
9'd420: return 400; 9'd421: return 408; 9'd422: return 432; 9'd423: return 440;
9'd424: return 466; 9'd425: return 474; 9'd426: return 498; 9'd427: return 506;
9'd428: return 402; 9'd429: return 410; 9'd430: return 434; 9'd431: return 442;
9'd432: return 468; 9'd433: return 476; 9'd434: return 500; 9'd435: return 508;
9'd436: return 404; 9'd437: return 412; 9'd438: return 436; 9'd439: return 444;
9'd440: return 470; 9'd441: return 478; 9'd442: return 502; 9'd443: return 510;
9'd444: return 406; 9'd445: return 414; 9'd446: return 438; 9'd447: return 446;
// yb=14
9'd448: return 385; 9'd449: return 393; 9'd450: return 417; 9'd451: return 425;
9'd452: return 449; 9'd453: return 457; 9'd454: return 481; 9'd455: return 489;
9'd456: return 387; 9'd457: return 395; 9'd458: return 419; 9'd459: return 427;
9'd460: return 451; 9'd461: return 459; 9'd462: return 483; 9'd463: return 491;
9'd464: return 389; 9'd465: return 397; 9'd466: return 421; 9'd467: return 429;
9'd468: return 453; 9'd469: return 461; 9'd470: return 485; 9'd471: return 493;
9'd472: return 391; 9'd473: return 399; 9'd474: return 423; 9'd475: return 431;
9'd476: return 455; 9'd477: return 463; 9'd478: return 487; 9'd479: return 495;
// yb=15
9'd480: return 401; 9'd481: return 409; 9'd482: return 433; 9'd483: return 441;
9'd484: return 465; 9'd485: return 473; 9'd486: return 497; 9'd487: return 505;
9'd488: return 403; 9'd489: return 411; 9'd490: return 435; 9'd491: return 443;
9'd492: return 467; 9'd493: return 475; 9'd494: return 499; 9'd495: return 507;
9'd496: return 405; 9'd497: return 413; 9'd498: return 437; 9'd499: return 445;
9'd500: return 469; 9'd501: return 477; 9'd502: return 501; 9'd503: return 509;
9'd504: return 407; 9'd505: return 415; 9'd506: return 439; 9'd507: return 447;
9'd508: return 471; 9'd509: return 479; 9'd510: return 503; default: return 511;
endcase
endfunction
function automatic logic [31:0] ref_addr_psmt4(
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, nibble_idx;
int addr_v;
page_x = x_v / 128;
page_y = y_v / 128;
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 % 128) / 16;
bx = (x_v % 128) / 32;
blk_idx = ref_block_idx4(by, bx);
xb = x_v % 32;
yb = y_v % 16;
nibble_idx = ref_col_idx4(yb, xb);
addr_v = page_base + blk_idx * 256 + (nibble_idx >> 1);
return addr_v[31:0];
endfunction
function automatic logic ref_nibble_hi(input int x_v, input int y_v);
int xb, yb, nibble_idx;
xb = x_v % 32;
yb = y_v % 16;
nibble_idx = ref_col_idx4(yb, xb);
return 1'(nibble_idx & 1);
endfunction
initial begin
fbp = 9'd0;
fbw = 6'd2; // PSMT4: FBW must be even
x = 12'd0;
y = 12'd0;
#1;
// -----------------------------------------------------------
// Phase 1 — spot-checks (hand-computed corners). FBW=2 →
// bw_pg=1.
//
// PSMT4 block = 32×16 px = 256 bytes = 512 nibbles.
// PSMT4 page = 128×128 px = 8192 bytes = 16384 nibbles.
// -----------------------------------------------------------
// (0, 0) → block (0,0)=0, nibble=0 → byte 0, hi=0.
check(9'd0, 6'd2, 12'd0, 12'd0, 32'd0, 1'b0, "origin");
// (1, 0) → block 0, xb=1 yb=0 → nibble=8 → byte 4, hi=0.
check(9'd0, 6'd2, 12'd1, 12'd0, 32'd4, 1'b0, "intra-block-x1");
// (8, 0) → block 0, xb=8 yb=0 → nibble=2 → byte 1, hi=0.
check(9'd0, 6'd2, 12'd8, 12'd0, 32'd1, 1'b0, "intra-block-x8");
// (16, 0) → block 0, xb=16 yb=0 → nibble=4 → byte 2, hi=0.
check(9'd0, 6'd2, 12'd16, 12'd0, 32'd2, 1'b0, "intra-block-x16");
// (0, 1) → block 0, xb=0 yb=1 → nibble=16 → byte 8, hi=0.
check(9'd0, 6'd2, 12'd0, 12'd1, 32'd8, 1'b0, "intra-block-y1");
// (0, 2) → block 0, xb=0 yb=2 → nibble=65 → byte 32, hi=1.
check(9'd0, 6'd2, 12'd0, 12'd2, 32'd32, 1'b1, "intra-block-y2-hi");
// (31, 15) → last px of block (0,0): xb=31 yb=15 → nibble=511.
// byte = 255, hi=1.
check(9'd0, 6'd2, 12'd31, 12'd15, 32'd255, 1'b1, "block-(0,0)-last");
// (32, 0) → block (0,1) (by=0, bx=1) → blockTable4[0][1]=2 →
// block_base=512. xb=0 yb=0 → nibble=0 → byte 0 → addr 512.
check(9'd0, 6'd2, 12'd32, 12'd0, 32'd512, 1'b0, "block-(0,1)-origin");
// (0, 16) → block (1,0) (by=1, bx=0) → blockTable4[1][0]=1 →
// block_base=256.
check(9'd0, 6'd2, 12'd0, 12'd16, 32'd256, 1'b0, "block-(1,0)-origin");
// (64, 0) → block (0,2) → blockTable4[0][2]=8 → block_base=2048.
check(9'd0, 6'd2, 12'd64, 12'd0, 32'd2048, 1'b0, "block-(0,2)-origin");
// (0, 32) → block (2,0) → blockTable4[2][0]=4 → block_base=1024.
check(9'd0, 6'd2, 12'd0, 12'd32, 32'd1024, 1'b0, "block-(2,0)-origin");
// (127, 127) → last pixel of last block of page 0:
// block (7,3) → blockTable4[7][3]=31 → block_base=7936.
// xb=31 yb=15 → nibble=511 → byte 255, hi=1 → addr 8191.
check(9'd0, 6'd2, 12'd127, 12'd127, 32'd8191, 1'b1, "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, 1'b0, "page1-x-origin");
// (0, 128) → start of page-row 1 (bw_pg=1) → page_idx=1,
// page_base=8192.
check(9'd0, 6'd2, 12'd0, 12'd128, 32'd8192, 1'b0, "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, 1'b0, "fbp4-origin");
// -----------------------------------------------------------
// Phase 2a — INDEPENDENT column-table source lock. 512 hard-
// coded checks (one per (yb, xb) inside block (0,0)) where
// the expected nibble index is taken VERBATIM from PCSX2
// columnTable4. Catches any case where DUT and ref_col_idx4
// happen to share the same miscopy.
// -----------------------------------------------------------
// yb=0
check_nibble(9'd0, 6'd2, 12'd0, 12'd0, 0, 0, "col-yb0-xb0");
check_nibble(9'd0, 6'd2, 12'd1, 12'd0, 0, 8, "col-yb0-xb1");
check_nibble(9'd0, 6'd2, 12'd2, 12'd0, 0, 32, "col-yb0-xb2");
check_nibble(9'd0, 6'd2, 12'd3, 12'd0, 0, 40, "col-yb0-xb3");
check_nibble(9'd0, 6'd2, 12'd4, 12'd0, 0, 64, "col-yb0-xb4");
check_nibble(9'd0, 6'd2, 12'd5, 12'd0, 0, 72, "col-yb0-xb5");
check_nibble(9'd0, 6'd2, 12'd6, 12'd0, 0, 96, "col-yb0-xb6");
check_nibble(9'd0, 6'd2, 12'd7, 12'd0, 0, 104, "col-yb0-xb7");
check_nibble(9'd0, 6'd2, 12'd8, 12'd0, 0, 2, "col-yb0-xb8");
check_nibble(9'd0, 6'd2, 12'd9, 12'd0, 0, 10, "col-yb0-xb9");
check_nibble(9'd0, 6'd2, 12'd10, 12'd0, 0, 34, "col-yb0-xb10");
check_nibble(9'd0, 6'd2, 12'd11, 12'd0, 0, 42, "col-yb0-xb11");
check_nibble(9'd0, 6'd2, 12'd12, 12'd0, 0, 66, "col-yb0-xb12");
check_nibble(9'd0, 6'd2, 12'd13, 12'd0, 0, 74, "col-yb0-xb13");
check_nibble(9'd0, 6'd2, 12'd14, 12'd0, 0, 98, "col-yb0-xb14");
check_nibble(9'd0, 6'd2, 12'd15, 12'd0, 0, 106, "col-yb0-xb15");
check_nibble(9'd0, 6'd2, 12'd16, 12'd0, 0, 4, "col-yb0-xb16");
check_nibble(9'd0, 6'd2, 12'd17, 12'd0, 0, 12, "col-yb0-xb17");
check_nibble(9'd0, 6'd2, 12'd18, 12'd0, 0, 36, "col-yb0-xb18");
check_nibble(9'd0, 6'd2, 12'd19, 12'd0, 0, 44, "col-yb0-xb19");
check_nibble(9'd0, 6'd2, 12'd20, 12'd0, 0, 68, "col-yb0-xb20");
check_nibble(9'd0, 6'd2, 12'd21, 12'd0, 0, 76, "col-yb0-xb21");
check_nibble(9'd0, 6'd2, 12'd22, 12'd0, 0, 100, "col-yb0-xb22");
check_nibble(9'd0, 6'd2, 12'd23, 12'd0, 0, 108, "col-yb0-xb23");
check_nibble(9'd0, 6'd2, 12'd24, 12'd0, 0, 6, "col-yb0-xb24");
check_nibble(9'd0, 6'd2, 12'd25, 12'd0, 0, 14, "col-yb0-xb25");
check_nibble(9'd0, 6'd2, 12'd26, 12'd0, 0, 38, "col-yb0-xb26");
check_nibble(9'd0, 6'd2, 12'd27, 12'd0, 0, 46, "col-yb0-xb27");
check_nibble(9'd0, 6'd2, 12'd28, 12'd0, 0, 70, "col-yb0-xb28");
check_nibble(9'd0, 6'd2, 12'd29, 12'd0, 0, 78, "col-yb0-xb29");
check_nibble(9'd0, 6'd2, 12'd30, 12'd0, 0, 102, "col-yb0-xb30");
check_nibble(9'd0, 6'd2, 12'd31, 12'd0, 0, 110, "col-yb0-xb31");
// Phase 2a continues — literal verbatim source-lock for
// yb=1..15 (480 more check_nibble() calls). Each row's
// 32 entries are taken VERBATIM from PCSX2
// pcsx2/GS/GSTables.cpp lines 153212 columnTable4. NOT
// derived from ref_col_idx4 — a wrong-but-permuted DUT
// table copied consistently into both DUT and TB ref
// would NOT survive these literal checks, even though it
// would pass a programmatic-against-ref walk + the
// bijectivity sweep. Mirrors Ch125/Ch131's full-literal
// source-lock pattern.
// yb=1: 16 24 48 56 80 88 112 120 18 26 50 58 82 90 114 122
// 20 28 52 60 84 92 116 124 22 30 54 62 86 94 118 126
check_nibble(9'd0, 6'd2, 12'd0, 12'd1, 0, 16, "col-yb1-xb0");
check_nibble(9'd0, 6'd2, 12'd1, 12'd1, 0, 24, "col-yb1-xb1");
check_nibble(9'd0, 6'd2, 12'd2, 12'd1, 0, 48, "col-yb1-xb2");
check_nibble(9'd0, 6'd2, 12'd3, 12'd1, 0, 56, "col-yb1-xb3");
check_nibble(9'd0, 6'd2, 12'd4, 12'd1, 0, 80, "col-yb1-xb4");
check_nibble(9'd0, 6'd2, 12'd5, 12'd1, 0, 88, "col-yb1-xb5");
check_nibble(9'd0, 6'd2, 12'd6, 12'd1, 0, 112, "col-yb1-xb6");
check_nibble(9'd0, 6'd2, 12'd7, 12'd1, 0, 120, "col-yb1-xb7");
check_nibble(9'd0, 6'd2, 12'd8, 12'd1, 0, 18, "col-yb1-xb8");
check_nibble(9'd0, 6'd2, 12'd9, 12'd1, 0, 26, "col-yb1-xb9");
check_nibble(9'd0, 6'd2, 12'd10, 12'd1, 0, 50, "col-yb1-xb10");
check_nibble(9'd0, 6'd2, 12'd11, 12'd1, 0, 58, "col-yb1-xb11");
check_nibble(9'd0, 6'd2, 12'd12, 12'd1, 0, 82, "col-yb1-xb12");
check_nibble(9'd0, 6'd2, 12'd13, 12'd1, 0, 90, "col-yb1-xb13");
check_nibble(9'd0, 6'd2, 12'd14, 12'd1, 0, 114, "col-yb1-xb14");
check_nibble(9'd0, 6'd2, 12'd15, 12'd1, 0, 122, "col-yb1-xb15");
check_nibble(9'd0, 6'd2, 12'd16, 12'd1, 0, 20, "col-yb1-xb16");
check_nibble(9'd0, 6'd2, 12'd17, 12'd1, 0, 28, "col-yb1-xb17");
check_nibble(9'd0, 6'd2, 12'd18, 12'd1, 0, 52, "col-yb1-xb18");
check_nibble(9'd0, 6'd2, 12'd19, 12'd1, 0, 60, "col-yb1-xb19");
check_nibble(9'd0, 6'd2, 12'd20, 12'd1, 0, 84, "col-yb1-xb20");
check_nibble(9'd0, 6'd2, 12'd21, 12'd1, 0, 92, "col-yb1-xb21");
check_nibble(9'd0, 6'd2, 12'd22, 12'd1, 0, 116, "col-yb1-xb22");
check_nibble(9'd0, 6'd2, 12'd23, 12'd1, 0, 124, "col-yb1-xb23");
check_nibble(9'd0, 6'd2, 12'd24, 12'd1, 0, 22, "col-yb1-xb24");
check_nibble(9'd0, 6'd2, 12'd25, 12'd1, 0, 30, "col-yb1-xb25");
check_nibble(9'd0, 6'd2, 12'd26, 12'd1, 0, 54, "col-yb1-xb26");
check_nibble(9'd0, 6'd2, 12'd27, 12'd1, 0, 62, "col-yb1-xb27");
check_nibble(9'd0, 6'd2, 12'd28, 12'd1, 0, 86, "col-yb1-xb28");
check_nibble(9'd0, 6'd2, 12'd29, 12'd1, 0, 94, "col-yb1-xb29");
check_nibble(9'd0, 6'd2, 12'd30, 12'd1, 0, 118, "col-yb1-xb30");
check_nibble(9'd0, 6'd2, 12'd31, 12'd1, 0, 126, "col-yb1-xb31");
// yb=2: 65 73 97 105 1 9 33 41 67 75 99 107 3 11 35 43
// 69 77 101 109 5 13 37 45 71 79 103 111 7 15 39 47
check_nibble(9'd0, 6'd2, 12'd0, 12'd2, 0, 65, "col-yb2-xb0");
check_nibble(9'd0, 6'd2, 12'd1, 12'd2, 0, 73, "col-yb2-xb1");
check_nibble(9'd0, 6'd2, 12'd2, 12'd2, 0, 97, "col-yb2-xb2");
check_nibble(9'd0, 6'd2, 12'd3, 12'd2, 0, 105, "col-yb2-xb3");
check_nibble(9'd0, 6'd2, 12'd4, 12'd2, 0, 1, "col-yb2-xb4");
check_nibble(9'd0, 6'd2, 12'd5, 12'd2, 0, 9, "col-yb2-xb5");
check_nibble(9'd0, 6'd2, 12'd6, 12'd2, 0, 33, "col-yb2-xb6");
check_nibble(9'd0, 6'd2, 12'd7, 12'd2, 0, 41, "col-yb2-xb7");
check_nibble(9'd0, 6'd2, 12'd8, 12'd2, 0, 67, "col-yb2-xb8");
check_nibble(9'd0, 6'd2, 12'd9, 12'd2, 0, 75, "col-yb2-xb9");
check_nibble(9'd0, 6'd2, 12'd10, 12'd2, 0, 99, "col-yb2-xb10");
check_nibble(9'd0, 6'd2, 12'd11, 12'd2, 0, 107, "col-yb2-xb11");
check_nibble(9'd0, 6'd2, 12'd12, 12'd2, 0, 3, "col-yb2-xb12");
check_nibble(9'd0, 6'd2, 12'd13, 12'd2, 0, 11, "col-yb2-xb13");
check_nibble(9'd0, 6'd2, 12'd14, 12'd2, 0, 35, "col-yb2-xb14");
check_nibble(9'd0, 6'd2, 12'd15, 12'd2, 0, 43, "col-yb2-xb15");
check_nibble(9'd0, 6'd2, 12'd16, 12'd2, 0, 69, "col-yb2-xb16");
check_nibble(9'd0, 6'd2, 12'd17, 12'd2, 0, 77, "col-yb2-xb17");
check_nibble(9'd0, 6'd2, 12'd18, 12'd2, 0, 101, "col-yb2-xb18");
check_nibble(9'd0, 6'd2, 12'd19, 12'd2, 0, 109, "col-yb2-xb19");
check_nibble(9'd0, 6'd2, 12'd20, 12'd2, 0, 5, "col-yb2-xb20");
check_nibble(9'd0, 6'd2, 12'd21, 12'd2, 0, 13, "col-yb2-xb21");
check_nibble(9'd0, 6'd2, 12'd22, 12'd2, 0, 37, "col-yb2-xb22");
check_nibble(9'd0, 6'd2, 12'd23, 12'd2, 0, 45, "col-yb2-xb23");
check_nibble(9'd0, 6'd2, 12'd24, 12'd2, 0, 71, "col-yb2-xb24");
check_nibble(9'd0, 6'd2, 12'd25, 12'd2, 0, 79, "col-yb2-xb25");
check_nibble(9'd0, 6'd2, 12'd26, 12'd2, 0, 103, "col-yb2-xb26");
check_nibble(9'd0, 6'd2, 12'd27, 12'd2, 0, 111, "col-yb2-xb27");
check_nibble(9'd0, 6'd2, 12'd28, 12'd2, 0, 7, "col-yb2-xb28");
check_nibble(9'd0, 6'd2, 12'd29, 12'd2, 0, 15, "col-yb2-xb29");
check_nibble(9'd0, 6'd2, 12'd30, 12'd2, 0, 39, "col-yb2-xb30");
check_nibble(9'd0, 6'd2, 12'd31, 12'd2, 0, 47, "col-yb2-xb31");
// yb=3: 81 89 113 121 17 25 49 57 83 91 115 123 19 27 51 59
// 85 93 117 125 21 29 53 61 87 95 119 127 23 31 55 63
check_nibble(9'd0, 6'd2, 12'd0, 12'd3, 0, 81, "col-yb3-xb0");
check_nibble(9'd0, 6'd2, 12'd1, 12'd3, 0, 89, "col-yb3-xb1");
check_nibble(9'd0, 6'd2, 12'd2, 12'd3, 0, 113, "col-yb3-xb2");
check_nibble(9'd0, 6'd2, 12'd3, 12'd3, 0, 121, "col-yb3-xb3");
check_nibble(9'd0, 6'd2, 12'd4, 12'd3, 0, 17, "col-yb3-xb4");
check_nibble(9'd0, 6'd2, 12'd5, 12'd3, 0, 25, "col-yb3-xb5");
check_nibble(9'd0, 6'd2, 12'd6, 12'd3, 0, 49, "col-yb3-xb6");
check_nibble(9'd0, 6'd2, 12'd7, 12'd3, 0, 57, "col-yb3-xb7");
check_nibble(9'd0, 6'd2, 12'd8, 12'd3, 0, 83, "col-yb3-xb8");
check_nibble(9'd0, 6'd2, 12'd9, 12'd3, 0, 91, "col-yb3-xb9");
check_nibble(9'd0, 6'd2, 12'd10, 12'd3, 0, 115, "col-yb3-xb10");
check_nibble(9'd0, 6'd2, 12'd11, 12'd3, 0, 123, "col-yb3-xb11");
check_nibble(9'd0, 6'd2, 12'd12, 12'd3, 0, 19, "col-yb3-xb12");
check_nibble(9'd0, 6'd2, 12'd13, 12'd3, 0, 27, "col-yb3-xb13");
check_nibble(9'd0, 6'd2, 12'd14, 12'd3, 0, 51, "col-yb3-xb14");
check_nibble(9'd0, 6'd2, 12'd15, 12'd3, 0, 59, "col-yb3-xb15");
check_nibble(9'd0, 6'd2, 12'd16, 12'd3, 0, 85, "col-yb3-xb16");
check_nibble(9'd0, 6'd2, 12'd17, 12'd3, 0, 93, "col-yb3-xb17");
check_nibble(9'd0, 6'd2, 12'd18, 12'd3, 0, 117, "col-yb3-xb18");
check_nibble(9'd0, 6'd2, 12'd19, 12'd3, 0, 125, "col-yb3-xb19");
check_nibble(9'd0, 6'd2, 12'd20, 12'd3, 0, 21, "col-yb3-xb20");
check_nibble(9'd0, 6'd2, 12'd21, 12'd3, 0, 29, "col-yb3-xb21");
check_nibble(9'd0, 6'd2, 12'd22, 12'd3, 0, 53, "col-yb3-xb22");
check_nibble(9'd0, 6'd2, 12'd23, 12'd3, 0, 61, "col-yb3-xb23");
check_nibble(9'd0, 6'd2, 12'd24, 12'd3, 0, 87, "col-yb3-xb24");
check_nibble(9'd0, 6'd2, 12'd25, 12'd3, 0, 95, "col-yb3-xb25");
check_nibble(9'd0, 6'd2, 12'd26, 12'd3, 0, 119, "col-yb3-xb26");
check_nibble(9'd0, 6'd2, 12'd27, 12'd3, 0, 127, "col-yb3-xb27");
check_nibble(9'd0, 6'd2, 12'd28, 12'd3, 0, 23, "col-yb3-xb28");
check_nibble(9'd0, 6'd2, 12'd29, 12'd3, 0, 31, "col-yb3-xb29");
check_nibble(9'd0, 6'd2, 12'd30, 12'd3, 0, 55, "col-yb3-xb30");
check_nibble(9'd0, 6'd2, 12'd31, 12'd3, 0, 63, "col-yb3-xb31");
// yb=4: 192 200 224 232 128 136 160 168 194 202 226 234 130 138 162 170
// 196 204 228 236 132 140 164 172 198 206 230 238 134 142 166 174
check_nibble(9'd0, 6'd2, 12'd0, 12'd4, 0, 192, "col-yb4-xb0");
check_nibble(9'd0, 6'd2, 12'd1, 12'd4, 0, 200, "col-yb4-xb1");
check_nibble(9'd0, 6'd2, 12'd2, 12'd4, 0, 224, "col-yb4-xb2");
check_nibble(9'd0, 6'd2, 12'd3, 12'd4, 0, 232, "col-yb4-xb3");
check_nibble(9'd0, 6'd2, 12'd4, 12'd4, 0, 128, "col-yb4-xb4");
check_nibble(9'd0, 6'd2, 12'd5, 12'd4, 0, 136, "col-yb4-xb5");
check_nibble(9'd0, 6'd2, 12'd6, 12'd4, 0, 160, "col-yb4-xb6");
check_nibble(9'd0, 6'd2, 12'd7, 12'd4, 0, 168, "col-yb4-xb7");
check_nibble(9'd0, 6'd2, 12'd8, 12'd4, 0, 194, "col-yb4-xb8");
check_nibble(9'd0, 6'd2, 12'd9, 12'd4, 0, 202, "col-yb4-xb9");
check_nibble(9'd0, 6'd2, 12'd10, 12'd4, 0, 226, "col-yb4-xb10");
check_nibble(9'd0, 6'd2, 12'd11, 12'd4, 0, 234, "col-yb4-xb11");
check_nibble(9'd0, 6'd2, 12'd12, 12'd4, 0, 130, "col-yb4-xb12");
check_nibble(9'd0, 6'd2, 12'd13, 12'd4, 0, 138, "col-yb4-xb13");
check_nibble(9'd0, 6'd2, 12'd14, 12'd4, 0, 162, "col-yb4-xb14");
check_nibble(9'd0, 6'd2, 12'd15, 12'd4, 0, 170, "col-yb4-xb15");
check_nibble(9'd0, 6'd2, 12'd16, 12'd4, 0, 196, "col-yb4-xb16");
check_nibble(9'd0, 6'd2, 12'd17, 12'd4, 0, 204, "col-yb4-xb17");
check_nibble(9'd0, 6'd2, 12'd18, 12'd4, 0, 228, "col-yb4-xb18");
check_nibble(9'd0, 6'd2, 12'd19, 12'd4, 0, 236, "col-yb4-xb19");
check_nibble(9'd0, 6'd2, 12'd20, 12'd4, 0, 132, "col-yb4-xb20");
check_nibble(9'd0, 6'd2, 12'd21, 12'd4, 0, 140, "col-yb4-xb21");
check_nibble(9'd0, 6'd2, 12'd22, 12'd4, 0, 164, "col-yb4-xb22");
check_nibble(9'd0, 6'd2, 12'd23, 12'd4, 0, 172, "col-yb4-xb23");
check_nibble(9'd0, 6'd2, 12'd24, 12'd4, 0, 198, "col-yb4-xb24");
check_nibble(9'd0, 6'd2, 12'd25, 12'd4, 0, 206, "col-yb4-xb25");
check_nibble(9'd0, 6'd2, 12'd26, 12'd4, 0, 230, "col-yb4-xb26");
check_nibble(9'd0, 6'd2, 12'd27, 12'd4, 0, 238, "col-yb4-xb27");
check_nibble(9'd0, 6'd2, 12'd28, 12'd4, 0, 134, "col-yb4-xb28");
check_nibble(9'd0, 6'd2, 12'd29, 12'd4, 0, 142, "col-yb4-xb29");
check_nibble(9'd0, 6'd2, 12'd30, 12'd4, 0, 166, "col-yb4-xb30");
check_nibble(9'd0, 6'd2, 12'd31, 12'd4, 0, 174, "col-yb4-xb31");
// yb=5: 208 216 240 248 144 152 176 184 210 218 242 250 146 154 178 186
// 212 220 244 252 148 156 180 188 214 222 246 254 150 158 182 190
check_nibble(9'd0, 6'd2, 12'd0, 12'd5, 0, 208, "col-yb5-xb0");
check_nibble(9'd0, 6'd2, 12'd1, 12'd5, 0, 216, "col-yb5-xb1");
check_nibble(9'd0, 6'd2, 12'd2, 12'd5, 0, 240, "col-yb5-xb2");
check_nibble(9'd0, 6'd2, 12'd3, 12'd5, 0, 248, "col-yb5-xb3");
check_nibble(9'd0, 6'd2, 12'd4, 12'd5, 0, 144, "col-yb5-xb4");
check_nibble(9'd0, 6'd2, 12'd5, 12'd5, 0, 152, "col-yb5-xb5");
check_nibble(9'd0, 6'd2, 12'd6, 12'd5, 0, 176, "col-yb5-xb6");
check_nibble(9'd0, 6'd2, 12'd7, 12'd5, 0, 184, "col-yb5-xb7");
check_nibble(9'd0, 6'd2, 12'd8, 12'd5, 0, 210, "col-yb5-xb8");
check_nibble(9'd0, 6'd2, 12'd9, 12'd5, 0, 218, "col-yb5-xb9");
check_nibble(9'd0, 6'd2, 12'd10, 12'd5, 0, 242, "col-yb5-xb10");
check_nibble(9'd0, 6'd2, 12'd11, 12'd5, 0, 250, "col-yb5-xb11");
check_nibble(9'd0, 6'd2, 12'd12, 12'd5, 0, 146, "col-yb5-xb12");
check_nibble(9'd0, 6'd2, 12'd13, 12'd5, 0, 154, "col-yb5-xb13");
check_nibble(9'd0, 6'd2, 12'd14, 12'd5, 0, 178, "col-yb5-xb14");
check_nibble(9'd0, 6'd2, 12'd15, 12'd5, 0, 186, "col-yb5-xb15");
check_nibble(9'd0, 6'd2, 12'd16, 12'd5, 0, 212, "col-yb5-xb16");
check_nibble(9'd0, 6'd2, 12'd17, 12'd5, 0, 220, "col-yb5-xb17");
check_nibble(9'd0, 6'd2, 12'd18, 12'd5, 0, 244, "col-yb5-xb18");
check_nibble(9'd0, 6'd2, 12'd19, 12'd5, 0, 252, "col-yb5-xb19");
check_nibble(9'd0, 6'd2, 12'd20, 12'd5, 0, 148, "col-yb5-xb20");
check_nibble(9'd0, 6'd2, 12'd21, 12'd5, 0, 156, "col-yb5-xb21");
check_nibble(9'd0, 6'd2, 12'd22, 12'd5, 0, 180, "col-yb5-xb22");
check_nibble(9'd0, 6'd2, 12'd23, 12'd5, 0, 188, "col-yb5-xb23");
check_nibble(9'd0, 6'd2, 12'd24, 12'd5, 0, 214, "col-yb5-xb24");
check_nibble(9'd0, 6'd2, 12'd25, 12'd5, 0, 222, "col-yb5-xb25");
check_nibble(9'd0, 6'd2, 12'd26, 12'd5, 0, 246, "col-yb5-xb26");
check_nibble(9'd0, 6'd2, 12'd27, 12'd5, 0, 254, "col-yb5-xb27");
check_nibble(9'd0, 6'd2, 12'd28, 12'd5, 0, 150, "col-yb5-xb28");
check_nibble(9'd0, 6'd2, 12'd29, 12'd5, 0, 158, "col-yb5-xb29");
check_nibble(9'd0, 6'd2, 12'd30, 12'd5, 0, 182, "col-yb5-xb30");
check_nibble(9'd0, 6'd2, 12'd31, 12'd5, 0, 190, "col-yb5-xb31");
// yb=6: 129 137 161 169 193 201 225 233 131 139 163 171 195 203 227 235
// 133 141 165 173 197 205 229 237 135 143 167 175 199 207 231 239
check_nibble(9'd0, 6'd2, 12'd0, 12'd6, 0, 129, "col-yb6-xb0");
check_nibble(9'd0, 6'd2, 12'd1, 12'd6, 0, 137, "col-yb6-xb1");
check_nibble(9'd0, 6'd2, 12'd2, 12'd6, 0, 161, "col-yb6-xb2");
check_nibble(9'd0, 6'd2, 12'd3, 12'd6, 0, 169, "col-yb6-xb3");
check_nibble(9'd0, 6'd2, 12'd4, 12'd6, 0, 193, "col-yb6-xb4");
check_nibble(9'd0, 6'd2, 12'd5, 12'd6, 0, 201, "col-yb6-xb5");
check_nibble(9'd0, 6'd2, 12'd6, 12'd6, 0, 225, "col-yb6-xb6");
check_nibble(9'd0, 6'd2, 12'd7, 12'd6, 0, 233, "col-yb6-xb7");
check_nibble(9'd0, 6'd2, 12'd8, 12'd6, 0, 131, "col-yb6-xb8");
check_nibble(9'd0, 6'd2, 12'd9, 12'd6, 0, 139, "col-yb6-xb9");
check_nibble(9'd0, 6'd2, 12'd10, 12'd6, 0, 163, "col-yb6-xb10");
check_nibble(9'd0, 6'd2, 12'd11, 12'd6, 0, 171, "col-yb6-xb11");
check_nibble(9'd0, 6'd2, 12'd12, 12'd6, 0, 195, "col-yb6-xb12");
check_nibble(9'd0, 6'd2, 12'd13, 12'd6, 0, 203, "col-yb6-xb13");
check_nibble(9'd0, 6'd2, 12'd14, 12'd6, 0, 227, "col-yb6-xb14");
check_nibble(9'd0, 6'd2, 12'd15, 12'd6, 0, 235, "col-yb6-xb15");
check_nibble(9'd0, 6'd2, 12'd16, 12'd6, 0, 133, "col-yb6-xb16");
check_nibble(9'd0, 6'd2, 12'd17, 12'd6, 0, 141, "col-yb6-xb17");
check_nibble(9'd0, 6'd2, 12'd18, 12'd6, 0, 165, "col-yb6-xb18");
check_nibble(9'd0, 6'd2, 12'd19, 12'd6, 0, 173, "col-yb6-xb19");
check_nibble(9'd0, 6'd2, 12'd20, 12'd6, 0, 197, "col-yb6-xb20");
check_nibble(9'd0, 6'd2, 12'd21, 12'd6, 0, 205, "col-yb6-xb21");
check_nibble(9'd0, 6'd2, 12'd22, 12'd6, 0, 229, "col-yb6-xb22");
check_nibble(9'd0, 6'd2, 12'd23, 12'd6, 0, 237, "col-yb6-xb23");
check_nibble(9'd0, 6'd2, 12'd24, 12'd6, 0, 135, "col-yb6-xb24");
check_nibble(9'd0, 6'd2, 12'd25, 12'd6, 0, 143, "col-yb6-xb25");
check_nibble(9'd0, 6'd2, 12'd26, 12'd6, 0, 167, "col-yb6-xb26");
check_nibble(9'd0, 6'd2, 12'd27, 12'd6, 0, 175, "col-yb6-xb27");
check_nibble(9'd0, 6'd2, 12'd28, 12'd6, 0, 199, "col-yb6-xb28");
check_nibble(9'd0, 6'd2, 12'd29, 12'd6, 0, 207, "col-yb6-xb29");
check_nibble(9'd0, 6'd2, 12'd30, 12'd6, 0, 231, "col-yb6-xb30");
check_nibble(9'd0, 6'd2, 12'd31, 12'd6, 0, 239, "col-yb6-xb31");
// yb=7: 145 153 177 185 209 217 241 249 147 155 179 187 211 219 243 251
// 149 157 181 189 213 221 245 253 151 159 183 191 215 223 247 255
check_nibble(9'd0, 6'd2, 12'd0, 12'd7, 0, 145, "col-yb7-xb0");
check_nibble(9'd0, 6'd2, 12'd1, 12'd7, 0, 153, "col-yb7-xb1");
check_nibble(9'd0, 6'd2, 12'd2, 12'd7, 0, 177, "col-yb7-xb2");
check_nibble(9'd0, 6'd2, 12'd3, 12'd7, 0, 185, "col-yb7-xb3");
check_nibble(9'd0, 6'd2, 12'd4, 12'd7, 0, 209, "col-yb7-xb4");
check_nibble(9'd0, 6'd2, 12'd5, 12'd7, 0, 217, "col-yb7-xb5");
check_nibble(9'd0, 6'd2, 12'd6, 12'd7, 0, 241, "col-yb7-xb6");
check_nibble(9'd0, 6'd2, 12'd7, 12'd7, 0, 249, "col-yb7-xb7");
check_nibble(9'd0, 6'd2, 12'd8, 12'd7, 0, 147, "col-yb7-xb8");
check_nibble(9'd0, 6'd2, 12'd9, 12'd7, 0, 155, "col-yb7-xb9");
check_nibble(9'd0, 6'd2, 12'd10, 12'd7, 0, 179, "col-yb7-xb10");
check_nibble(9'd0, 6'd2, 12'd11, 12'd7, 0, 187, "col-yb7-xb11");
check_nibble(9'd0, 6'd2, 12'd12, 12'd7, 0, 211, "col-yb7-xb12");
check_nibble(9'd0, 6'd2, 12'd13, 12'd7, 0, 219, "col-yb7-xb13");
check_nibble(9'd0, 6'd2, 12'd14, 12'd7, 0, 243, "col-yb7-xb14");
check_nibble(9'd0, 6'd2, 12'd15, 12'd7, 0, 251, "col-yb7-xb15");
check_nibble(9'd0, 6'd2, 12'd16, 12'd7, 0, 149, "col-yb7-xb16");
check_nibble(9'd0, 6'd2, 12'd17, 12'd7, 0, 157, "col-yb7-xb17");
check_nibble(9'd0, 6'd2, 12'd18, 12'd7, 0, 181, "col-yb7-xb18");
check_nibble(9'd0, 6'd2, 12'd19, 12'd7, 0, 189, "col-yb7-xb19");
check_nibble(9'd0, 6'd2, 12'd20, 12'd7, 0, 213, "col-yb7-xb20");
check_nibble(9'd0, 6'd2, 12'd21, 12'd7, 0, 221, "col-yb7-xb21");
check_nibble(9'd0, 6'd2, 12'd22, 12'd7, 0, 245, "col-yb7-xb22");
check_nibble(9'd0, 6'd2, 12'd23, 12'd7, 0, 253, "col-yb7-xb23");
check_nibble(9'd0, 6'd2, 12'd24, 12'd7, 0, 151, "col-yb7-xb24");
check_nibble(9'd0, 6'd2, 12'd25, 12'd7, 0, 159, "col-yb7-xb25");
check_nibble(9'd0, 6'd2, 12'd26, 12'd7, 0, 183, "col-yb7-xb26");
check_nibble(9'd0, 6'd2, 12'd27, 12'd7, 0, 191, "col-yb7-xb27");
check_nibble(9'd0, 6'd2, 12'd28, 12'd7, 0, 215, "col-yb7-xb28");
check_nibble(9'd0, 6'd2, 12'd29, 12'd7, 0, 223, "col-yb7-xb29");
check_nibble(9'd0, 6'd2, 12'd30, 12'd7, 0, 247, "col-yb7-xb30");
check_nibble(9'd0, 6'd2, 12'd31, 12'd7, 0, 255, "col-yb7-xb31");
// yb=8: 256 264 288 296 320 328 352 360 258 266 290 298 322 330 354 362
// 260 268 292 300 324 332 356 364 262 270 294 302 326 334 358 366
check_nibble(9'd0, 6'd2, 12'd0, 12'd8, 0, 256, "col-yb8-xb0");
check_nibble(9'd0, 6'd2, 12'd1, 12'd8, 0, 264, "col-yb8-xb1");
check_nibble(9'd0, 6'd2, 12'd2, 12'd8, 0, 288, "col-yb8-xb2");
check_nibble(9'd0, 6'd2, 12'd3, 12'd8, 0, 296, "col-yb8-xb3");
check_nibble(9'd0, 6'd2, 12'd4, 12'd8, 0, 320, "col-yb8-xb4");
check_nibble(9'd0, 6'd2, 12'd5, 12'd8, 0, 328, "col-yb8-xb5");
check_nibble(9'd0, 6'd2, 12'd6, 12'd8, 0, 352, "col-yb8-xb6");
check_nibble(9'd0, 6'd2, 12'd7, 12'd8, 0, 360, "col-yb8-xb7");
check_nibble(9'd0, 6'd2, 12'd8, 12'd8, 0, 258, "col-yb8-xb8");
check_nibble(9'd0, 6'd2, 12'd9, 12'd8, 0, 266, "col-yb8-xb9");
check_nibble(9'd0, 6'd2, 12'd10, 12'd8, 0, 290, "col-yb8-xb10");
check_nibble(9'd0, 6'd2, 12'd11, 12'd8, 0, 298, "col-yb8-xb11");
check_nibble(9'd0, 6'd2, 12'd12, 12'd8, 0, 322, "col-yb8-xb12");
check_nibble(9'd0, 6'd2, 12'd13, 12'd8, 0, 330, "col-yb8-xb13");
check_nibble(9'd0, 6'd2, 12'd14, 12'd8, 0, 354, "col-yb8-xb14");
check_nibble(9'd0, 6'd2, 12'd15, 12'd8, 0, 362, "col-yb8-xb15");
check_nibble(9'd0, 6'd2, 12'd16, 12'd8, 0, 260, "col-yb8-xb16");
check_nibble(9'd0, 6'd2, 12'd17, 12'd8, 0, 268, "col-yb8-xb17");
check_nibble(9'd0, 6'd2, 12'd18, 12'd8, 0, 292, "col-yb8-xb18");
check_nibble(9'd0, 6'd2, 12'd19, 12'd8, 0, 300, "col-yb8-xb19");
check_nibble(9'd0, 6'd2, 12'd20, 12'd8, 0, 324, "col-yb8-xb20");
check_nibble(9'd0, 6'd2, 12'd21, 12'd8, 0, 332, "col-yb8-xb21");
check_nibble(9'd0, 6'd2, 12'd22, 12'd8, 0, 356, "col-yb8-xb22");
check_nibble(9'd0, 6'd2, 12'd23, 12'd8, 0, 364, "col-yb8-xb23");
check_nibble(9'd0, 6'd2, 12'd24, 12'd8, 0, 262, "col-yb8-xb24");
check_nibble(9'd0, 6'd2, 12'd25, 12'd8, 0, 270, "col-yb8-xb25");
check_nibble(9'd0, 6'd2, 12'd26, 12'd8, 0, 294, "col-yb8-xb26");
check_nibble(9'd0, 6'd2, 12'd27, 12'd8, 0, 302, "col-yb8-xb27");
check_nibble(9'd0, 6'd2, 12'd28, 12'd8, 0, 326, "col-yb8-xb28");
check_nibble(9'd0, 6'd2, 12'd29, 12'd8, 0, 334, "col-yb8-xb29");
check_nibble(9'd0, 6'd2, 12'd30, 12'd8, 0, 358, "col-yb8-xb30");
check_nibble(9'd0, 6'd2, 12'd31, 12'd8, 0, 366, "col-yb8-xb31");
// yb=9: 272 280 304 312 336 344 368 376 274 282 306 314 338 346 370 378
// 276 284 308 316 340 348 372 380 278 286 310 318 342 350 374 382
check_nibble(9'd0, 6'd2, 12'd0, 12'd9, 0, 272, "col-yb9-xb0");
check_nibble(9'd0, 6'd2, 12'd1, 12'd9, 0, 280, "col-yb9-xb1");
check_nibble(9'd0, 6'd2, 12'd2, 12'd9, 0, 304, "col-yb9-xb2");
check_nibble(9'd0, 6'd2, 12'd3, 12'd9, 0, 312, "col-yb9-xb3");
check_nibble(9'd0, 6'd2, 12'd4, 12'd9, 0, 336, "col-yb9-xb4");
check_nibble(9'd0, 6'd2, 12'd5, 12'd9, 0, 344, "col-yb9-xb5");
check_nibble(9'd0, 6'd2, 12'd6, 12'd9, 0, 368, "col-yb9-xb6");
check_nibble(9'd0, 6'd2, 12'd7, 12'd9, 0, 376, "col-yb9-xb7");
check_nibble(9'd0, 6'd2, 12'd8, 12'd9, 0, 274, "col-yb9-xb8");
check_nibble(9'd0, 6'd2, 12'd9, 12'd9, 0, 282, "col-yb9-xb9");
check_nibble(9'd0, 6'd2, 12'd10, 12'd9, 0, 306, "col-yb9-xb10");
check_nibble(9'd0, 6'd2, 12'd11, 12'd9, 0, 314, "col-yb9-xb11");
check_nibble(9'd0, 6'd2, 12'd12, 12'd9, 0, 338, "col-yb9-xb12");
check_nibble(9'd0, 6'd2, 12'd13, 12'd9, 0, 346, "col-yb9-xb13");
check_nibble(9'd0, 6'd2, 12'd14, 12'd9, 0, 370, "col-yb9-xb14");
check_nibble(9'd0, 6'd2, 12'd15, 12'd9, 0, 378, "col-yb9-xb15");
check_nibble(9'd0, 6'd2, 12'd16, 12'd9, 0, 276, "col-yb9-xb16");
check_nibble(9'd0, 6'd2, 12'd17, 12'd9, 0, 284, "col-yb9-xb17");
check_nibble(9'd0, 6'd2, 12'd18, 12'd9, 0, 308, "col-yb9-xb18");
check_nibble(9'd0, 6'd2, 12'd19, 12'd9, 0, 316, "col-yb9-xb19");
check_nibble(9'd0, 6'd2, 12'd20, 12'd9, 0, 340, "col-yb9-xb20");
check_nibble(9'd0, 6'd2, 12'd21, 12'd9, 0, 348, "col-yb9-xb21");
check_nibble(9'd0, 6'd2, 12'd22, 12'd9, 0, 372, "col-yb9-xb22");
check_nibble(9'd0, 6'd2, 12'd23, 12'd9, 0, 380, "col-yb9-xb23");
check_nibble(9'd0, 6'd2, 12'd24, 12'd9, 0, 278, "col-yb9-xb24");
check_nibble(9'd0, 6'd2, 12'd25, 12'd9, 0, 286, "col-yb9-xb25");
check_nibble(9'd0, 6'd2, 12'd26, 12'd9, 0, 310, "col-yb9-xb26");
check_nibble(9'd0, 6'd2, 12'd27, 12'd9, 0, 318, "col-yb9-xb27");
check_nibble(9'd0, 6'd2, 12'd28, 12'd9, 0, 342, "col-yb9-xb28");
check_nibble(9'd0, 6'd2, 12'd29, 12'd9, 0, 350, "col-yb9-xb29");
check_nibble(9'd0, 6'd2, 12'd30, 12'd9, 0, 374, "col-yb9-xb30");
check_nibble(9'd0, 6'd2, 12'd31, 12'd9, 0, 382, "col-yb9-xb31");
// yb=10: 321 329 353 361 257 265 289 297 323 331 355 363 259 267 291 299
// 325 333 357 365 261 269 293 301 327 335 359 367 263 271 295 303
check_nibble(9'd0, 6'd2, 12'd0, 12'd10, 0, 321, "col-yb10-xb0");
check_nibble(9'd0, 6'd2, 12'd1, 12'd10, 0, 329, "col-yb10-xb1");
check_nibble(9'd0, 6'd2, 12'd2, 12'd10, 0, 353, "col-yb10-xb2");
check_nibble(9'd0, 6'd2, 12'd3, 12'd10, 0, 361, "col-yb10-xb3");
check_nibble(9'd0, 6'd2, 12'd4, 12'd10, 0, 257, "col-yb10-xb4");
check_nibble(9'd0, 6'd2, 12'd5, 12'd10, 0, 265, "col-yb10-xb5");
check_nibble(9'd0, 6'd2, 12'd6, 12'd10, 0, 289, "col-yb10-xb6");
check_nibble(9'd0, 6'd2, 12'd7, 12'd10, 0, 297, "col-yb10-xb7");
check_nibble(9'd0, 6'd2, 12'd8, 12'd10, 0, 323, "col-yb10-xb8");
check_nibble(9'd0, 6'd2, 12'd9, 12'd10, 0, 331, "col-yb10-xb9");
check_nibble(9'd0, 6'd2, 12'd10, 12'd10, 0, 355, "col-yb10-xb10");
check_nibble(9'd0, 6'd2, 12'd11, 12'd10, 0, 363, "col-yb10-xb11");
check_nibble(9'd0, 6'd2, 12'd12, 12'd10, 0, 259, "col-yb10-xb12");
check_nibble(9'd0, 6'd2, 12'd13, 12'd10, 0, 267, "col-yb10-xb13");
check_nibble(9'd0, 6'd2, 12'd14, 12'd10, 0, 291, "col-yb10-xb14");
check_nibble(9'd0, 6'd2, 12'd15, 12'd10, 0, 299, "col-yb10-xb15");
check_nibble(9'd0, 6'd2, 12'd16, 12'd10, 0, 325, "col-yb10-xb16");
check_nibble(9'd0, 6'd2, 12'd17, 12'd10, 0, 333, "col-yb10-xb17");
check_nibble(9'd0, 6'd2, 12'd18, 12'd10, 0, 357, "col-yb10-xb18");
check_nibble(9'd0, 6'd2, 12'd19, 12'd10, 0, 365, "col-yb10-xb19");
check_nibble(9'd0, 6'd2, 12'd20, 12'd10, 0, 261, "col-yb10-xb20");
check_nibble(9'd0, 6'd2, 12'd21, 12'd10, 0, 269, "col-yb10-xb21");
check_nibble(9'd0, 6'd2, 12'd22, 12'd10, 0, 293, "col-yb10-xb22");
check_nibble(9'd0, 6'd2, 12'd23, 12'd10, 0, 301, "col-yb10-xb23");
check_nibble(9'd0, 6'd2, 12'd24, 12'd10, 0, 327, "col-yb10-xb24");
check_nibble(9'd0, 6'd2, 12'd25, 12'd10, 0, 335, "col-yb10-xb25");
check_nibble(9'd0, 6'd2, 12'd26, 12'd10, 0, 359, "col-yb10-xb26");
check_nibble(9'd0, 6'd2, 12'd27, 12'd10, 0, 367, "col-yb10-xb27");
check_nibble(9'd0, 6'd2, 12'd28, 12'd10, 0, 263, "col-yb10-xb28");
check_nibble(9'd0, 6'd2, 12'd29, 12'd10, 0, 271, "col-yb10-xb29");
check_nibble(9'd0, 6'd2, 12'd30, 12'd10, 0, 295, "col-yb10-xb30");
check_nibble(9'd0, 6'd2, 12'd31, 12'd10, 0, 303, "col-yb10-xb31");
// yb=11: 337 345 369 377 273 281 305 313 339 347 371 379 275 283 307 315
// 341 349 373 381 277 285 309 317 343 351 375 383 279 287 311 319
check_nibble(9'd0, 6'd2, 12'd0, 12'd11, 0, 337, "col-yb11-xb0");
check_nibble(9'd0, 6'd2, 12'd1, 12'd11, 0, 345, "col-yb11-xb1");
check_nibble(9'd0, 6'd2, 12'd2, 12'd11, 0, 369, "col-yb11-xb2");
check_nibble(9'd0, 6'd2, 12'd3, 12'd11, 0, 377, "col-yb11-xb3");
check_nibble(9'd0, 6'd2, 12'd4, 12'd11, 0, 273, "col-yb11-xb4");
check_nibble(9'd0, 6'd2, 12'd5, 12'd11, 0, 281, "col-yb11-xb5");
check_nibble(9'd0, 6'd2, 12'd6, 12'd11, 0, 305, "col-yb11-xb6");
check_nibble(9'd0, 6'd2, 12'd7, 12'd11, 0, 313, "col-yb11-xb7");
check_nibble(9'd0, 6'd2, 12'd8, 12'd11, 0, 339, "col-yb11-xb8");
check_nibble(9'd0, 6'd2, 12'd9, 12'd11, 0, 347, "col-yb11-xb9");
check_nibble(9'd0, 6'd2, 12'd10, 12'd11, 0, 371, "col-yb11-xb10");
check_nibble(9'd0, 6'd2, 12'd11, 12'd11, 0, 379, "col-yb11-xb11");
check_nibble(9'd0, 6'd2, 12'd12, 12'd11, 0, 275, "col-yb11-xb12");
check_nibble(9'd0, 6'd2, 12'd13, 12'd11, 0, 283, "col-yb11-xb13");
check_nibble(9'd0, 6'd2, 12'd14, 12'd11, 0, 307, "col-yb11-xb14");
check_nibble(9'd0, 6'd2, 12'd15, 12'd11, 0, 315, "col-yb11-xb15");
check_nibble(9'd0, 6'd2, 12'd16, 12'd11, 0, 341, "col-yb11-xb16");
check_nibble(9'd0, 6'd2, 12'd17, 12'd11, 0, 349, "col-yb11-xb17");
check_nibble(9'd0, 6'd2, 12'd18, 12'd11, 0, 373, "col-yb11-xb18");
check_nibble(9'd0, 6'd2, 12'd19, 12'd11, 0, 381, "col-yb11-xb19");
check_nibble(9'd0, 6'd2, 12'd20, 12'd11, 0, 277, "col-yb11-xb20");
check_nibble(9'd0, 6'd2, 12'd21, 12'd11, 0, 285, "col-yb11-xb21");
check_nibble(9'd0, 6'd2, 12'd22, 12'd11, 0, 309, "col-yb11-xb22");
check_nibble(9'd0, 6'd2, 12'd23, 12'd11, 0, 317, "col-yb11-xb23");
check_nibble(9'd0, 6'd2, 12'd24, 12'd11, 0, 343, "col-yb11-xb24");
check_nibble(9'd0, 6'd2, 12'd25, 12'd11, 0, 351, "col-yb11-xb25");
check_nibble(9'd0, 6'd2, 12'd26, 12'd11, 0, 375, "col-yb11-xb26");
check_nibble(9'd0, 6'd2, 12'd27, 12'd11, 0, 383, "col-yb11-xb27");
check_nibble(9'd0, 6'd2, 12'd28, 12'd11, 0, 279, "col-yb11-xb28");
check_nibble(9'd0, 6'd2, 12'd29, 12'd11, 0, 287, "col-yb11-xb29");
check_nibble(9'd0, 6'd2, 12'd30, 12'd11, 0, 311, "col-yb11-xb30");
check_nibble(9'd0, 6'd2, 12'd31, 12'd11, 0, 319, "col-yb11-xb31");
// yb=12: 448 456 480 488 384 392 416 424 450 458 482 490 386 394 418 426
// 452 460 484 492 388 396 420 428 454 462 486 494 390 398 422 430
check_nibble(9'd0, 6'd2, 12'd0, 12'd12, 0, 448, "col-yb12-xb0");
check_nibble(9'd0, 6'd2, 12'd1, 12'd12, 0, 456, "col-yb12-xb1");
check_nibble(9'd0, 6'd2, 12'd2, 12'd12, 0, 480, "col-yb12-xb2");
check_nibble(9'd0, 6'd2, 12'd3, 12'd12, 0, 488, "col-yb12-xb3");
check_nibble(9'd0, 6'd2, 12'd4, 12'd12, 0, 384, "col-yb12-xb4");
check_nibble(9'd0, 6'd2, 12'd5, 12'd12, 0, 392, "col-yb12-xb5");
check_nibble(9'd0, 6'd2, 12'd6, 12'd12, 0, 416, "col-yb12-xb6");
check_nibble(9'd0, 6'd2, 12'd7, 12'd12, 0, 424, "col-yb12-xb7");
check_nibble(9'd0, 6'd2, 12'd8, 12'd12, 0, 450, "col-yb12-xb8");
check_nibble(9'd0, 6'd2, 12'd9, 12'd12, 0, 458, "col-yb12-xb9");
check_nibble(9'd0, 6'd2, 12'd10, 12'd12, 0, 482, "col-yb12-xb10");
check_nibble(9'd0, 6'd2, 12'd11, 12'd12, 0, 490, "col-yb12-xb11");
check_nibble(9'd0, 6'd2, 12'd12, 12'd12, 0, 386, "col-yb12-xb12");
check_nibble(9'd0, 6'd2, 12'd13, 12'd12, 0, 394, "col-yb12-xb13");
check_nibble(9'd0, 6'd2, 12'd14, 12'd12, 0, 418, "col-yb12-xb14");
check_nibble(9'd0, 6'd2, 12'd15, 12'd12, 0, 426, "col-yb12-xb15");
check_nibble(9'd0, 6'd2, 12'd16, 12'd12, 0, 452, "col-yb12-xb16");
check_nibble(9'd0, 6'd2, 12'd17, 12'd12, 0, 460, "col-yb12-xb17");
check_nibble(9'd0, 6'd2, 12'd18, 12'd12, 0, 484, "col-yb12-xb18");
check_nibble(9'd0, 6'd2, 12'd19, 12'd12, 0, 492, "col-yb12-xb19");
check_nibble(9'd0, 6'd2, 12'd20, 12'd12, 0, 388, "col-yb12-xb20");
check_nibble(9'd0, 6'd2, 12'd21, 12'd12, 0, 396, "col-yb12-xb21");
check_nibble(9'd0, 6'd2, 12'd22, 12'd12, 0, 420, "col-yb12-xb22");
check_nibble(9'd0, 6'd2, 12'd23, 12'd12, 0, 428, "col-yb12-xb23");
check_nibble(9'd0, 6'd2, 12'd24, 12'd12, 0, 454, "col-yb12-xb24");
check_nibble(9'd0, 6'd2, 12'd25, 12'd12, 0, 462, "col-yb12-xb25");
check_nibble(9'd0, 6'd2, 12'd26, 12'd12, 0, 486, "col-yb12-xb26");
check_nibble(9'd0, 6'd2, 12'd27, 12'd12, 0, 494, "col-yb12-xb27");
check_nibble(9'd0, 6'd2, 12'd28, 12'd12, 0, 390, "col-yb12-xb28");
check_nibble(9'd0, 6'd2, 12'd29, 12'd12, 0, 398, "col-yb12-xb29");
check_nibble(9'd0, 6'd2, 12'd30, 12'd12, 0, 422, "col-yb12-xb30");
check_nibble(9'd0, 6'd2, 12'd31, 12'd12, 0, 430, "col-yb12-xb31");
// yb=13: 464 472 496 504 400 408 432 440 466 474 498 506 402 410 434 442
// 468 476 500 508 404 412 436 444 470 478 502 510 406 414 438 446
check_nibble(9'd0, 6'd2, 12'd0, 12'd13, 0, 464, "col-yb13-xb0");
check_nibble(9'd0, 6'd2, 12'd1, 12'd13, 0, 472, "col-yb13-xb1");
check_nibble(9'd0, 6'd2, 12'd2, 12'd13, 0, 496, "col-yb13-xb2");
check_nibble(9'd0, 6'd2, 12'd3, 12'd13, 0, 504, "col-yb13-xb3");
check_nibble(9'd0, 6'd2, 12'd4, 12'd13, 0, 400, "col-yb13-xb4");
check_nibble(9'd0, 6'd2, 12'd5, 12'd13, 0, 408, "col-yb13-xb5");
check_nibble(9'd0, 6'd2, 12'd6, 12'd13, 0, 432, "col-yb13-xb6");
check_nibble(9'd0, 6'd2, 12'd7, 12'd13, 0, 440, "col-yb13-xb7");
check_nibble(9'd0, 6'd2, 12'd8, 12'd13, 0, 466, "col-yb13-xb8");
check_nibble(9'd0, 6'd2, 12'd9, 12'd13, 0, 474, "col-yb13-xb9");
check_nibble(9'd0, 6'd2, 12'd10, 12'd13, 0, 498, "col-yb13-xb10");
check_nibble(9'd0, 6'd2, 12'd11, 12'd13, 0, 506, "col-yb13-xb11");
check_nibble(9'd0, 6'd2, 12'd12, 12'd13, 0, 402, "col-yb13-xb12");
check_nibble(9'd0, 6'd2, 12'd13, 12'd13, 0, 410, "col-yb13-xb13");
check_nibble(9'd0, 6'd2, 12'd14, 12'd13, 0, 434, "col-yb13-xb14");
check_nibble(9'd0, 6'd2, 12'd15, 12'd13, 0, 442, "col-yb13-xb15");
check_nibble(9'd0, 6'd2, 12'd16, 12'd13, 0, 468, "col-yb13-xb16");
check_nibble(9'd0, 6'd2, 12'd17, 12'd13, 0, 476, "col-yb13-xb17");
check_nibble(9'd0, 6'd2, 12'd18, 12'd13, 0, 500, "col-yb13-xb18");
check_nibble(9'd0, 6'd2, 12'd19, 12'd13, 0, 508, "col-yb13-xb19");
check_nibble(9'd0, 6'd2, 12'd20, 12'd13, 0, 404, "col-yb13-xb20");
check_nibble(9'd0, 6'd2, 12'd21, 12'd13, 0, 412, "col-yb13-xb21");
check_nibble(9'd0, 6'd2, 12'd22, 12'd13, 0, 436, "col-yb13-xb22");
check_nibble(9'd0, 6'd2, 12'd23, 12'd13, 0, 444, "col-yb13-xb23");
check_nibble(9'd0, 6'd2, 12'd24, 12'd13, 0, 470, "col-yb13-xb24");
check_nibble(9'd0, 6'd2, 12'd25, 12'd13, 0, 478, "col-yb13-xb25");
check_nibble(9'd0, 6'd2, 12'd26, 12'd13, 0, 502, "col-yb13-xb26");
check_nibble(9'd0, 6'd2, 12'd27, 12'd13, 0, 510, "col-yb13-xb27");
check_nibble(9'd0, 6'd2, 12'd28, 12'd13, 0, 406, "col-yb13-xb28");
check_nibble(9'd0, 6'd2, 12'd29, 12'd13, 0, 414, "col-yb13-xb29");
check_nibble(9'd0, 6'd2, 12'd30, 12'd13, 0, 438, "col-yb13-xb30");
check_nibble(9'd0, 6'd2, 12'd31, 12'd13, 0, 446, "col-yb13-xb31");
// yb=14: 385 393 417 425 449 457 481 489 387 395 419 427 451 459 483 491
// 389 397 421 429 453 461 485 493 391 399 423 431 455 463 487 495
check_nibble(9'd0, 6'd2, 12'd0, 12'd14, 0, 385, "col-yb14-xb0");
check_nibble(9'd0, 6'd2, 12'd1, 12'd14, 0, 393, "col-yb14-xb1");
check_nibble(9'd0, 6'd2, 12'd2, 12'd14, 0, 417, "col-yb14-xb2");
check_nibble(9'd0, 6'd2, 12'd3, 12'd14, 0, 425, "col-yb14-xb3");
check_nibble(9'd0, 6'd2, 12'd4, 12'd14, 0, 449, "col-yb14-xb4");
check_nibble(9'd0, 6'd2, 12'd5, 12'd14, 0, 457, "col-yb14-xb5");
check_nibble(9'd0, 6'd2, 12'd6, 12'd14, 0, 481, "col-yb14-xb6");
check_nibble(9'd0, 6'd2, 12'd7, 12'd14, 0, 489, "col-yb14-xb7");
check_nibble(9'd0, 6'd2, 12'd8, 12'd14, 0, 387, "col-yb14-xb8");
check_nibble(9'd0, 6'd2, 12'd9, 12'd14, 0, 395, "col-yb14-xb9");
check_nibble(9'd0, 6'd2, 12'd10, 12'd14, 0, 419, "col-yb14-xb10");
check_nibble(9'd0, 6'd2, 12'd11, 12'd14, 0, 427, "col-yb14-xb11");
check_nibble(9'd0, 6'd2, 12'd12, 12'd14, 0, 451, "col-yb14-xb12");
check_nibble(9'd0, 6'd2, 12'd13, 12'd14, 0, 459, "col-yb14-xb13");
check_nibble(9'd0, 6'd2, 12'd14, 12'd14, 0, 483, "col-yb14-xb14");
check_nibble(9'd0, 6'd2, 12'd15, 12'd14, 0, 491, "col-yb14-xb15");
check_nibble(9'd0, 6'd2, 12'd16, 12'd14, 0, 389, "col-yb14-xb16");
check_nibble(9'd0, 6'd2, 12'd17, 12'd14, 0, 397, "col-yb14-xb17");
check_nibble(9'd0, 6'd2, 12'd18, 12'd14, 0, 421, "col-yb14-xb18");
check_nibble(9'd0, 6'd2, 12'd19, 12'd14, 0, 429, "col-yb14-xb19");
check_nibble(9'd0, 6'd2, 12'd20, 12'd14, 0, 453, "col-yb14-xb20");
check_nibble(9'd0, 6'd2, 12'd21, 12'd14, 0, 461, "col-yb14-xb21");
check_nibble(9'd0, 6'd2, 12'd22, 12'd14, 0, 485, "col-yb14-xb22");
check_nibble(9'd0, 6'd2, 12'd23, 12'd14, 0, 493, "col-yb14-xb23");
check_nibble(9'd0, 6'd2, 12'd24, 12'd14, 0, 391, "col-yb14-xb24");
check_nibble(9'd0, 6'd2, 12'd25, 12'd14, 0, 399, "col-yb14-xb25");
check_nibble(9'd0, 6'd2, 12'd26, 12'd14, 0, 423, "col-yb14-xb26");
check_nibble(9'd0, 6'd2, 12'd27, 12'd14, 0, 431, "col-yb14-xb27");
check_nibble(9'd0, 6'd2, 12'd28, 12'd14, 0, 455, "col-yb14-xb28");
check_nibble(9'd0, 6'd2, 12'd29, 12'd14, 0, 463, "col-yb14-xb29");
check_nibble(9'd0, 6'd2, 12'd30, 12'd14, 0, 487, "col-yb14-xb30");
check_nibble(9'd0, 6'd2, 12'd31, 12'd14, 0, 495, "col-yb14-xb31");
// yb=15: 401 409 433 441 465 473 497 505 403 411 435 443 467 475 499 507
// 405 413 437 445 469 477 501 509 407 415 439 447 471 479 503 511
check_nibble(9'd0, 6'd2, 12'd0, 12'd15, 0, 401, "col-yb15-xb0");
check_nibble(9'd0, 6'd2, 12'd1, 12'd15, 0, 409, "col-yb15-xb1");
check_nibble(9'd0, 6'd2, 12'd2, 12'd15, 0, 433, "col-yb15-xb2");
check_nibble(9'd0, 6'd2, 12'd3, 12'd15, 0, 441, "col-yb15-xb3");
check_nibble(9'd0, 6'd2, 12'd4, 12'd15, 0, 465, "col-yb15-xb4");
check_nibble(9'd0, 6'd2, 12'd5, 12'd15, 0, 473, "col-yb15-xb5");
check_nibble(9'd0, 6'd2, 12'd6, 12'd15, 0, 497, "col-yb15-xb6");
check_nibble(9'd0, 6'd2, 12'd7, 12'd15, 0, 505, "col-yb15-xb7");
check_nibble(9'd0, 6'd2, 12'd8, 12'd15, 0, 403, "col-yb15-xb8");
check_nibble(9'd0, 6'd2, 12'd9, 12'd15, 0, 411, "col-yb15-xb9");
check_nibble(9'd0, 6'd2, 12'd10, 12'd15, 0, 435, "col-yb15-xb10");
check_nibble(9'd0, 6'd2, 12'd11, 12'd15, 0, 443, "col-yb15-xb11");
check_nibble(9'd0, 6'd2, 12'd12, 12'd15, 0, 467, "col-yb15-xb12");
check_nibble(9'd0, 6'd2, 12'd13, 12'd15, 0, 475, "col-yb15-xb13");
check_nibble(9'd0, 6'd2, 12'd14, 12'd15, 0, 499, "col-yb15-xb14");
check_nibble(9'd0, 6'd2, 12'd15, 12'd15, 0, 507, "col-yb15-xb15");
check_nibble(9'd0, 6'd2, 12'd16, 12'd15, 0, 405, "col-yb15-xb16");
check_nibble(9'd0, 6'd2, 12'd17, 12'd15, 0, 413, "col-yb15-xb17");
check_nibble(9'd0, 6'd2, 12'd18, 12'd15, 0, 437, "col-yb15-xb18");
check_nibble(9'd0, 6'd2, 12'd19, 12'd15, 0, 445, "col-yb15-xb19");
check_nibble(9'd0, 6'd2, 12'd20, 12'd15, 0, 469, "col-yb15-xb20");
check_nibble(9'd0, 6'd2, 12'd21, 12'd15, 0, 477, "col-yb15-xb21");
check_nibble(9'd0, 6'd2, 12'd22, 12'd15, 0, 501, "col-yb15-xb22");
check_nibble(9'd0, 6'd2, 12'd23, 12'd15, 0, 509, "col-yb15-xb23");
check_nibble(9'd0, 6'd2, 12'd24, 12'd15, 0, 407, "col-yb15-xb24");
check_nibble(9'd0, 6'd2, 12'd25, 12'd15, 0, 415, "col-yb15-xb25");
check_nibble(9'd0, 6'd2, 12'd26, 12'd15, 0, 439, "col-yb15-xb26");
check_nibble(9'd0, 6'd2, 12'd27, 12'd15, 0, 447, "col-yb15-xb27");
check_nibble(9'd0, 6'd2, 12'd28, 12'd15, 0, 471, "col-yb15-xb28");
check_nibble(9'd0, 6'd2, 12'd29, 12'd15, 0, 479, "col-yb15-xb29");
check_nibble(9'd0, 6'd2, 12'd30, 12'd15, 0, 503, "col-yb15-xb30");
check_nibble(9'd0, 6'd2, 12'd31, 12'd15, 0, 511, "col-yb15-xb31");
// -----------------------------------------------------------
// Phase 2b — within-block 16×32 walk via the in-TB
// ref_col_idx4 (self-check that ref_col_idx4 agrees with
// the DUT — Phase 2a's full literal source-lock above is
// the load-bearing check; this walk just guards the ref
// function for use in Phase 5's bijectivity sweep).
// -----------------------------------------------------------
for (int yb_i = 0; yb_i < 16; yb_i++) begin
for (int xb_i = 0; xb_i < 32; xb_i++) begin
check_nibble(9'd0, 6'd2, 12'(xb_i), 12'(yb_i),
0, ref_col_idx4(yb_i, xb_i),
"ref-self-check");
end
end
// -----------------------------------------------------------
// Phase 3 — INDEPENDENT block-table source lock. 32 hard-
// coded address checks (one per block in page 0) where the
// expected block index is taken VERBATIM from PCSX2
// blockTable4 (NOT derived from ref_block_idx4).
// For each block (block_y, block_x), use pixel
// (32*block_x, 16*block_y) — xb=yb=0 → nibble=0 → byte 0,
// hi=0 within the block; total addr = block_idx * 256.
//
// blockTable4[8][4] (PCSX2 master GSTables.cpp:6169):
// by=0: 0 2 8 10
// by=1: 1 3 9 11
// by=2: 4 6 12 14
// by=3: 5 7 13 15
// by=4: 16 18 24 26
// by=5: 17 19 25 27
// by=6: 20 22 28 30
// by=7: 21 23 29 31
// -----------------------------------------------------------
check(9'd0, 6'd2, 12'(0*32), 12'(0*16), 32'(0*256), 1'b0, "src-lock-by0bx0");
check(9'd0, 6'd2, 12'(1*32), 12'(0*16), 32'(2*256), 1'b0, "src-lock-by0bx1");
check(9'd0, 6'd2, 12'(2*32), 12'(0*16), 32'(8*256), 1'b0, "src-lock-by0bx2");
check(9'd0, 6'd2, 12'(3*32), 12'(0*16), 32'(10*256), 1'b0, "src-lock-by0bx3");
check(9'd0, 6'd2, 12'(0*32), 12'(1*16), 32'(1*256), 1'b0, "src-lock-by1bx0");
check(9'd0, 6'd2, 12'(1*32), 12'(1*16), 32'(3*256), 1'b0, "src-lock-by1bx1");
check(9'd0, 6'd2, 12'(2*32), 12'(1*16), 32'(9*256), 1'b0, "src-lock-by1bx2");
check(9'd0, 6'd2, 12'(3*32), 12'(1*16), 32'(11*256), 1'b0, "src-lock-by1bx3");
check(9'd0, 6'd2, 12'(0*32), 12'(2*16), 32'(4*256), 1'b0, "src-lock-by2bx0");
check(9'd0, 6'd2, 12'(1*32), 12'(2*16), 32'(6*256), 1'b0, "src-lock-by2bx1");
check(9'd0, 6'd2, 12'(2*32), 12'(2*16), 32'(12*256), 1'b0, "src-lock-by2bx2");
check(9'd0, 6'd2, 12'(3*32), 12'(2*16), 32'(14*256), 1'b0, "src-lock-by2bx3");
check(9'd0, 6'd2, 12'(0*32), 12'(3*16), 32'(5*256), 1'b0, "src-lock-by3bx0");
check(9'd0, 6'd2, 12'(1*32), 12'(3*16), 32'(7*256), 1'b0, "src-lock-by3bx1");
check(9'd0, 6'd2, 12'(2*32), 12'(3*16), 32'(13*256), 1'b0, "src-lock-by3bx2");
check(9'd0, 6'd2, 12'(3*32), 12'(3*16), 32'(15*256), 1'b0, "src-lock-by3bx3");
check(9'd0, 6'd2, 12'(0*32), 12'(4*16), 32'(16*256), 1'b0, "src-lock-by4bx0");
check(9'd0, 6'd2, 12'(1*32), 12'(4*16), 32'(18*256), 1'b0, "src-lock-by4bx1");
check(9'd0, 6'd2, 12'(2*32), 12'(4*16), 32'(24*256), 1'b0, "src-lock-by4bx2");
check(9'd0, 6'd2, 12'(3*32), 12'(4*16), 32'(26*256), 1'b0, "src-lock-by4bx3");
check(9'd0, 6'd2, 12'(0*32), 12'(5*16), 32'(17*256), 1'b0, "src-lock-by5bx0");
check(9'd0, 6'd2, 12'(1*32), 12'(5*16), 32'(19*256), 1'b0, "src-lock-by5bx1");
check(9'd0, 6'd2, 12'(2*32), 12'(5*16), 32'(25*256), 1'b0, "src-lock-by5bx2");
check(9'd0, 6'd2, 12'(3*32), 12'(5*16), 32'(27*256), 1'b0, "src-lock-by5bx3");
check(9'd0, 6'd2, 12'(0*32), 12'(6*16), 32'(20*256), 1'b0, "src-lock-by6bx0");
check(9'd0, 6'd2, 12'(1*32), 12'(6*16), 32'(22*256), 1'b0, "src-lock-by6bx1");
check(9'd0, 6'd2, 12'(2*32), 12'(6*16), 32'(28*256), 1'b0, "src-lock-by6bx2");
check(9'd0, 6'd2, 12'(3*32), 12'(6*16), 32'(30*256), 1'b0, "src-lock-by6bx3");
check(9'd0, 6'd2, 12'(0*32), 12'(7*16), 32'(21*256), 1'b0, "src-lock-by7bx0");
check(9'd0, 6'd2, 12'(1*32), 12'(7*16), 32'(23*256), 1'b0, "src-lock-by7bx1");
check(9'd0, 6'd2, 12'(2*32), 12'(7*16), 32'(29*256), 1'b0, "src-lock-by7bx2");
check(9'd0, 6'd2, 12'(3*32), 12'(7*16), 32'(31*256), 1'b0, "src-lock-by7bx3");
// -----------------------------------------------------------
// Phase 4 — block-swizzle walk via the in-TB ref_block_idx4
// (the bijectivity sweep below relies on it being correct).
// -----------------------------------------------------------
for (int by_i = 0; by_i < 8; by_i++) begin
for (int bx_i = 0; bx_i < 4; bx_i++) begin
check(9'd0, 6'd2, 12'(bx_i*32), 12'(by_i*16),
32'(ref_block_idx4(by_i, bx_i) * 256), 1'b0,
"block-swizzle-walk");
end
end
// -----------------------------------------------------------
// Phase 5 — bijectivity sweep over the 128×128 page (16384
// pixels). Each pixel maps to a (byte_addr, nibble_hi) pair;
// encode as nibble_slot = byte_addr*2 + nibble_hi. Every
// pixel must hit a unique nibble_slot in `[0, 16384)` and
// agree with ref_addr_psmt4 + ref_nibble_hi.
// -----------------------------------------------------------
begin : sweep
logic seen [0:16383];
for (int i = 0; i < 16384; i++) seen[i] = 1'b0;
for (int yy = 0; yy < 128; yy++) begin
for (int xx = 0; xx < 128; xx++) begin
logic [31:0] got_addr;
logic got_nib;
logic [31:0] ref_byte_addr;
logic ref_nib;
int nibble_slot;
compute(9'd0, 6'd2, 12'(xx), 12'(yy), got_addr, got_nib);
ref_byte_addr = ref_addr_psmt4(0, 2, xx, yy);
ref_nib = ref_nibble_hi(xx, yy);
if (got_addr !== ref_byte_addr) begin
$error("sweep: (%0d,%0d) addr DUT=0x%08x ref=0x%08x",
xx, yy, got_addr, ref_byte_addr);
errors = errors + 1;
end
if (got_nib !== ref_nib) begin
$error("sweep: (%0d,%0d) nibble_hi DUT=%0b ref=%0b",
xx, yy, got_nib, ref_nib);
errors = errors + 1;
end
if (got_addr >= 32'd8192) begin
$error("sweep: (%0d,%0d) addr=0x%08x out of page bounds",
xx, yy, got_addr);
errors = errors + 1;
end
nibble_slot = (got_addr[12:0] * 2) + (got_nib ? 1 : 0);
if (seen[nibble_slot]) begin
$error("sweep: (%0d,%0d) addr=0x%08x hi=%0b duplicate (slot=%0d)",
xx, yy, got_addr, got_nib, nibble_slot);
errors = errors + 1;
end
seen[nibble_slot] = 1'b1;
end
end
for (int i = 0; i < 16384; i++) begin
if (!seen[i]) begin
$error("sweep: nibble_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 = 8192.
// bx = (192 % 128) / 32 = 64/32 = 2.
// by = (16 % 128) / 16 = 16/16 = 1.
// block (by=1, bx=2) → blockTable4[1][2] = 9 →
// block_base = 8192 + 9*256 = 10496.
// xb = 192%32 = 0, yb = 16%16 = 0 → nibble = 0 → byte 0,
// hi=0. addr = 10496.
// -----------------------------------------------------------
check(9'd0, 6'd4, 12'd192, 12'd16, 32'd10496, 1'b0, "fbw4-multi-page-x");
// FBW=4 + page-y crossing: (0, 128) → page (0, 1),
// page_idx = 1*2 + 0 = 2, page_base = 16384.
check(9'd0, 6'd4, 12'd0, 12'd128, 32'd16384, 1'b0, "fbw4-page-y-origin");
// -----------------------------------------------------------
// Non-page-aligned FBP coverage. FBP=1 → 2048; FBP=2 → 4096;
// FBP=3 → 6144. (0,0) → addr = FBP*2048.
// -----------------------------------------------------------
check(9'd1, 6'd2, 12'd0, 12'd0, 32'd2048, 1'b0, "fbp1-mid-page-origin");
check(9'd2, 6'd2, 12'd0, 12'd0, 32'd4096, 1'b0, "fbp2-mid-page-origin");
check(9'd3, 6'd2, 12'd0, 12'd0, 32'd6144, 1'b0, "fbp3-mid-page-origin");
// FBP=3 + FBW=4 + intra-block + page-(1,1) crossing:
// (129, 129) → page (1, 1), page_idx = 1*2+1 = 3,
// page_base = 6144 + 3*8192 = 30720.
// bx = (129 % 128) / 32 = 0, by = (129 % 128) / 16 = 0.
// block (0,0) → swizzle 0 → block_base = 30720.
// xb = 129%32 = 1, yb = 129%16 = 1.
// nibble = ref_col_idx4(1, 1) = 24 → byte 12, hi=0 →
// addr = 30732.
check(9'd3, 6'd4, 12'd129, 12'd129, 32'd30732, 1'b0,
"fbp3-fbw4-page1-1-intra");
$display("[tb_gs_swizzle_psmt4] errors=%0d", errors);
if (errors == 0) $display("[tb_gs_swizzle_psmt4] PASS");
else $display("[tb_gs_swizzle_psmt4] FAIL");
$finish;
end
initial begin
#2000000;
$error("[tb_gs_swizzle_psmt4] timeout");
$finish;
end
endmodule : tb_gs_swizzle_psmt4