`timescale 1ns / 1ps

module tb_packet_filter;

    // Inputs
    reg [31:0] src_ip;
    reg [15:0] dst_port;
    reg [7:0]  protocol;
    
    // Outputs
    wire allow;
    
    // Instantiate DUT
    packet_filter uut (
        .src_ip(src_ip),
        .dst_port(dst_port),
        .protocol(protocol),
        .allow(allow)
    );
    
    // Golden Vectors
    localparam NUM_TESTS = 33;
    reg [31:0] tb_src_ip [0:32];
    reg [15:0] tb_dst_port [0:32];
    reg [7:0]  tb_protocol [0:32];
    reg        exp_allow [0:32];
    
    integer i;
    integer errors = 0;
    
    initial begin
        // Test 0: Rule 1 Block 10.x with ICMP
        tb_src_ip[0]   = 32'h0a000001;     tb_dst_port[0] = 16'd0;     tb_protocol[0] = 8'd1;     exp_allow[0]   = 1'b0;

        // Test 1: Rule 1 Block 10.x with HTTP
        tb_src_ip[1]   = 32'h0a010203;     tb_dst_port[1] = 16'd80;     tb_protocol[1] = 8'd6;     exp_allow[1]   = 1'b0;

        // Test 2: Rule 2 Block 192.168.x with DNS
        tb_src_ip[2]   = 32'hc0a80101;     tb_dst_port[2] = 16'd53;     tb_protocol[2] = 8'd17;     exp_allow[2]   = 1'b0;

        // Test 3: Rule 3 Allow ICMP public
        tb_src_ip[3]   = 32'h08080808;     tb_dst_port[3] = 16'd0;     tb_protocol[3] = 8'd1;     exp_allow[3]   = 1'b1;

        // Test 4: Rule 4 Allow HTTP
        tb_src_ip[4]   = 32'h01020304;     tb_dst_port[4] = 16'd80;     tb_protocol[4] = 8'd6;     exp_allow[4]   = 1'b1;

        // Test 5: Rule 5 Allow HTTPS
        tb_src_ip[5]   = 32'h01020304;     tb_dst_port[5] = 16'd443;     tb_protocol[5] = 8'd6;     exp_allow[5]   = 1'b1;

        // Test 6: Rule 6 Allow SSH
        tb_src_ip[6]   = 32'h01020304;     tb_dst_port[6] = 16'd22;     tb_protocol[6] = 8'd6;     exp_allow[6]   = 1'b1;

        // Test 7: Rule 7 Allow DNS
        tb_src_ip[7]   = 32'h01020304;     tb_dst_port[7] = 16'd53;     tb_protocol[7] = 8'd17;     exp_allow[7]   = 1'b1;

        // Test 8: Rule 8 Default Drop TCP
        tb_src_ip[8]   = 32'h01020304;     tb_dst_port[8] = 16'd12345;     tb_protocol[8] = 8'd6;     exp_allow[8]   = 1'b0;

        // Test 9: Rule 8 Default Drop UDP
        tb_src_ip[9]   = 32'h01020304;     tb_dst_port[9] = 16'd12345;     tb_protocol[9] = 8'd17;     exp_allow[9]   = 1'b0;

        // Test 10: Rule 8 Default Drop Proto
        tb_src_ip[10]   = 32'h01020304;     tb_dst_port[10] = 16'd80;     tb_protocol[10] = 8'd99;     exp_allow[10]   = 1'b0;

        // Test 11: Boundary 10.255.255.255
        tb_src_ip[11]   = 32'h0affffff;     tb_dst_port[11] = 16'd80;     tb_protocol[11] = 8'd6;     exp_allow[11]   = 1'b0;

        // Test 12: Boundary 11.0.0.0
        tb_src_ip[12]   = 32'h0b000000;     tb_dst_port[12] = 16'd80;     tb_protocol[12] = 8'd6;     exp_allow[12]   = 1'b1;

        // Test 13: Random 0
        tb_src_ip[13]   = 32'ha3b1799d;     tb_dst_port[13] = 16'd443;     tb_protocol[13] = 8'd1;     exp_allow[13]   = 1'b1;

        // Test 14: Random 1
        tb_src_ip[14]   = 32'h392456de;     tb_dst_port[14] = 16'd0;     tb_protocol[14] = 8'd1;     exp_allow[14]   = 1'b1;

        // Test 15: Random 2
        tb_src_ip[15]   = 32'h6c031199;     tb_dst_port[15] = 16'd443;     tb_protocol[15] = 8'd1;     exp_allow[15]   = 1'b1;

        // Test 16: Random 3
        tb_src_ip[16]   = 32'h9a1de644;     tb_dst_port[16] = 16'd65535;     tb_protocol[16] = 8'd255;     exp_allow[16]   = 1'b0;

        // Test 17: Random 4
        tb_src_ip[17]   = 32'h8b8148f6;     tb_dst_port[17] = 16'd0;     tb_protocol[17] = 8'd6;     exp_allow[17]   = 1'b0;

        // Test 18: Random 5
        tb_src_ip[18]   = 32'hde8a774b;     tb_dst_port[18] = 16'd22;     tb_protocol[18] = 8'd6;     exp_allow[18]   = 1'b1;

        // Test 19: Random 6
        tb_src_ip[19]   = 32'h47229389;     tb_dst_port[19] = 16'd80;     tb_protocol[19] = 8'd6;     exp_allow[19]   = 1'b1;

        // Test 20: Random 7
        tb_src_ip[20]   = 32'h17be3111;     tb_dst_port[20] = 16'd47052;     tb_protocol[20] = 8'd1;     exp_allow[20]   = 1'b1;

        // Test 21: Random 8
        tb_src_ip[21]   = 32'hec1b8ca1;     tb_dst_port[21] = 16'd38427;     tb_protocol[21] = 8'd1;     exp_allow[21]   = 1'b1;

        // Test 22: Random 9
        tb_src_ip[22]   = 32'h11ce5dd2;     tb_dst_port[22] = 16'd80;     tb_protocol[22] = 8'd6;     exp_allow[22]   = 1'b1;

        // Test 23: Random 10
        tb_src_ip[23]   = 32'hdaf61a26;     tb_dst_port[23] = 16'd22;     tb_protocol[23] = 8'd1;     exp_allow[23]   = 1'b1;

        // Test 24: Random 11
        tb_src_ip[24]   = 32'hd58842de;     tb_dst_port[24] = 16'd22;     tb_protocol[24] = 8'd6;     exp_allow[24]   = 1'b1;

        // Test 25: Random 12
        tb_src_ip[25]   = 32'ha5e5a5ab;     tb_dst_port[25] = 16'd0;     tb_protocol[25] = 8'd255;     exp_allow[25]   = 1'b0;

        // Test 26: Random 13
        tb_src_ip[26]   = 32'hbaa80dd4;     tb_dst_port[26] = 16'd53;     tb_protocol[26] = 8'd6;     exp_allow[26]   = 1'b0;

        // Test 27: Random 14
        tb_src_ip[27]   = 32'h0e51f30d;     tb_dst_port[27] = 16'd53;     tb_protocol[27] = 8'd1;     exp_allow[27]   = 1'b1;

        // Test 28: Random 15
        tb_src_ip[28]   = 32'h448aaa9e;     tb_dst_port[28] = 16'd443;     tb_protocol[28] = 8'd6;     exp_allow[28]   = 1'b1;

        // Test 29: Random 16
        tb_src_ip[29]   = 32'ha7cad415;     tb_dst_port[29] = 16'd443;     tb_protocol[29] = 8'd0;     exp_allow[29]   = 1'b0;

        // Test 30: Random 17
        tb_src_ip[30]   = 32'h43cf2fde;     tb_dst_port[30] = 16'd65535;     tb_protocol[30] = 8'd6;     exp_allow[30]   = 1'b0;

        // Test 31: Random 18
        tb_src_ip[31]   = 32'h95a76d79;     tb_dst_port[31] = 16'd22;     tb_protocol[31] = 8'd255;     exp_allow[31]   = 1'b0;

        // Test 32: Random 19
        tb_src_ip[32]   = 32'hff5e9ff0;     tb_dst_port[32] = 16'd80;     tb_protocol[32] = 8'd255;     exp_allow[32]   = 1'b0;

        // Wait for inputs to settle
        #100;
        
        // Run tests
        for (i = 0; i < NUM_TESTS; i = i + 1) begin
            src_ip   = tb_src_ip[i];
            dst_port = tb_dst_port[i];
            protocol = tb_protocol[i];
            
            #10;
            
            if (allow !== exp_allow[i]) begin
                $display("ERROR [Test %0d]: IP=%h, Proto=%d, Port=%d :: Expected=%b, Got=%b", 
                         i, src_ip, protocol, dst_port, exp_allow[i], allow);
                errors = errors + 1;
            end
        end
        
        // Final Results
        $display("");
        $display("===========================================");
        $display("  Tests Run: %0d", NUM_TESTS);
        $display("===========================================");
        
        if (errors == 0) begin
            $display("TEST_RESULT: PASS");
        end else begin
            $display("TEST_RESULT: FAIL (%0d errors)", errors);
        end
        
        $finish;
    end

endmodule
