The "game" is played on a two-dimensional grid of cells, where each cell is either 1 (alive) or 0 (dead). At each time step, each cell changes state depending on how many neighbours it has:
// (1) 0-1 neighbour: Cell becomes 0.
// (2) 2 neighbours: Cell state does not change.
// (3) 3 neighbours: Cell becomes 1.
// (4) 4+ neighbours: Cell becomes 0.
// The game is formulated for an infinite grid. In this circuit, we will use a 16x16 grid. To make things more interesting, we will use a 16x16 toroid, where the sides wrap around to the other side of the grid. For example, the corner cell (0,0) has 8 neighbours: (15,1), (15,0), (15,15), (0,1), (0,15), (1,1), (1,0), and (1,15). The 16x16 grid is represented by a length 256 vector, where each row of 16 cells is represented by a sub-vector: q[15:0] is row 0, q[31:16] is row 1, etc.
// (1) load: Loads data into q at the next clock edge, for loading initial state. Active high synchronous.
// (2) q: The 16x16 current state of the game, updated every clock cycle.
// The game state should advance by one timestep every clock cycle.

module top_module(
	input clk,
	input load,
	input [255:0] data,
	output reg [255:0] q);

`timescale 1 ps/1 ps
`define OK 12
`define INCORRECT 13
module reference_module(
	input clk,
	input load,
	input [255:0] data,
	output reg [255:0] q);

	logic [323:0] q_pad;
	always@(*) begin
		for (int i=0;i<16;i++)
			q_pad[18*(i+1)+1 +: 16] = q[16*i +: 16];
		q_pad[1 +: 16] = q[16*15 +: 16];
		q_pad[18*17+1 +: 16] = q[0 +: 16];

		for (int i=0; i<18; i++) begin
			q_pad[i*18] = q_pad[i*18+16];
			q_pad[i*18+17] = q_pad[i*18+1];
		end
	end

	always @(posedge clk) begin
		for (int i=0;i<16;i++)
		for (int j=0;j<16;j++) begin
			q[i*16+j] <=
				((q_pad[(i+1)*18+j+1 -1+18] + q_pad[(i+1)*18+j+1 +18] + q_pad[(i+1)*18+j+1 +1+18] +
				q_pad[(i+1)*18+j+1 -1]                                + q_pad[(i+1)*18+j+1+1] +
				q_pad[(i+1)*18+j+1 -1-18]   + q_pad[(i+1)*18+j+1 -18] + q_pad[(i+1)*18+j+1 +1-18]) & 3'h7 | q[i*16+j]) == 3'h3;
		end

		if (load)
			q <= data;

	end

endmodule

module stimulus_gen (
	input clk,
	input tb_match,
	input [255:0] q_ref,
	input [255:0] q_dut,
	output reg load,
	output reg[255:0] data
);

	logic errored = 0;
	int blinker_cycle = 0;

	initial begin
		data <= 3'h7;			// Simple blinker, period 2
		load <= 1;
		@(posedge clk);
		load <= 0;
		data <= 4'hx;
		errored = 0;
		blinker_cycle = 0;
		repeat(5) @(posedge clk) begin
			blinker_cycle++;
			if (!tb_match) begin
				if (!errored) begin
					errored = 1;
					$display("Hint: The first test case is a blinker (initial state = 256'h7). First mismatch occurred at cycle %0d.\nHint:", blinker_cycle);
				end
			end

			if (errored) begin
				$display ("Hint: Cycle %0d:         Your game state       Reference game state", blinker_cycle);
				for (int i=15;i>=0;i--) begin
					$display("Hint:   q[%3d:%3d]     %016b      %016b", i*16+15, i*16, q_dut [ i*16 +: 16 ], q_ref[ i*16 +: 16 ]);
				end
				$display("Hint:\nHint:\n");
			end
		end

		data <= 48'h000200010007;	// Glider, Traveling diagonal down-right.
		load <= 1;
		@(posedge clk);
		@(posedge clk);
		@(posedge clk);
		load <= 0;
		data <= 4'hx;
		errored = 0;
		blinker_cycle = 0;
		repeat(100) @(posedge clk) begin
			blinker_cycle++;
			if (!tb_match) begin
				if (!errored) begin
					errored = 1;
					$display("Hint: The second test case is a glider (initial state = 256'h000200010007). First mismatch occurred at cycle %0d.\nHint:", blinker_cycle);
				end
			end

			if (errored && blinker_cycle < 20) begin
				$display ("Hint: Cycle %0d:         Your game state       Reference game state", blinker_cycle);
				for (int i=15;i>=0;i--) begin
					$display("Hint:   q[%3d:%3d]     %016b      %016b", i*16+15, i*16, q_dut [ i*16 +: 16 ], q_ref[ i*16 +: 16 ]);
				end
				$display("Hint:\nHint:\n");
			end
		end

		data <= 48'h0040001000ce;			// Acorn
		load <= 1;
		@(posedge clk);
		load <= 0;
		repeat(2000) @(posedge clk);

		data <= {$random,$random,$random,$random,$random,$random,$random,$random};		// Some random test cases.
		load <= 1;
		@(posedge clk);
		load <= 0;
		repeat(200) @(posedge clk);

		data <= {$random,$random,$random,$random,$random,$random,$random,$random}&		// Random with more zeros.
				{$random,$random,$random,$random,$random,$random,$random,$random}&
				{$random,$random,$random,$random,$random,$random,$random,$random}&
				{$random,$random,$random,$random,$random,$random,$random,$random};
		load <= 1;
		@(posedge clk);
		load <= 0;
		repeat(200) @(posedge clk);

		#1 $finish;
	end

endmodule

module tb();

	typedef struct packed {
		int errors;
		int errortime;
		int errors_q;
		int errortime_q;

		int clocks;
	} stats;

	stats stats1;

	wire[511:0] wavedrom_title;
	wire wavedrom_enable;
	int wavedrom_hide_after_time;

	reg clk=0;
	initial forever
		#5 clk = ~clk;

	logic load;
	logic [255:0] data;
	logic [255:0] q_ref;
	logic [255:0] q_dut;

	initial begin
		$dumpfile("wave.vcd");
		$dumpvars(1, stim1.clk, tb_mismatch ,clk,load,data,q_ref,q_dut );
	end

	wire tb_match;		// Verification
	wire tb_mismatch = ~tb_match;

	stimulus_gen stim1 (
		.clk,
		.* ,
		.load,
		.data );
	reference_module good1 (
		.clk,
		.load,
		.data,
		.q(q_ref) );

	top_module top_module1 (
		.clk,
		.load,
		.data,
		.q(q_dut) );

	bit strobe = 0;
	task wait_for_end_of_timestep;
		repeat(5) begin
			strobe <= !strobe;  // Try to delay until the very end of the time step.
			@(strobe);
		end
	endtask

	final begin
		if (stats1.errors_q) $display("Hint: Output '%s' has %0d mismatches. First mismatch occurred at time %0d.", "q", stats1.errors_q, stats1.errortime_q);
		else $display("Hint: Output '%s' has no mismatches.", "q");

		$display("Hint: Total mismatched samples is %1d out of %1d samples\n", stats1.errors, stats1.clocks);
		$display("Simulation finished at %0d ps", $time);
		$display("Mismatches: %1d in %1d samples", stats1.errors, stats1.clocks);
	end

	// Verification: XORs on the right makes any X in good_vector match anything, but X in dut_vector will only match X.
	assign tb_match = ( { q_ref } === ( { q_ref } ^ { q_dut } ^ { q_ref } ) );
	// Use explicit sensitivity list here. @(*) causes NetProc::nex_input() to be called when trying to compute
	// the sensitivity list of the @(strobe) process, which isn't implemented.
	always @(posedge clk, negedge clk) begin

		stats1.clocks++;
		if (!tb_match) begin
			if (stats1.errors == 0) stats1.errortime = $time;
			stats1.errors++;
		end
		if (q_ref !== ( q_ref ^ q_dut ^ q_ref ))
		begin if (stats1.errors_q == 0) stats1.errortime_q = $time;
			stats1.errors_q = stats1.errors_q+1'b1; end

	end
endmodule


The game Lemmings involves critters with fairly simple brains. So simple that we are going to model it using a finite state machine. In the Lemmings' 2D world, Lemmings can be in one of two states: walking left (walk_left is 1) or walking right (walk_right is 1). It will switch directions if it hits an obstacle. In particular, if a Lemming is bumped on the left (by receiving a 1 on bump_left), it will walk right. If it's bumped on the right (by receiving a 1 on bump_right), it will walk left. If it's bumped on both sides at the same time, it will still switch directions.
// In addition to walking left and right and changing direction when bumped, when ground=0, the Lemming will fall and say "aaah!". When the ground reappears (ground=1), the Lemming will resume walking in the same direction as before the fall. Being bumped while falling does not affect the walking direction, and being bumped in the same cycle as ground disappears (but not yet falling), or when the ground reappears while still falling, also does not affect the walking direction.
// In addition to walking and falling, Lemmings can sometimes be told to do useful things, like dig (it starts digging when dig=1). A Lemming can dig if it is currently walking on ground (ground=1 and not falling), and will continue digging until it reaches the other side (ground=0). At that point, since there is no ground, it will fall (aaah!), then continue walking in its original direction once it hits ground again. As with falling, being bumped while digging has no effect, and being told to dig when falling or when there is no ground is ignored. (In other words, a walking Lemming can fall, dig, or switch directions. If more than one of these conditions are satisfied, fall has higher precedence than dig, which has higher precedence than switching directions.)
// Implement a Moore state machine that models this behaviour. areset is positive edge triggered asynchronous reseting the Lemming machine to walk left.

module top_module (
	input clk,
	input areset,
	input bump_left,
	input bump_right,
	input ground,
	input dig,
	output walk_left,
	output walk_right,
	output aaah,
	output digging
);
	parameter WL=0, WR=1, FALLL=2, FALLR=3, DIGL=4, DIGR=5;
	reg [2:0] state;
	reg [2:0] next;

    always_comb begin
		case (state)
			WL: if (!ground) next = FALLL;
				else if (dig) next = DIGL;
				else if (bump_left) next = WR;
				else next = WL;
			WR:
				if (!ground) next = FALLR;
				else if (dig) next = DIGR;
				else if (bump_right) next = WL;
				else next = WR;
			FALLL: next = ground ? WL : FALLL;
			FALLR: next = ground ? WR : FALLR;
			DIGL: next = ground ? DIGL : FALLL;
			DIGR: next = ground ? DIGR : FALLR;
		endcase
    end

    always @(posedge clk, posedge areset) begin
		if (areset) state <= WL;
        else state <= next;
	end

	assign walk_left = (state==WL);
	assign walk_right = (state==WR);
	assign aaah = (state == FALLL) || (state == FALLR);
	assign digging = (state == DIGL) || (state == DIGR);

endmodule

`timescale 1 ps/1 ps
`define OK 12
`define INCORRECT 13
module reference_module (
	input clk,
	input areset,
	input bump_left,
	input bump_right,
	input ground,
	input dig,
	output walk_left,
	output walk_right,
	output aaah,
	output digging
);
	parameter WL=0, WR=1, FALLL=2, FALLR=3, DIGL=4, DIGR=5;
	reg [2:0] state;
	reg [2:0] next;

    always_comb begin
		case (state)
			WL: if (!ground) next = FALLL;
				else if (dig) next = DIGL;
				else if (bump_left) next = WR;
				else next = WL;
			WR:
				if (!ground) next = FALLR;
				else if (dig) next = DIGR;
				else if (bump_right) next = WL;
				else next = WR;
			FALLL: next = ground ? WL : FALLL;
			FALLR: next = ground ? WR : FALLR;
			DIGL: next = ground ? DIGL : FALLL;
			DIGR: next = ground ? DIGR : FALLR;
		endcase
    end

    always @(posedge clk, posedge areset) begin
		if (areset) state <= WL;
        else state <= next;
	end

	assign walk_left = (state==WL);
	assign walk_right = (state==WR);
	assign aaah = (state == FALLL) || (state == FALLR);
	assign digging = (state == DIGL) || (state == DIGR);

endmodule

module stimulus_gen (
	input clk,
	output logic areset,
	output logic bump_left,
	output logic bump_right,
	output logic dig,
	output logic ground,
	output reg[511:0] wavedrom_title,
	output reg wavedrom_enable,
	input tb_match
);
	reg reset;
	assign areset = reset;

	task reset_test(input async=0);
		bit arfail, srfail, datafail;

		@(posedge clk);
		@(posedge clk) reset <= 0;
		repeat(3) @(posedge clk);

		@(negedge clk) begin datafail = !tb_match ; reset <= 1; end
		@(posedge clk) arfail = !tb_match;
		@(posedge clk) begin
			srfail = !tb_match;
			reset <= 0;
		end
		if (srfail)
			$display("Hint: Your reset doesn't seem to be working.");
		else if (arfail && (async || !datafail))
			$display("Hint: Your reset should be %0s, but doesn't appear to be.", async ? "asynchronous" : "synchronous");
		// Don't warn about synchronous reset if the half-cycle before is already wrong. It's more likely
		// a functionality error than the reset being implemented asynchronously.

	endtask

// Add two ports to module stimulus_gen:
//    output [511:0] wavedrom_title
//    output reg wavedrom_enable

	task wavedrom_start(input[511:0] title = "");
	endtask

	task wavedrom_stop;
		#1;
	endtask

	wire [0:13][3:0] d = {
		4'h2,
		4'h2,
		4'h3,
		4'h2,
		4'ha,
		4'h2,
		4'h0,
		4'h0,
		4'h0,
		4'h3,
		4'h2,
		4'h2,
		4'h2,
		4'h2
	};

	initial begin
		reset <= 1'b1;
		{bump_left, bump_right, ground, dig} <= 4'h2;
		reset_test(1);

		reset <= 1'b1;
		@(posedge clk);
		reset <= 0;

		@(negedge clk);
		wavedrom_start("Digging");
		for (int i=0;i<14;i++)
			@(posedge clk) {bump_left, bump_right, ground, dig} <= d[i];
		wavedrom_stop();

		repeat(400) @(posedge clk, negedge clk) begin
			{dig, bump_right, bump_left} <= $random & $random;
			ground <= |($random & 7);
			reset <= !($random & 31);
		end

		#1 $finish;
	end

endmodule

module tb();

	typedef struct packed {
		int errors;
		int errortime;
		int errors_walk_left;
		int errortime_walk_left;
		int errors_walk_right;
		int errortime_walk_right;
		int errors_aaah;
		int errortime_aaah;
		int errors_digging;
		int errortime_digging;

		int clocks;
	} stats;

	stats stats1;

	wire[511:0] wavedrom_title;
	wire wavedrom_enable;
	int wavedrom_hide_after_time;

	reg clk=0;
	initial forever
		#5 clk = ~clk;

	logic areset;
	logic bump_left;
	logic bump_right;
	logic ground;
	logic dig;
	logic walk_left_ref;
	logic walk_left_dut;
	logic walk_right_ref;
	logic walk_right_dut;
	logic aaah_ref;
	logic aaah_dut;
	logic digging_ref;
	logic digging_dut;

	initial begin
		$dumpfile("wave.vcd");
		$dumpvars(1, stim1.clk, tb_mismatch ,clk,areset,bump_left,bump_right,ground,dig,walk_left_ref,walk_left_dut,walk_right_ref,walk_right_dut,aaah_ref,aaah_dut,digging_ref,digging_dut );
	end

	wire tb_match;		// Verification
	wire tb_mismatch = ~tb_match;

	stimulus_gen stim1 (
		.clk,
		.* ,
		.areset,
		.bump_left,
		.bump_right,
		.ground,
		.dig );
	reference_module good1 (
		.clk,
		.areset,
		.bump_left,
		.bump_right,
		.ground,
		.dig,
		.walk_left(walk_left_ref),
		.walk_right(walk_right_ref),
		.aaah(aaah_ref),
		.digging(digging_ref) );

	top_module top_module1 (
		.clk,
		.areset,
		.bump_left,
		.bump_right,
		.ground,
		.dig,
		.walk_left(walk_left_dut),
		.walk_right(walk_right_dut),
		.aaah(aaah_dut),
		.digging(digging_dut) );

	bit strobe = 0;
	task wait_for_end_of_timestep;
		repeat(5) begin
			strobe <= !strobe;  // Try to delay until the very end of the time step.
			@(strobe);
		end
	endtask

	final begin
		if (stats1.errors_walk_left) $display("Hint: Output '%s' has %0d mismatches. First mismatch occurred at time %0d.", "walk_left", stats1.errors_walk_left, stats1.errortime_walk_left);
		else $display("Hint: Output '%s' has no mismatches.", "walk_left");
		if (stats1.errors_walk_right) $display("Hint: Output '%s' has %0d mismatches. First mismatch occurred at time %0d.", "walk_right", stats1.errors_walk_right, stats1.errortime_walk_right);
		else $display("Hint: Output '%s' has no mismatches.", "walk_right");
		if (stats1.errors_aaah) $display("Hint: Output '%s' has %0d mismatches. First mismatch occurred at time %0d.", "aaah", stats1.errors_aaah, stats1.errortime_aaah);
		else $display("Hint: Output '%s' has no mismatches.", "aaah");
		if (stats1.errors_digging) $display("Hint: Output '%s' has %0d mismatches. First mismatch occurred at time %0d.", "digging", stats1.errors_digging, stats1.errortime_digging);
		else $display("Hint: Output '%s' has no mismatches.", "digging");

		$display("Hint: Total mismatched samples is %1d out of %1d samples\n", stats1.errors, stats1.clocks);
		$display("Simulation finished at %0d ps", $time);
		$display("Mismatches: %1d in %1d samples", stats1.errors, stats1.clocks);
	end

	// Verification: XORs on the right makes any X in good_vector match anything, but X in dut_vector will only match X.
	assign tb_match = ( { walk_left_ref, walk_right_ref, aaah_ref, digging_ref } === ( { walk_left_ref, walk_right_ref, aaah_ref, digging_ref } ^ { walk_left_dut, walk_right_dut, aaah_dut, digging_dut } ^ { walk_left_ref, walk_right_ref, aaah_ref, digging_ref } ) );
	// Use explicit sensitivity list here. @(*) causes NetProc::nex_input() to be called when trying to compute
	// the sensitivity list of the @(strobe) process, which isn't implemented.
	always @(posedge clk, negedge clk) begin

		stats1.clocks++;
		if (!tb_match) begin
			if (stats1.errors == 0) stats1.errortime = $time;
			stats1.errors++;
		end
		if (walk_left_ref !== ( walk_left_ref ^ walk_left_dut ^ walk_left_ref ))
		begin if (stats1.errors_walk_left == 0) stats1.errortime_walk_left = $time;
			stats1.errors_walk_left = stats1.errors_walk_left+1'b1; end
		if (walk_right_ref !== ( walk_right_ref ^ walk_right_dut ^ walk_right_ref ))
		begin if (stats1.errors_walk_right == 0) stats1.errortime_walk_right = $time;
			stats1.errors_walk_right = stats1.errors_walk_right+1'b1; end
		if (aaah_ref !== ( aaah_ref ^ aaah_dut ^ aaah_ref ))
		begin if (stats1.errors_aaah == 0) stats1.errortime_aaah = $time;
			stats1.errors_aaah = stats1.errors_aaah+1'b1; end
		if (digging_ref !== ( digging_ref ^ digging_dut ^ digging_ref ))
		begin if (stats1.errors_digging == 0) stats1.errortime_digging = $time;
			stats1.errors_digging = stats1.errors_digging+1'b1; end

	end
endmodule


Create a set of counters suitable for use as a 12-hour clock (with am/pm indicator). Your counters are clocked by a fast-running clk, with a pulse on ena whenever your clock should increment (i.e., once per second, while "clk" is much faster than once per second). The signal "pm" is asserted if the clock is PM, or is otherwise AM. hh, mm, and ss are two BCD (Binary-Coded Decimal) digits each for hours (01-12), minutes (00-59), and seconds (00-59). Reset is the active high synchronous signal that resets the clock to "12:00 AM." Reset has higher priority than enable and can occur even when not enabled.

module top_module(
	input clk,
	input reset,
	input ena,
	output reg pm,
	output reg [7:0] hh,
	output reg [7:0] mm,
	output reg [7:0] ss);

`timescale 1 ps/1 ps
`define OK 12
`define INCORRECT 13
module reference_module(
	input clk,
	input reset,
	input ena,
	output reg pm,
	output reg [7:0] hh,
	output reg [7:0] mm,
	output reg [7:0] ss);

	wire [6:0] enable = {
		{hh[7:0],mm[7:0],ss[7:0]}==24'h115959,
		{hh[3:0],mm[7:0],ss[7:0]}==20'h95959,
		{mm[7:0],ss[7:0]}==16'h5959,
		{mm[3:0],ss[7:0]}==12'h959,
		ss[7:0]==8'h59,
		ss[3:0] == 4'h9,
		1'b1};

	always @(posedge clk)
		if (reset)
			{pm,hh,mm,ss} <= 25'h0120000;
		else if (ena) begin
			if (enable[0] && ss[3:0] == 9) ss[3:0] <= 0;
			else if (enable[0]) ss[3:0] <= ss[3:0] + 1;

			if (enable[1] && ss[7:4] == 4'h5) ss[7:4] <= 0;
			else if (enable[1]) ss[7:4] <= ss[7:4] + 1;

			if (enable[2] && mm[3:0] == 9) mm[3:0] <= 0;
			else if (enable[2]) mm[3:0] <= mm[3:0] + 1;

			if (enable[3] && mm[7:4] == 4'h5) mm[7:4] <= 0;
			else if (enable[3]) mm[7:4] <= mm[7:4] + 1;

			if (enable[4] && hh[3:0] == 4'h9) hh[3:0] <= 0;
			else if (enable[4]) hh[3:0] <= hh[3:0] + 1;

			if (enable[4] && hh[7:0] == 8'h12) hh[7:0] <= 8'h1;
			else if (enable[5]) hh[7:4] <= hh[7:4] + 1;

			if (enable[6]) pm <= ~pm;
		end
endmodule

module stimulus_gen (
	input clk,
	output reg reset,
	output reg ena,
	input [7:0] hh_dut, mm_dut, ss_dut,
	input pm_dut,
	input tb_match,
	output reg[511:0] wavedrom_title,
	output reg wavedrom_enable
);
	task reset_test(input async=0);
		bit arfail, srfail, datafail;

		@(posedge clk);
		@(posedge clk) reset <= 0;
		repeat(3) @(posedge clk);

		@(negedge clk) begin datafail = !tb_match ; reset <= 1; end
		@(posedge clk) arfail = !tb_match;
		@(posedge clk) begin
			srfail = !tb_match;
			reset <= 0;
		end
		if (srfail)
			$display("Hint: Your reset doesn't seem to be working.");
		else if (arfail && (async || !datafail))
			$display("Hint: Your reset should be %0s, but doesn't appear to be.", async ? "asynchronous" : "synchronous");
		// Don't warn about synchronous reset if the half-cycle before is already wrong. It's more likely
		// a functionality error than the reset being implemented asynchronously.

	endtask

// Add two ports to module stimulus_gen:
//    output [511:0] wavedrom_title
//    output reg wavedrom_enable

	task wavedrom_start(input[511:0] title = "");
	endtask

	task wavedrom_stop;
		#1;
	endtask

	logic bcd_fail = 0;
	logic reset_fail = 0;

	always @(posedge clk) begin
		if ((hh_dut[3:0] >= 4'ha) ||
			(hh_dut[7:4] >= 4'ha) ||
			(mm_dut[3:0] >= 4'ha) ||
			(mm_dut[7:4] >= 4'ha) ||
			(ss_dut[3:0] >= 4'ha) ||
			(ss_dut[7:4] >= 4'ha))
			bcd_fail <= 1'b1;
	end

	initial begin
		reset <= 1;
		ena <= 1;
		wavedrom_start("Reset and count to 10");
		reset_test();
		repeat(12) @(posedge clk);
		wavedrom_stop();
		ena <= 1'b1;
		reset <= 1'b1;
		@(posedge clk);
		@(posedge clk)
			if (!tb_match) begin
				$display("Hint: Clock seems to reset to %02x:%02x:%02x %s (Should be 12:00:00 AM).", hh_dut, mm_dut, ss_dut, pm_dut ? "PM": "AM");
				reset_fail <= 1'b1;
			end

		reset <= 1'b0;
		@(posedge clk);
		@(posedge clk);
		@(posedge clk);
		ena <= 1'b0;
		reset <= 1'b1;
		@(posedge clk);
		@(posedge clk)
			if (!tb_match && !reset_fail)
				$display("Hint: Reset has higher priority than enable and should occur even if not enabled.");

		repeat(400) @(posedge clk, negedge clk) begin
			reset <= !($random & 31);
			ena <= !($random & 3);
		end
		reset <= 1;
		@(posedge clk) begin
			{reset, ena} <= 2'b1;
		end

		repeat(55) @(posedge clk);
		wavedrom_start("Minute roll-over");
		repeat(10) @(posedge clk);
		wavedrom_stop();

		repeat(3530) @(posedge clk);
		wavedrom_start("Hour roll-over");
		repeat(10) @(posedge clk);
		wavedrom_stop();

		repeat(39590) @(posedge clk);
		wavedrom_start("PM roll-over");
		repeat(10) @(posedge clk);
		wavedrom_stop();

		repeat(132745) @(posedge clk);
		repeat(50) @(posedge clk, negedge clk) begin
			ena <= !($random & 7);
		end
		reset <= 1'b1;
		repeat(5) @(posedge clk);

		if (bcd_fail)
			$display("Hint: Non-BCD values detected. Are you sure you're using two-digit BCD representation for hh, mm, and ss?");

		#1 $finish;
	end

endmodule

module tb();

	typedef struct packed {
		int errors;
		int errortime;
		int errors_pm;
		int errortime_pm;
		int errors_hh;
		int errortime_hh;
		int errors_mm;
		int errortime_mm;
		int errors_ss;
		int errortime_ss;

		int clocks;
	} stats;

	stats stats1;

	wire[511:0] wavedrom_title;
	wire wavedrom_enable;
	int wavedrom_hide_after_time;

	reg clk=0;
	initial forever
		#5 clk = ~clk;

	logic reset;
	logic ena;
	logic pm_ref;
	logic pm_dut;
	logic [7:0] hh_ref;
	logic [7:0] hh_dut;
	logic [7:0] mm_ref;
	logic [7:0] mm_dut;
	logic [7:0] ss_ref;
	logic [7:0] ss_dut;

	initial begin
		$dumpfile("wave.vcd");
		$dumpvars(1, stim1.clk, tb_mismatch ,clk,reset,ena,pm_ref,pm_dut,hh_ref,hh_dut,mm_ref,mm_dut,ss_ref,ss_dut );
	end

	wire tb_match;		// Verification
	wire tb_mismatch = ~tb_match;

	stimulus_gen stim1 (
		.clk,
		.* ,
		.reset,
		.ena );
	reference_module good1 (
		.clk,
		.reset,
		.ena,
		.pm(pm_ref),
		.hh(hh_ref),
		.mm(mm_ref),
		.ss(ss_ref) );

	top_module top_module1 (
		.clk,
		.reset,
		.ena,
		.pm(pm_dut),
		.hh(hh_dut),
		.mm(mm_dut),
		.ss(ss_dut) );

	bit strobe = 0;
	task wait_for_end_of_timestep;
		repeat(5) begin
			strobe <= !strobe;  // Try to delay until the very end of the time step.
			@(strobe);
		end
	endtask

	final begin
		if (stats1.errors_pm) $display("Hint: Output '%s' has %0d mismatches. First mismatch occurred at time %0d.", "pm", stats1.errors_pm, stats1.errortime_pm);
		else $display("Hint: Output '%s' has no mismatches.", "pm");
		if (stats1.errors_hh) $display("Hint: Output '%s' has %0d mismatches. First mismatch occurred at time %0d.", "hh", stats1.errors_hh, stats1.errortime_hh);
		else $display("Hint: Output '%s' has no mismatches.", "hh");
		if (stats1.errors_mm) $display("Hint: Output '%s' has %0d mismatches. First mismatch occurred at time %0d.", "mm", stats1.errors_mm, stats1.errortime_mm);
		else $display("Hint: Output '%s' has no mismatches.", "mm");
		if (stats1.errors_ss) $display("Hint: Output '%s' has %0d mismatches. First mismatch occurred at time %0d.", "ss", stats1.errors_ss, stats1.errortime_ss);
		else $display("Hint: Output '%s' has no mismatches.", "ss");

		$display("Hint: Total mismatched samples is %1d out of %1d samples\n", stats1.errors, stats1.clocks);
		$display("Simulation finished at %0d ps", $time);
		$display("Mismatches: %1d in %1d samples", stats1.errors, stats1.clocks);
	end

	// Verification: XORs on the right makes any X in good_vector match anything, but X in dut_vector will only match X.
	assign tb_match = ( { pm_ref, hh_ref, mm_ref, ss_ref } === ( { pm_ref, hh_ref, mm_ref, ss_ref } ^ { pm_dut, hh_dut, mm_dut, ss_dut } ^ { pm_ref, hh_ref, mm_ref, ss_ref } ) );
	// Use explicit sensitivity list here. @(*) causes NetProc::nex_input() to be called when trying to compute
	// the sensitivity list of the @(strobe) process, which isn't implemented.
	always @(posedge clk, negedge clk) begin

		stats1.clocks++;
		if (!tb_match) begin
			if (stats1.errors == 0) stats1.errortime = $time;
			stats1.errors++;
		end
		if (pm_ref !== ( pm_ref ^ pm_dut ^ pm_ref ))
		begin if (stats1.errors_pm == 0) stats1.errortime_pm = $time;
			stats1.errors_pm = stats1.errors_pm+1'b1; end
		if (hh_ref !== ( hh_ref ^ hh_dut ^ hh_ref ))
		begin if (stats1.errors_hh == 0) stats1.errortime_hh = $time;
			stats1.errors_hh = stats1.errors_hh+1'b1; end
		if (mm_ref !== ( mm_ref ^ mm_dut ^ mm_ref ))
		begin if (stats1.errors_mm == 0) stats1.errortime_mm = $time;
			stats1.errors_mm = stats1.errors_mm+1'b1; end
		if (ss_ref !== ( ss_ref ^ ss_dut ^ ss_ref ))
		begin if (stats1.errors_ss == 0) stats1.errortime_ss = $time;
			stats1.errors_ss = stats1.errors_ss+1'b1; end

	end
endmodule


The game Lemmings involves critters with fairly simple brains. So simple that we are going to model it using a finite state machine. In the Lemmings' 2D world, Lemmings can be in one of two states: walking left (walk_left is 1) or walking right (walk_right is 1). It will switch directions if it hits an obstacle. In particular, if a Lemming is bumped on the left (by receiving a 1 on bump_left), it will walk right. If it's bumped on the right (by receiving a 1 on bump_right), it will walk left. If it's bumped on both sides at the same time, it will still switch directions.
// In addition to walking left and right and changing direction when bumped, when ground=0, the Lemming will fall and say "aaah!". When the ground reappears (ground=1), the Lemming will resume walking in the same direction as before the fall. Being bumped while falling does not affect the walking direction, and being bumped in the same cycle as ground disappears (but not yet falling), or when the ground reappears while still falling, also does not affect the walking direction.
// Implement a Moore state machine that models this behaviour. areset is positive edge triggered asynchronous reseting the Lemming machine to walk left.

module top_module (
	input clk,
	input areset,
	input bump_left,
	input bump_right,
	input ground,
	output walk_left,
	output walk_right,
	output aaah
);
	parameter WL=0, WR=1, FALLL=2, FALLR=3;
	reg [1:0] state;
	reg [1:0] next;

    always_comb begin
		case (state)
			WL: next = ground ? (bump_left ? WR : WL) : FALLL;
			WR: next = ground ? (bump_right ? WL: WR) : FALLR;
			FALLL: next = ground ? WL : FALLL;
			FALLR: next = ground ? WR : FALLR;
		endcase
    end

    always @(posedge clk, posedge areset) begin
		if (areset) state <= WL;
        else state <= next;
	end

	assign walk_left = (state==WL);
	assign walk_right = (state==WR);
	assign aaah = (state == FALLL) || (state == FALLR);

endmodule

`timescale 1 ps/1 ps
`define OK 12
`define INCORRECT 13
module reference_module (
	input clk,
	input areset,
	input bump_left,
	input bump_right,
	input ground,
	output walk_left,
	output walk_right,
	output aaah
);
	parameter WL=0, WR=1, FALLL=2, FALLR=3;
	reg [1:0] state;
	reg [1:0] next;

    always_comb begin
		case (state)
			WL: next = ground ? (bump_left ? WR : WL) : FALLL;
			WR: next = ground ? (bump_right ? WL: WR) : FALLR;
			FALLL: next = ground ? WL : FALLL;
			FALLR: next = ground ? WR : FALLR;
		endcase
    end

    always @(posedge clk, posedge areset) begin
		if (areset) state <= WL;
        else state <= next;
	end

	assign walk_left = (state==WL);
	assign walk_right = (state==WR);
	assign aaah = (state == FALLL) || (state == FALLR);

endmodule

module stimulus_gen (
	input clk,
	output logic areset,
	output logic bump_left,
	output logic bump_right,
	output logic ground,
	output reg[511:0] wavedrom_title,
	output reg wavedrom_enable,
	input tb_match
);
	reg reset;
	assign areset = reset;

	task reset_test(input async=0);
		bit arfail, srfail, datafail;

		@(posedge clk);
		@(posedge clk) reset <= 0;
		repeat(3) @(posedge clk);

		@(negedge clk) begin datafail = !tb_match ; reset <= 1; end
		@(posedge clk) arfail = !tb_match;
		@(posedge clk) begin
			srfail = !tb_match;
			reset <= 0;
		end
		if (srfail)
			$display("Hint: Your reset doesn't seem to be working.");
		else if (arfail && (async || !datafail))
			$display("Hint: Your reset should be %0s, but doesn't appear to be.", async ? "asynchronous" : "synchronous");
		// Don't warn about synchronous reset if the half-cycle before is already wrong. It's more likely
		// a functionality error than the reset being implemented asynchronously.

	endtask

// Add two ports to module stimulus_gen:
//    output [511:0] wavedrom_title
//    output reg wavedrom_enable

	task wavedrom_start(input[511:0] title = "");
	endtask

	task wavedrom_stop;
		#1;
	endtask

	initial begin
		reset <= 1'b1;
		{bump_left, bump_right, ground} <= 3'h1;
		reset_test(1);
		{bump_right, bump_left} <= 3'h0;
		wavedrom_start("Falling");
		repeat(3) @(posedge clk);
		{bump_right, bump_left, ground} <= 0;
		repeat(3) @(posedge clk);
		{bump_right, bump_left, ground} <= 3;
		repeat(2) @(posedge clk);
		{bump_right, bump_left, ground} <= 0;
		repeat(3) @(posedge clk);
		{bump_right, bump_left, ground} <= 1;
		repeat(2) @(posedge clk);
		wavedrom_stop();

		reset <= 1'b1;
		@(posedge clk);
		repeat(400) @(posedge clk, negedge clk) begin
			{bump_right, bump_left} <= $random & $random;
			ground <= |($random & 7);
			reset <= !($random & 31);
		end

		#1 $finish;
	end

endmodule

module tb();

	typedef struct packed {
		int errors;
		int errortime;
		int errors_walk_left;
		int errortime_walk_left;
		int errors_walk_right;
		int errortime_walk_right;
		int errors_aaah;
		int errortime_aaah;

		int clocks;
	} stats;

	stats stats1;

	wire[511:0] wavedrom_title;
	wire wavedrom_enable;
	int wavedrom_hide_after_time;

	reg clk=0;
	initial forever
		#5 clk = ~clk;

	logic areset;
	logic bump_left;
	logic bump_right;
	logic ground;
	logic walk_left_ref;
	logic walk_left_dut;
	logic walk_right_ref;
	logic walk_right_dut;
	logic aaah_ref;
	logic aaah_dut;

	initial begin
		$dumpfile("wave.vcd");
		$dumpvars(1, stim1.clk, tb_mismatch ,clk,areset,bump_left,bump_right,ground,walk_left_ref,walk_left_dut,walk_right_ref,walk_right_dut,aaah_ref,aaah_dut );
	end

	wire tb_match;		// Verification
	wire tb_mismatch = ~tb_match;

	stimulus_gen stim1 (
		.clk,
		.* ,
		.areset,
		.bump_left,
		.bump_right,
		.ground );
	reference_module good1 (
		.clk,
		.areset,
		.bump_left,
		.bump_right,
		.ground,
		.walk_left(walk_left_ref),
		.walk_right(walk_right_ref),
		.aaah(aaah_ref) );

	top_module top_module1 (
		.clk,
		.areset,
		.bump_left,
		.bump_right,
		.ground,
		.walk_left(walk_left_dut),
		.walk_right(walk_right_dut),
		.aaah(aaah_dut) );

	bit strobe = 0;
	task wait_for_end_of_timestep;
		repeat(5) begin
			strobe <= !strobe;  // Try to delay until the very end of the time step.
			@(strobe);
		end
	endtask

	final begin
		if (stats1.errors_walk_left) $display("Hint: Output '%s' has %0d mismatches. First mismatch occurred at time %0d.", "walk_left", stats1.errors_walk_left, stats1.errortime_walk_left);
		else $display("Hint: Output '%s' has no mismatches.", "walk_left");
		if (stats1.errors_walk_right) $display("Hint: Output '%s' has %0d mismatches. First mismatch occurred at time %0d.", "walk_right", stats1.errors_walk_right, stats1.errortime_walk_right);
		else $display("Hint: Output '%s' has no mismatches.", "walk_right");
		if (stats1.errors_aaah) $display("Hint: Output '%s' has %0d mismatches. First mismatch occurred at time %0d.", "aaah", stats1.errors_aaah, stats1.errortime_aaah);
		else $display("Hint: Output '%s' has no mismatches.", "aaah");

		$display("Hint: Total mismatched samples is %1d out of %1d samples\n", stats1.errors, stats1.clocks);
		$display("Simulation finished at %0d ps", $time);
		$display("Mismatches: %1d in %1d samples", stats1.errors, stats1.clocks);
	end

	// Verification: XORs on the right makes any X in good_vector match anything, but X in dut_vector will only match X.
	assign tb_match = ( { walk_left_ref, walk_right_ref, aaah_ref } === ( { walk_left_ref, walk_right_ref, aaah_ref } ^ { walk_left_dut, walk_right_dut, aaah_dut } ^ { walk_left_ref, walk_right_ref, aaah_ref } ) );
	// Use explicit sensitivity list here. @(*) causes NetProc::nex_input() to be called when trying to compute
	// the sensitivity list of the @(strobe) process, which isn't implemented.
	always @(posedge clk, negedge clk) begin

		stats1.clocks++;
		if (!tb_match) begin
			if (stats1.errors == 0) stats1.errortime = $time;
			stats1.errors++;
		end
		if (walk_left_ref !== ( walk_left_ref ^ walk_left_dut ^ walk_left_ref ))
		begin if (stats1.errors_walk_left == 0) stats1.errortime_walk_left = $time;
			stats1.errors_walk_left = stats1.errors_walk_left+1'b1; end
		if (walk_right_ref !== ( walk_right_ref ^ walk_right_dut ^ walk_right_ref ))
		begin if (stats1.errors_walk_right == 0) stats1.errortime_walk_right = $time;
			stats1.errors_walk_right = stats1.errors_walk_right+1'b1; end
		if (aaah_ref !== ( aaah_ref ^ aaah_dut ^ aaah_ref ))
		begin if (stats1.errors_aaah == 0) stats1.errortime_aaah = $time;
			stats1.errors_aaah = stats1.errors_aaah+1'b1; end

	end
endmodule


Build a 4-digit BCD (binary-coded decimal) counter. Each decimal digit is encoded using 4 bits: q[3:0] is the ones digit, q[7:4] is the tens digit, etc. For digits [3:1], also output an enable signal indicating when each of the upper three digits should be incremented. Include a synchronous active-high reset.

module top_module(
	input clk,
	input reset,
	output [3:1] ena,
	output reg [15:0] q);

	wire [3:0] enable = { q[11:0]==12'h999, q[7:0]==8'h99, q[3:0] == 4'h9, 1'b1};
	assign ena = enable[3:1];
	always @(posedge clk)
		for (int i=0;i<4;i++) begin
			if (reset || (q[i*4 +:4] == 9 && enable[i]))
				q[i*4 +:4] <= 0;
			else if (enable[i])
				q[i*4 +:4] <= q[i*4 +:4]+1;
		end

endmodule

`timescale 1 ps/1 ps
`define OK 12
`define INCORRECT 13
module reference_module(
	input clk,
	input reset,
	output [3:1] ena,
	output reg [15:0] q);

	wire [3:0] enable = { q[11:0]==12'h999, q[7:0]==8'h99, q[3:0] == 4'h9, 1'b1};
	assign ena = enable[3:1];
	always @(posedge clk)
		for (int i=0;i<4;i++) begin
			if (reset || (q[i*4 +:4] == 9 && enable[i]))
				q[i*4 +:4] <= 0;
			else if (enable[i])
				q[i*4 +:4] <= q[i*4 +:4]+1;
		end

endmodule

module stimulus_gen (
	input clk,
	output reg reset,
	output reg[511:0] wavedrom_title,
	output reg wavedrom_enable,
	input tb_match
);

	task reset_test(input async=0);
		bit arfail, srfail, datafail;

		@(posedge clk);
		@(posedge clk) reset <= 0;
		repeat(3) @(posedge clk);

		@(negedge clk) begin datafail = !tb_match ; reset <= 1; end
		@(posedge clk) arfail = !tb_match;
		@(posedge clk) begin
			srfail = !tb_match;
			reset <= 0;
		end
		if (srfail)
			$display("Hint: Your reset doesn't seem to be working.");
		else if (arfail && (async || !datafail))
			$display("Hint: Your reset should be %0s, but doesn't appear to be.", async ? "asynchronous" : "synchronous");
		// Don't warn about synchronous reset if the half-cycle before is already wrong. It's more likely
		// a functionality error than the reset being implemented asynchronously.

	endtask

// Add two ports to module stimulus_gen:
//    output [511:0] wavedrom_title
//    output reg wavedrom_enable

	task wavedrom_start(input[511:0] title = "");
	endtask

	task wavedrom_stop;
		#1;
	endtask

	initial begin
		reset <= 1;
		reset_test();
		repeat(2) @(posedge clk);
		@(negedge clk);
		wavedrom_start("Counting");
			repeat(12) @(posedge clk);
		@(negedge clk);
		wavedrom_stop();
		repeat(71) @(posedge clk);
		@(negedge clk) wavedrom_start("100 rollover");
			repeat(16) @(posedge clk);
		@(negedge clk) wavedrom_stop();
		repeat(400) @(posedge clk, negedge clk)
			reset <= !($random & 31);
		repeat(19590) @(posedge clk);
		reset <= 1'b1;
		repeat(5) @(posedge clk);
		#1 $finish;
	end

endmodule

module tb();

	typedef struct packed {
		int errors;
		int errortime;
		int errors_ena;
		int errortime_ena;
		int errors_q;
		int errortime_q;

		int clocks;
	} stats;

	stats stats1;

	wire[511:0] wavedrom_title;
	wire wavedrom_enable;
	int wavedrom_hide_after_time;

	reg clk=0;
	initial forever
		#5 clk = ~clk;

	logic reset;
	logic [3:1] ena_ref;
	logic [3:1] ena_dut;
	logic [15:0] q_ref;
	logic [15:0] q_dut;

	initial begin
		$dumpfile("wave.vcd");
		$dumpvars(1, stim1.clk, tb_mismatch ,clk,reset,ena_ref,ena_dut,q_ref,q_dut );
	end

	wire tb_match;		// Verification
	wire tb_mismatch = ~tb_match;

	stimulus_gen stim1 (
		.clk,
		.* ,
		.reset );
	reference_module good1 (
		.clk,
		.reset,
		.ena(ena_ref),
		.q(q_ref) );

	top_module top_module1 (
		.clk,
		.reset,
		.ena(ena_dut),
		.q(q_dut) );

	bit strobe = 0;
	task wait_for_end_of_timestep;
		repeat(5) begin
			strobe <= !strobe;  // Try to delay until the very end of the time step.
			@(strobe);
		end
	endtask

	final begin
		if (stats1.errors_ena) $display("Hint: Output '%s' has %0d mismatches. First mismatch occurred at time %0d.", "ena", stats1.errors_ena, stats1.errortime_ena);
		else $display("Hint: Output '%s' has no mismatches.", "ena");
		if (stats1.errors_q) $display("Hint: Output '%s' has %0d mismatches. First mismatch occurred at time %0d.", "q", stats1.errors_q, stats1.errortime_q);
		else $display("Hint: Output '%s' has no mismatches.", "q");

		$display("Hint: Total mismatched samples is %1d out of %1d samples\n", stats1.errors, stats1.clocks);
		$display("Simulation finished at %0d ps", $time);
		$display("Mismatches: %1d in %1d samples", stats1.errors, stats1.clocks);
	end

	// Verification: XORs on the right makes any X in good_vector match anything, but X in dut_vector will only match X.
	assign tb_match = ( { ena_ref, q_ref } === ( { ena_ref, q_ref } ^ { ena_dut, q_dut } ^ { ena_ref, q_ref } ) );
	// Use explicit sensitivity list here. @(*) causes NetProc::nex_input() to be called when trying to compute
	// the sensitivity list of the @(strobe) process, which isn't implemented.
	always @(posedge clk, negedge clk) begin

		stats1.clocks++;
		if (!tb_match) begin
			if (stats1.errors == 0) stats1.errortime = $time;
			stats1.errors++;
		end
		if (ena_ref !== ( ena_ref ^ ena_dut ^ ena_ref ))
		begin if (stats1.errors_ena == 0) stats1.errortime_ena = $time;
			stats1.errors_ena = stats1.errors_ena+1'b1; end
		if (q_ref !== ( q_ref ^ q_dut ^ q_ref ))
		begin if (stats1.errors_q == 0) stats1.errortime_q = $time;
			stats1.errors_q = stats1.errors_q+1'b1; end

	end
endmodule