module tb_statemachine();
	logic err, slow_clock, resetb, load_pcard1, load_pcard2, load_pcard3,
		load_dcard1, load_dcard2, load_dcard3,
		player_win_light, dealer_win_light;
	logic [3:0] dscore, pscore, pcard3;

	statemachine DUT(slow_clock, resetb, dscore, pscore, pcard3,
		load_pcard1, load_pcard2, load_pcard3,
		load_dcard1, load_dcard2, load_dcard3,
		player_win_light, dealer_win_light);

	task check;
		input logic [7:0] expected;

		if (load_pcard1 !== expected[7]) begin
			err = 1;
			$display("FAILED: load_pcard1 is incorrect.",);
		end
		if (load_pcard2 !== expected[6]) begin
			err = 1;
			$display("FAILED: load_pcard2 is incorrect.",);
		end
		if (load_pcard3 !== expected[5]) begin
			err = 1;
			$display("FAILED: load_pcard3 is incorrect.",);
		end
		if (load_dcard1 !== expected[4]) begin
			err = 1;
			$display("FAILED: load_dcard1 is incorrect.",);
		end
		if (load_dcard2 !== expected[3]) begin
			err = 1;
			$display("FAILED: load_dcard2 is incorrect.",);
		end
		if (load_dcard3 !== expected[2]) begin
			err = 1;
			$display("FAILED: load_dcard3 is incorrect.",);
		end
		if (player_win_light !== expected[1]) begin
			err = 1;
			$display("FAILED: player_win_light is incorrect.",);
		end
		if (dealer_win_light !== expected[0]) begin
			err = 1;
			$display("FAILED: dealer_win_light is incorrect.",);
		end
	endtask: check

	initial forever begin
		slow_clock = 1'b0;
		#5;
		slow_clock = 1'b1;
		#5;
	end

	initial begin
		#10000;
		$stop;
	end

	initial begin
		err = 0;
		pcard3 = 4'b0;

		/* Natural 9 vs natural 8: deal four cards, player win. */

		$display("Test 1");

		resetb = 1'b0;
		pscore = 4'd9;
		dscore = 4'd8;

		#10;

		resetb = 1'b1;

		check(8'b10000000); #10;
		check(8'b00010000); #10;
		check(8'b01000000); #10;
		check(8'b00001000); #10;
		check(8'b00000000); #10;
		check(8'b00000010); #10;

		/* Natural 8 vs natural 9: deal four cards, dealer win. */

		$display("Test 2");

		resetb = 1'b0;
		pscore = 4'd8;
		dscore = 4'd9;

		#10;

		resetb = 1'b1;

		check(8'b10000000); #10;
		check(8'b00010000); #10;
		check(8'b01000000); #10;
		check(8'b00001000); #10;
		check(8'b00000000); #10;
		check(8'b00000001); #10;

		/* 7 vs 6: deal four cards, player win. */

		$display("Test 3");

		resetb = 1'b0;
		pscore = 4'd7;
		dscore = 4'd6;

		#10;

		resetb = 1'b1;

		check(8'b10000000); #10;
		check(8'b00010000); #10;
		check(8'b01000000); #10;
		check(8'b00001000); #10;
		check(8'b00000000); #10;
		check(8'b00000010); #10;

		/* 7 vs 5: player stands, dealer hits, dealer win. */

		$display("Test 4");

		resetb = 1'b0;
		pscore = 4'd7;
		dscore = 4'd5;

		#10;

		resetb = 1'b1;

		check(8'b10000000); #10;
		check(8'b00010000); #10;
		check(8'b01000000); #10;
		check(8'b00001000); #10;

		/* Dealer 3rd card is a 3. */
		check(8'b00000100);
		dscore = 4'd8;
		#10;

		check(8'b00000001); #10;

		/* 3 vs 4: player hits and gets 7, dealer hits, dealer win. */

		$display("Test 5");

		resetb = 1'b0;
		pscore = 4'd3;
		dscore = 4'd4;

		#10;

		resetb = 1'b1;

		check(8'b10000000); #10;
		check(8'b00010000); #10;
		check(8'b01000000); #10;
		check(8'b00001000); #10;

		/* Player draws a 7. */
		pcard3 = 4'd7;
		pscore = 4'b0;
		check(8'b00100000);
		#10;

		/* Dealer 3rd card is a 3. */
		check(8'b00000100);
		dscore = 4'd8;
		#10;

		check(8'b00000001); #10;

		/* 0 vs 3: player hits and gets 8, dealer stands, player win. */

		$display("Test 6");

		resetb = 1'b0;
		pscore = 4'd0;
		dscore = 4'd3;

		#10;

		resetb = 1'b1;

		check(8'b10000000); #10;
		check(8'b00010000); #10;
		check(8'b01000000); #10;
		check(8'b00001000); #10;

		/* Player draws a 8. */
		pcard3 = 4'd8;
		pscore = 4'd8;
		check(8'b00100000);
		#10;

		check(8'b00000010); #10;

		/* 5 vs 0: player hits and gets 9, dealer hits, tie. */

		$display("Test 7");

		resetb = 1'b0;
		pscore = 4'd5;
		dscore = 4'd0;

		#10;

		resetb = 1'b1;

		check(8'b10000000); #10;
		check(8'b00010000); #10;
		check(8'b01000000); #10;
		check(8'b00001000); #10;

		/* Player draws a 9. */
		pcard3 = 4'd9;
		pscore = 4'd4;
		check(8'b00100000);
		#10;

		/* Dealer 3rd card is a 4. */
		check(8'b00000100);
		dscore = 4'd4;
		#10;

		check(8'b00000011); #10;

		/* 5 vs 0: player hits and gets 9, dealer hits, dealer win. */

		$display("Test 8");

		resetb = 1'b0;
		pscore = 4'd5;
		dscore = 4'd0;

		#10;

		resetb = 1'b1;

		check(8'b10000000); #10;
		check(8'b00010000); #10;
		check(8'b01000000); #10;
		check(8'b00001000); #10;

		/* Player draws a 9. */
		pcard3 = 4'd9;
		pscore = 4'd4;
		check(8'b00100000);
		#10;

		/* Dealer 3rd card is a 5. */
		check(8'b00000100);
		dscore = 4'd5;
		#10;

		check(8'b00000001); #10;

		if (~err)
			$display("All tests passed.");

		#10;
		$stop;
	end
endmodule: tb_statemachine
