`timescale 1ns/1ps // ============================================================ // Isolated correctness test for weight_tile_gather.v, forked against // a real layer_weight_buffer.v (hardware/v2/rtl/, unmodified) -- // verifies the byte->tile assembly is bit-exact BEFORE integrating // with neural_processor_packed.v, per this project's own "verify in // isolation first" discipline (see feedback-correctness-first- // verification). // ============================================================ module tb; localparam DATA_WIDTH = 8; localparam P_IN = 8; localparam LAYER_DEPTH = 128; localparam BUFADDRW = $clog2(LAYER_DEPTH); localparam N_TILES = LAYER_DEPTH / P_IN; reg clk = 0; always #5 clk = ~clk; // 100MHz sim clock, arbitrary for a functional-only check reg rst; integer errors, tests; // ---- layer_weight_buffer.v (real, unmodified) ---- reg fill_we; reg [BUFADDRW-1:0] fill_addr; reg [DATA_WIDTH-1:0] fill_data; reg fill_done; wire [BUFADDRW-1:0] rd_addr; wire [DATA_WIDTH-1:0] rd_data; reg consume_done; wire active_sel, swapped; layer_weight_buffer #( .DATA_WIDTH(DATA_WIDTH), .LAYER_DEPTH(LAYER_DEPTH) ) buf_dut ( .clk(clk), .rst(rst), .fill_we(fill_we), .fill_addr(fill_addr), .fill_data(fill_data), .fill_done(fill_done), .rd_addr(rd_addr), .rd_data(rd_data), .consume_done(consume_done), .active_sel(active_sel), .swapped(swapped) ); // ---- weight_tile_gather.v (DUT) ---- reg tile_req; reg [BUFADDRW-1:0] tile_base; wire tile_valid; wire [DATA_WIDTH*P_IN-1:0] tile_data; weight_tile_gather #( .DATA_WIDTH(DATA_WIDTH), .P_IN(P_IN), .BUFADDRW(BUFADDRW) ) gather_dut ( .clk(clk), .rst(rst), .tile_req(tile_req), .tile_base(tile_base), .tile_valid(tile_valid), .tile_data(tile_data), .rd_addr(rd_addr), .rd_data(rd_data) ); // ---- reference layer content: layer_pattern[i] = (i*7+3) & 0xFF // (deterministic, non-uniform, matches this project's own // "small non-uniform values" testing convention) ---- reg [DATA_WIDTH-1:0] layer_pattern [0:LAYER_DEPTH-1]; integer li; task automatic gather_and_check(input [BUFADDRW-1:0] base, input integer tile_idx); integer k; reg [DATA_WIDTH*P_IN-1:0] expected; begin for (k = 0; k < P_IN; k = k + 1) expected[k*DATA_WIDTH +: DATA_WIDTH] = layer_pattern[base + k]; @(posedge clk); tile_req = 1'b1; tile_base = base; @(posedge clk); tile_req = 1'b0; while (!tile_valid) @(posedge clk); tests = tests + 1; if (tile_data !== expected) begin $display("FAIL tile %0d base=%0d: got=%h expected=%h", tile_idx, base, tile_data, expected); errors = errors + 1; end else begin $display("PASS tile %0d base=%0d: bit-exact %h", tile_idx, base, tile_data); end end endtask integer t; initial begin errors = 0; tests = 0; rst = 1; fill_we = 0; fill_addr = 0; fill_data = 0; fill_done = 0; consume_done = 0; tile_req = 0; tile_base = 0; for (li = 0; li < LAYER_DEPTH; li = li + 1) layer_pattern[li] = (li*7+3) & 8'hFF; repeat(3) @(posedge clk); rst = 0; @(posedge clk); // fill the (inactive) buffer with the reference pattern via // the real fill_we/fill_addr/fill_data port, then declare it done for (li = 0; li < LAYER_DEPTH; li = li + 1) begin @(posedge clk); fill_we = 1'b1; fill_addr = li[BUFADDRW-1:0]; fill_data = layer_pattern[li]; end @(posedge clk); fill_we = 1'b0; fill_done = 1'b1; @(posedge clk); fill_done = 1'b0; // consume_done pulses too (this buffer's own swap needs both -- // no real "active" consumption happened yet, but at reset // active_sel=0 and we just filled buffer 1 (the inactive one at // reset) -- swap once so reads below hit the buffer we just filled. consume_done = 1'b1; @(posedge clk); consume_done = 1'b0; while (!swapped) @(posedge clk); // wait for the real swap pulse @(posedge clk); $display("=== TEST 1: sequential tiles, whole layer ==="); for (t = 0; t < N_TILES; t = t + 1) gather_and_check(t*P_IN, t); $display("=== TEST 2: back-to-back tile_req with no idle gap ==="); for (t = 0; t < N_TILES; t = t + 1) gather_and_check(t*P_IN, t); $display("=== TEST 3: non-sequential (reuse-position-style) tile requests ==="); gather_and_check(8*P_IN, 8); gather_and_check(2*P_IN, 2); gather_and_check(8*P_IN, 8); // re-request same tile (real reuse pattern) gather_and_check(15*P_IN, 15); gather_and_check(0, 0); $display("=== %0d/%0d tests, %0d errors ===", tests-errors, tests, errors); if (errors == 0) $display("ALL TESTS PASSED (tb_weight_tile_gather)"); $finish; end endmodule