// tb_sha3_xsim_simple.v - Self-checking testbench for sha3_top (G/H/J modes) // // Drives sha3_top in all three modes and checks hash_o against expected // values computed by the verified Python reference (server_code SHA_3, // KAT-validated). Vectors are deterministic (gen_vectors seed=20260627). // // G (mode=00, SHA3-512): data_i[263:0] = d||k, output 512 bits // H (mode=01, SHA3-256): data_i[255:0] = ek, output low 256 bits // J (mode=10, SHAKE-256): data_i[511:0] = z||c, output low 256 bits // // data_i / hash_o use MSB-first hex packing (hex[511:0] literal == data_i). // // Usage: // xvlog -sv sha3_top.v tb_sha3_xsim_simple.v // xelab tb_sha3_xsim_simple -s sha3_sim // xsim sha3_sim -R `timescale 1ns / 1ps module tb_sha3_xsim_simple; // ================================================================ // DUT signals // ================================================================ reg clk; reg rst_n; reg [1:0] mode; reg [511:0] data_i; reg valid_i; wire ready_o; wire [511:0] hash_o; wire valid_o; reg ready_i; // ================================================================ // DUT instantiation // ================================================================ sha3_top u_dut ( .clk (clk), .rst_n (rst_n), .mode (mode), .data_i (data_i), .valid_i (valid_i), .ready_o (ready_o), .hash_o (hash_o), .valid_o (valid_o), .ready_i (ready_i) ); // ================================================================ // Clock generation: 100 MHz (10 ns period) // ================================================================ initial clk = 1'b0; always #5 clk = ~clk; // ================================================================ // Expected vectors (verified Python reference, seed=20260627) // ================================================================ // G: data_i[263:0] = {k=2, d}; output 512-bit SHA3-512 localparam [511:0] G_DATA = 512'h000000000000000000000000000000000000000000000000000000000000007DBC2AC0D13D719B37B4E2D4691951FF890A97854EF5D3A8957EF67A54978E26C9; localparam [511:0] G_EXP = 512'h615E530C77D5D834311E922DB99D5B7F1D57C7B08F029FD829914D3F4035FB730350FD00A852A5CCE9CFC79CF8C61384FEA115030E41750A6AE2CFE055D7976D; // H: data_i[255:0] = ek; output 256-bit SHA3-256 (in hash_o[255:0]) localparam [511:0] H_DATA = 512'h000000000000000000000000000000000000000000000000000000000000000047885BF4E257CF39645D34C593047B7570D6ABBA300599D96171A950BB5027D5; localparam [255:0] H_EXP = 256'h6B44867E24B29A9231570DF5E1D6D14DB0C29EBD7A40AE98606EF66B8244C308; // J: data_i[511:0] = {c, z}; output 256-bit SHAKE-256 (in hash_o[255:0]) localparam [511:0] J_DATA = 512'hB73DCA0F437D2334320494E5D0F728D73F5275E342572FF9B0219DC338CB3C2F0F7398474A3D68C4C90B777F42FA4C12B1FC8F70E1DAADF20755473CC2653D3C; localparam [255:0] J_EXP = 256'hECEC4DAD11DFF42D911925DB83F13D119209AB4EE182E9E9BA0F29F5524B240E; integer error_count; integer cycle_count; parameter TIMEOUT = 200; // ================================================================ // Drive one mode and self-check against expected output // ================================================================ task run_mode(input [1:0] m, input [511:0] din, input [511:0] exp, input integer out_bits, input [127:0] label); reg [511:0] got; begin @(posedge clk); mode <= m; data_i <= din; valid_i <= 1'b1; @(posedge clk); valid_i <= 1'b0; cycle_count = 0; while (!valid_o && cycle_count < TIMEOUT) begin @(posedge clk); cycle_count = cycle_count + 1; end if (cycle_count >= TIMEOUT) begin $display("FAIL [%0s]: TIMEOUT, valid_o not asserted", label); error_count = error_count + 1; end else begin got = hash_o; if (out_bits == 512) begin if (got !== exp) begin $display("FAIL [%0s]: hash mismatch", label); $display(" got = 512'h%0h", got); $display(" exp = 512'h%0h", exp); error_count = error_count + 1; end else begin $display("PASS [%0s]: hash_o = 512'h%0h", label, got); end end else begin // Compare low 256 bits only if (got[255:0] !== exp[255:0]) begin $display("FAIL [%0s]: hash mismatch", label); $display(" got = 256'h%0h", got[255:0]); $display(" exp = 256'h%0h", exp[255:0]); error_count = error_count + 1; end else begin $display("PASS [%0s]: hash_o = 256'h%0h", label, got[255:0]); end end end // Wait for DUT to return to IDLE @(posedge clk); while (!ready_o) @(posedge clk); end endtask // ================================================================ // Test sequence // ================================================================ initial begin error_count = 0; $display("========================================"); $display(" SHA3 Top Testbench (G / H / J modes)"); $display("========================================"); mode <= 2'd0; data_i <= 512'd0; valid_i <= 1'b0; ready_i <= 1'b1; rst_n <= 1'b0; repeat (3) @(posedge clk); rst_n <= 1'b1; @(posedge clk); $display("INFO: Reset complete. Running G/H/J..."); run_mode(2'd0, G_DATA, G_EXP, 512, "G SHA3-512"); run_mode(2'd1, H_DATA, {256'd0,H_EXP},256, "H SHA3-256"); run_mode(2'd2, J_DATA, {256'd0,J_EXP},256, "J SHAKE-256"); $display("========================================"); if (error_count == 0) $display("ALL TESTS PASSED (3/3 modes)"); else $display("TESTS FAILED: %0d error(s)", error_count); $display("========================================"); $finish; end // ================================================================ // Timeout watchdog // ================================================================ initial begin #(TIMEOUT * 10 * 100); $display("FATAL: Global simulation timeout"); $finish; end endmodule