/*
 * led_ctrl_tb.v
 *
 * vim: ts=4 sw=4
 *
 * Copyright (C) 2022-2023  Sylvain Munaut <tnt@246tNt.com>
 * SPDX-License-Identifier: CERN-OHL-P-2.0
 */

`default_nettype none
`timescale 1ns / 100ps

module led_ctrl_tb;

	// Signals
	// -------

	// DUT
	wire [13:0] led_a;
	wire  [2:0] led_c;

	wire        trig_out;

	// Wishbone interface
	reg  [31:0] wb_wdata;
	wire [31:0] wb_rdata;
	reg  [15:0] wb_addr;
	reg         wb_we;
	reg         wb_cyc;
	wire        wb_ack;

	// Clocks / Sync
	reg         pll_lock = 1'b0;

	reg         led_clk = 1'b0;
	wire        led_rst;
	reg   [3:0] led_rst_cnt = 4'h8;

	reg         wb_clk = 1'b0;
	wire        wb_rst;
	reg   [3:0] wb_rst_cnt = 4'h8;


	// Recording setup
	// ---------------

	initial begin
		$dumpfile("led_ctrl_tb.vcd");
		$dumpvars(0,led_ctrl_tb);
	end


	// DUT
	// ---

	led_ctrl dut_I (
		.led_a    (led_a),
		.led_c    (led_c),
		.led_clk  (led_clk),
		.led_rst  (led_rst),
		.trig_out (trig_out),
		.wb_addr  (wb_addr),
		.wb_rdata (wb_rdata),
		.wb_wdata (wb_wdata),
		.wb_we    (wb_we),
		.wb_cyc   (wb_cyc),
		.wb_ack   (wb_ack),
		.wb_clk   (wb_clk),
		.wb_rst   (wb_rst)
	);


	// Stimulus
	// --------

	task wb_write;
		input [15:0] addr;
		input [31:0] data;
		begin
			wb_addr  <= addr;
			wb_wdata <= data;
			wb_we    <= 1'b1;
			wb_cyc   <= 1'b1;

			while (~wb_ack)
				@(posedge wb_clk);

			wb_addr  <= 4'hx;
			wb_wdata <= 32'hxxxxxxxx;
			wb_we    <= 1'bx;
			wb_cyc   <= 1'b0;

			@(posedge wb_clk);
		end
	endtask

	initial begin
		// Defaults
		wb_addr  <= 4'hx;
		wb_wdata <= 32'hxxxxxxxx;
		wb_we    <= 1'bx;
		wb_cyc   <= 1'b0;

		@(negedge wb_rst);
		@(negedge led_rst);
		@(posedge wb_clk);

		// Write to frame memory
			// Anode 4
			// C0 [00-7f] (all ON)
			// C1         (all OFF)
			// C2 [40-4f] (16 cycles)
		wb_write(16'h0200, 32'h7f_00_00_04);
		wb_write(16'h0201, 32'h4f_40_00_7f);

		wb_write(16'h0202, 32'h01_01_00_0a);
		wb_write(16'h0203, 32'h01_00_00_01);

		// Enable
		wb_write(16'h0000, 32'hc0000007);
	end


	// Clock / Reset
	// -------------

	// Clocks
	initial begin
		# 200 pll_lock = 1'b1;
		# 1000000 $finish;
		//# 35000000 $finish;
	end

	always #20 wb_clk  = ~wb_clk;		// 25 MHz
	always #83 led_clk = ~led_clk;		//  6 MHz

	// Reset
	always @(posedge wb_clk or negedge pll_lock)
		if (~pll_lock)
			wb_rst_cnt <= 4'h8;
		else if (wb_rst_cnt[3])
			wb_rst_cnt <= wb_rst_cnt + 1;

	assign wb_rst = wb_rst_cnt[3];

	always @(posedge led_clk or negedge pll_lock)
		if (~pll_lock)
			led_rst_cnt <= 4'h8;
		else if (led_rst_cnt[3])
			led_rst_cnt <= led_rst_cnt + 1;

	assign led_rst = led_rst_cnt[3];

endmodule
