`timescale 1ns/1ps module tb_cdc_strobe_data; localparam integer WIDTH = 16; localparam integer NUM_TX = 5; // Source domain reg s_clk; reg s_rst; reg s_pulse; reg [WIDTH-1:0] s_data; wire s_busy; wire s_accepted; // Destination domain reg d_clk; reg d_rst; wire d_pulse; wire [WIDTH-1:0] d_data; reg [WIDTH-1:0] exp_data [0:NUM_TX-1]; integer rx_idx; integer tx_idx; cdc_strobe_data #( .WIDTH(WIDTH), .STABLE_SAMPLES(2) ) dut ( .s_clk(s_clk), .s_rst(s_rst), .s_pulse(s_pulse), .s_data(s_data), .s_busy(s_busy), .s_accepted(s_accepted), .d_clk(d_clk), .d_rst(d_rst), .d_pulse(d_pulse), .d_data(d_data) ); initial s_clk = 1'b0; always #625 s_clk = ~s_clk; // 800 kHz initial d_clk = 1'b0; always #33.333 d_clk = ~d_clk; // 15 MHz (asynchronous to s_clk) task send_word; input [WIDTH-1:0] value; begin @(posedge s_clk); while (s_busy) @(posedge s_clk); s_data <= value; s_pulse <= 1'b1; @(posedge s_clk); if (!s_accepted) begin $display("[%0t] ERROR: expected s_accepted for value 0x%0h", $time, value); $fatal(1); end s_pulse <= 1'b0; s_data <= {WIDTH{1'b0}}; end endtask always @(posedge d_clk) begin if (!d_rst && d_pulse) begin if (rx_idx >= NUM_TX) begin $display("[%0t] ERROR: unexpected extra d_pulse with data=0x%0h", $time, d_data); $fatal(1); end if (d_data !== exp_data[rx_idx]) begin $display("[%0t] ERROR: rx[%0d] expected 0x%0h, got 0x%0h", $time, rx_idx, exp_data[rx_idx], d_data); $fatal(1); end $display("[%0t] INFO: rx[%0d] = 0x%0h", $time, rx_idx, d_data); rx_idx <= rx_idx + 1; end end initial begin $dumpfile("out.vcd"); $dumpvars(0, tb_cdc_strobe_data); s_rst = 1'b1; d_rst = 1'b1; s_pulse = 1'b0; s_data = {WIDTH{1'b0}}; rx_idx = 0; tx_idx = 0; exp_data[0] = 16'h1234; exp_data[1] = 16'h00A5; exp_data[2] = 16'hBEEF; exp_data[3] = 16'h5AA5; exp_data[4] = 16'hCAFE; repeat (4) @(posedge s_clk); s_rst = 1'b0; repeat (3) @(posedge d_clk); d_rst = 1'b0; for (tx_idx = 0; tx_idx < NUM_TX; tx_idx = tx_idx + 1) send_word(exp_data[tx_idx]); wait (rx_idx == NUM_TX); $display("[%0t] PASS: received %0d/%0d transfers correctly", $time, rx_idx, NUM_TX); #20; $finish; end initial begin #100000000; $display("[%0t] ERROR: timeout waiting for transfers", $time); $fatal(1); end endmodule