`define ACE	7'b0001000
`define TWO	7'b0100100
`define THREE	7'b0110000
`define FOUR	7'b0011001
`define FIVE	7'b0010010
`define SIX	7'b0000010
`define SEVEN	7'b1111000
`define EIGHT	7'b0000000
`define NINE	7'b0010000
`define TEN	7'b1000000
`define JACK	7'b1100001
`define QUEEN	7'b0011000
`define KING	7'b0001001
`define BLANK	7'b1111111

module tb_datapath();
	logic err, slow_clock, fast_clock, resetb,
		load_pcard1, load_pcard2, load_pcard3,
		load_dcard1, load_dcard2, load_dcard3;
	logic [3:0] pcard3_out, pscore_out, dscore_out;
	logic [6:0] HEX0, HEX1, HEX2, HEX3, HEX4, HEX5;

	datapath DUT(slow_clock, fast_clock, resetb,
		load_pcard1, load_pcard2, load_pcard3,
		load_dcard1, load_dcard2, load_dcard3,
		pcard3_out, pscore_out, dscore_out,
		HEX5, HEX4, HEX3, HEX2, HEX1, HEX0);

	task check;
		input logic [3:0] expected_pscore, expected_dscore;
		input logic [6:0] expected_HEX0, expected_HEX1, expected_HEX2,
			expected_HEX3, expected_HEX4, expected_HEX5;

		if (pscore_out !== expected_pscore) begin
			err = 1;
			$display("FAILED: pscore_out is incorrect.",);
		end
		if (dscore_out !== expected_dscore) begin
			err = 1;
			$display("FAILED: dscore_out is incorrect.",);
		end
		if (HEX0 !== expected_HEX0) begin
			err = 1;
			$display("FAILED: HEX0 is incorrect.",);
		end
		if (HEX1 !== expected_HEX1) begin
			err = 1;
			$display("FAILED: HEX1 is incorrect.",);
		end
		if (HEX2 !== expected_HEX2) begin
			err = 1;
			$display("FAILED: HEX2 is incorrect.",);
		end
		if (HEX3 !== expected_HEX3) begin
			err = 1;
			$display("FAILED: HEX3 is incorrect.",);
		end
		if (HEX4 !== expected_HEX4) begin
			err = 1;
			$display("FAILED: HEX4 is incorrect.",);
		end
		if (HEX5 !== expected_HEX5) begin
			err = 1;
			$display("FAILED: HEX5 is incorrect.",);
		end
	endtask: check

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

	initial begin
		err = 0;

		{resetb, load_pcard1, load_pcard2, load_pcard3,
			load_pcard1, load_pcard2, load_pcard3}
			= 7'b0;

		#10;

		resetb = 1'b1;

		/* Player: AK8, dealer: TJ9. */

		/* Load A. */

		$display("Test 1.1");

		force tb_datapath.DUT.new_card = 4'd1;
		load_pcard1 = 1'b1;

		#10;

		check(4'd1, 4'd0, `ACE, `BLANK, `BLANK, `BLANK, `BLANK, `BLANK);
		load_pcard1 = 1'b0;

		/* Load T. */

		$display("Test 1.2");

		force tb_datapath.DUT.new_card = 4'd10;
		load_dcard1 = 1'b1;

		#10;

		check(4'd1, 4'd0, `ACE, `BLANK, `BLANK, `TEN, `BLANK, `BLANK);
		load_dcard1 = 1'b0;

		/* Load K. */

		$display("Test 1.3");

		force tb_datapath.DUT.new_card = 4'd13;
		load_pcard2 = 1'b1;

		#10;

		check(4'd1, 4'd0, `ACE, `KING, `BLANK, `TEN, `BLANK, `BLANK);
		load_pcard2 = 1'b0;

		/* Load J. */

		$display("Test 1.4");

		force tb_datapath.DUT.new_card = 4'd11;
		load_dcard2 = 1'b1;

		#10;

		check(4'd1, 4'd0, `ACE, `KING, `BLANK, `TEN, `JACK, `BLANK);
		load_dcard2 = 1'b0;

		/* Load 8. */

		$display("Test 1.5");

		force tb_datapath.DUT.new_card = 4'd8;
		load_pcard3 = 1'b1;

		#10;

		check(4'd9, 4'd0, `ACE, `KING, `EIGHT, `TEN, `JACK, `BLANK);
		load_pcard3 = 1'b0;

		/* Load 9. */

		$display("Test 1.6");

		force tb_datapath.DUT.new_card = 4'd9;
		load_dcard3 = 1'b1;

		#10;

		check(4'd9, 4'd9, `ACE, `KING, `EIGHT, `TEN, `JACK, `NINE);
		load_dcard3 = 1'b0;

		/* Reset. */

		$display("Test 1.7");

		resetb = 1'b0;

		#10;

		check(4'd0, 4'd0, `BLANK, `BLANK, `BLANK, `BLANK, `BLANK, `BLANK);
		resetb = 1'b1;

		/* Player: 234, dealer: 567. */

		/* Load 2. */

		$display("Test 2.1");

		force tb_datapath.DUT.new_card = 4'd2;
		load_pcard1 = 1'b1;

		#10;

		check(4'd2, 4'd0, `TWO, `BLANK, `BLANK, `BLANK, `BLANK, `BLANK);
		load_pcard1 = 1'b0;

		/* Load 5. */

		$display("Test 2.2");

		force tb_datapath.DUT.new_card = 4'd5;
		load_dcard1 = 1'b1;

		#10;

		check(4'd2, 4'd5, `TWO, `BLANK, `BLANK, `FIVE, `BLANK, `BLANK);
		load_dcard1 = 1'b0;

		/* Load 3. */

		$display("Test 2.3");

		force tb_datapath.DUT.new_card = 4'd3;
		load_pcard2 = 1'b1;

		#10;

		check(4'd5, 4'd5, `TWO, `THREE, `BLANK, `FIVE, `BLANK, `BLANK);
		load_pcard2 = 1'b0;

		/* Load 6. */

		$display("Test 2.4");

		force tb_datapath.DUT.new_card = 4'd6;
		load_dcard2 = 1'b1;

		#10;

		check(4'd5, 4'd1, `TWO, `THREE, `BLANK, `FIVE, `SIX, `BLANK);
		load_dcard2 = 1'b0;

		/* Load 4. */

		$display("Test 2.5");

		force tb_datapath.DUT.new_card = 4'd4;
		load_pcard3 = 1'b1;

		#10;

		check(4'd9, 4'd1, `TWO, `THREE, `FOUR, `FIVE, `SIX, `BLANK);
		load_pcard3 = 1'b0;

		/* Load 7. */

		$display("Test 2.6");

		force tb_datapath.DUT.new_card = 4'd7;
		load_dcard3 = 1'b1;

		#10;

		check(4'd9, 4'd8, `TWO, `THREE, `FOUR, `FIVE, `SIX, `SEVEN);
		load_dcard3 = 1'b0;

		/* Reset. */

		$display("Test 2.7");

		resetb = 1'b0;

		#10;

		check(4'd0, 4'd0, `BLANK, `BLANK, `BLANK, `BLANK, `BLANK, `BLANK);
		resetb = 1'b1;

		/* Player: 89, dealer: JQK. */

		/* Load 8. */

		$display("Test 3.1");

		force tb_datapath.DUT.new_card = 4'd8;
		load_pcard1 = 1'b1;

		#10;

		check(4'd8, 4'd0, `EIGHT, `BLANK, `BLANK, `BLANK, `BLANK, `BLANK);
		load_pcard1 = 1'b0;

		/* Load J. */

		$display("Test 3.2");

		force tb_datapath.DUT.new_card = 4'd11;
		load_dcard1 = 1'b1;

		#10;

		check(4'd8, 4'd0, `EIGHT, `BLANK, `BLANK, `JACK, `BLANK, `BLANK);
		load_dcard1 = 1'b0;

		/* Load 9. */

		$display("Test 3.3");

		force tb_datapath.DUT.new_card = 4'd9;
		load_pcard2 = 1'b1;

		#10;

		check(4'd7, 4'd0, `EIGHT, `NINE, `BLANK, `JACK, `BLANK, `BLANK);
		load_pcard2 = 1'b0;

		#10;

		/* Load Q. */

		$display("Test 3.4");

		force tb_datapath.DUT.new_card = 4'd12;
		load_dcard2 = 1'b1;

		#10;

		check(4'd7, 4'd0, `EIGHT, `NINE, `BLANK, `JACK, `QUEEN, `BLANK);
		load_dcard2 = 1'b0;

		/* Load K. */

		$display("Test 3.5");

		force tb_datapath.DUT.new_card = 4'd13;
		load_dcard3 = 1'b1;

		#10;

		check(4'd7, 4'd0, `EIGHT, `NINE, `BLANK, `JACK, `QUEEN, `KING);
		load_dcard3 = 1'b0;

		/* Reset. */

		$display("Test 3.6");

		resetb = 1'b0;

		#10;

		check(4'd0, 4'd0, `BLANK, `BLANK, `BLANK, `BLANK, `BLANK, `BLANK);
		resetb = 1'b1;

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

		#10;
		$stop;
	end
endmodule: tb_datapath
