summaryrefslogtreecommitdiff
path: root/rtl/pkt_switch/pkt_switch.v
blob: c146b5e124729bee4acfeb3b19a269d843b93a8c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
//Simple pkt switch, functionality:
// - 1 data input interface, 2 data output interfaces
// - data width is 8 bits, with "valid" bit
// - packet is tranmitted continuously (valid = 1, cannot fall in the middle)
// - when valid = 0 that means a gap between packets, packet always starts when valid 0->1
// - first byte of the packet is address, second is packet length (in bytes), following by the data
// - non-filtered packets are transmitted on interface 0, filtered on 1
// - if filtering is not enabled, packets are simply forwarded on interface 0
// - 1 control interface (write only)
// - registers:
// - ADDR:         FUNCTIONALITY:
// - 000           settings:
//                            bit 0 - enable address-based filtering
//                            bit 1 - enable length-based filtering 
//                            bit 2 - transmit packet on both interfaces
// - 010           address for address-based filtering  
// - 011           address based filtering mask (which bits of the address are valid)
// - 100           lower size limit for length based filtering
// - 101           uppoer size limit for length based filtering

module pkt_switch (
  clk, 
  rst_n, 
  datain_data, 
  datain_valid, 
  dataout0_data, 
  dataout1_data, 
  dataout0_valid, 
  dataout1_valid,
  ctrl_addr,
  ctrl_data,
  ctrl_wr
);

  input clk, rst_n;
  //data interfaces
  input [7:0] datain_data;
  input datain_valid;
  output reg [7:0] dataout0_data, dataout1_data;
  output reg dataout0_valid, dataout1_valid;
  //control interface
  input [2:0] ctrl_addr;
  input [7:0] ctrl_data;
  input ctrl_wr; 

  //config registers
  reg addr_filtering_ena_r;
  reg len_filtering_ena_r;  
  reg transmit_both_ena_r; 

  reg [7:0] filter_addr_r;
  reg [7:0] filter_addr_mask_r;
  reg [7:0] lower_size_limit_r;
  reg [7:0] upper_size_limit_r;

  reg [7:0] data_0_r, data_1_r;
  reg datain_valid_0_r, datain_valid_1_r;
  reg [7:0] pkt_addr_r, pkt_len_r;

  wire addr_filtering_active, channel0_active, channel1_active, len_filtering_active;

  always @(posedge clk or negedge rst_n)  
  begin : config_proc
    if(~rst_n) begin
      addr_filtering_ena_r <= 1'b0;
      len_filtering_ena_r <= 1'b0;
      transmit_both_ena_r <= 1'b0;
      filter_addr_r <= 8'd0;
      filter_addr_mask_r <= 8'd0;
      lower_size_limit_r <= 8'd0;
      upper_size_limit_r <= 8'd0;
    end else if (ctrl_wr) begin
      case (ctrl_addr)
        3'b000: begin
          addr_filtering_ena_r <= ctrl_data[0];
          len_filtering_ena_r <= ctrl_data[1];
          transmit_both_ena_r <= ctrl_data[2];
        end
        3'b010: filter_addr_r <= ctrl_data;
        3'b011: filter_addr_mask_r <= ctrl_data;
        3'b100: lower_size_limit_r <= ctrl_data;
        3'b101: upper_size_limit_r <= ctrl_data;
        default: ;
      endcase
    end  
  end

  always @(posedge clk or negedge rst_n)  
  begin : data_proc
    if(~rst_n) begin
      data_0_r <= 8'd0;
      data_1_r <= 8'd0;
      dataout0_data <= 8'd0;
      dataout1_data <= 8'd0;
      datain_valid_0_r <= 1'b0;
      datain_valid_1_r <= 1'b0;
    end else begin
      data_0_r <= datain_data;
      data_1_r <= data_0_r;
      datain_valid_0_r <= datain_valid;
      datain_valid_1_r <= datain_valid_0_r;
      dataout0_data <= (channel0_active) ? data_1_r : 8'd0;
      dataout0_valid <= (channel0_active) ? datain_valid_1_r : 1'b0;
      dataout1_data <= (channel1_active) ? data_1_r : 8'd0;
      dataout1_valid <= (channel1_active) ? datain_valid_1_r : 1'b0;
    end
  end

  always @(posedge clk or negedge rst_n)  
  begin : header_proc
    if(~rst_n) begin
      pkt_addr_r <= 8'd0;
      pkt_len_r <= 8'd0;
    end else begin
      if (datain_valid && !datain_valid_0_r) //first packet byte
        pkt_addr_r <= datain_data;
      if (datain_valid_0_r && !datain_valid_1_r) //second packet byte
        pkt_len_r <= datain_data;
    end
  end

  assign addr_filtering_active = 
    addr_filtering_ena_r &&        
    ((pkt_addr_r & filter_addr_mask_r) == (filter_addr_r & filter_addr_mask_r));
  assign len_filtering_active =
    len_filtering_ena_r &&
    ((pkt_len_r >= lower_size_limit_r) && (pkt_len_r <= upper_size_limit_r));

  assign channel0_active = 
    !addr_filtering_active && !len_filtering_active;
  assign channel1_active =
    transmit_both_ena_r || 
    addr_filtering_active || len_filtering_active;

endmodule