`timescale 1ps/1ps /* verilator lint_off DECLFILENAME */ /* verilator lint_off MULTITOP */ /* verilator lint_off STMTDLY */ /* verilator lint_off INFINITELOOP */ /* verilator lint_off INITIALDLY */ module i2c_io_output_tb; logic clock = 1'b0; logic reset = 1'b1; /* Master clock 100MHz (10ns period) */ always #(10ns/2) clock = ~clock; parameter SCL_PERIOD = 364793; // ~300ns logic scl_async; logic sda_async; event scl_low_ev; event scl_high_ev; initial begin scl_async = 1'b1; forever begin #(SCL_PERIOD/4) scl_async = 1'b1; #(SCL_PERIOD/4) -> scl_high_ev; #(SCL_PERIOD/4) scl_async = 1'b0; #(SCL_PERIOD/4) -> scl_low_ev; end end parameter IO_BYTES_COUNT = 2; parameter [6:0] I2C_ADDRESS = 7'h5a; localparam DATA_WIDTH = IO_BYTES_COUNT * 8; logic i_scl; logic i_sdi; logic o_sdo; logic [DATA_WIDTH-1:0] o_data; i2c_io_output #(.I2C_ADDR(I2C_ADDRESS), .IO_BYTES_COUNT(IO_BYTES_COUNT)) DUT (.*); logic [1:0] scl_sync; logic [1:0] sda_sync; always_ff @(posedge clock) if (reset) begin scl_sync <= '1; sda_sync <= '1; end else begin scl_sync <= {scl_sync[0], scl_async}; sda_sync <= {sda_sync[0], sda_async}; end assign i_scl = scl_sync[1]; assign i_sdi = sda_sync[1]; task send_start; wait(scl_async == 1'b0); sda_async = 1'b1; @(scl_high_ev); sda_async = 1'b0; endtask task send_stop; wait(scl_async == 1'b0); sda_async = 1'b0; @(scl_high_ev); sda_async = 1'b1; endtask task send_byte(logic [7:0] b); for (int n = 7; n >= 0; n -= 1) begin @(scl_low_ev); sda_async = b[n]; end @(scl_low_ev); wait(scl_async == 1'b1); endtask initial begin reset = 1'b1; repeat(2) @(posedge clock) #1; reset = 1'b0; repeat(2) @(posedge clock) #1; send_start; send_byte(8'hb4); send_byte(8'ha5); send_byte(8'h38); send_byte(8'h42); send_stop; repeat(1000) @(posedge clock) #1; $finish; end `ifdef DUMP initial begin $dumpfile("i2c_io_output_tb.fst"); $dumpvars(0, i2c_io_output_tb); end `endif endmodule // i2c_io_output_tb