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 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294
|
//
// Copyright 2011 Ettus Research LLC
//
// Packet dispatcher with fifo36 interface and 3 outputs.
//
// The packet dispatcher expects 2-byte padded ethernet frames.
// The frames will be inspected at ethernet, IPv4, UDP, and VRT layers.
// Packets are dispatched into the following streams:
// * tx dsp stream
// * to cpu stream
// * to external stream
// * to both cpu and external
//
// The following registers are used for dispatcher control:
// * base + 0 = this ipv4 address (32 bits)
// * base + 1 = udp dst port (lower 16 bits)
//
module packet_dispatcher36_x3
#(
parameter BASE = 0
)
(
//clocking and reset interface:
input clk, input rst, input clr,
//setting register interface:
input set_stb, input [7:0] set_addr, input [31:0] set_data,
//input stream interfaces:
input [35:0] com_inp_data, input com_inp_valid, output com_inp_ready,
//output stream interfaces:
output [35:0] ext_out_data, output ext_out_valid, input ext_out_ready,
output [35:0] dsp_out_data, output dsp_out_valid, input dsp_out_ready,
output [35:0] cpu_out_data, output cpu_out_valid, input cpu_out_ready
);
//setting register to program the IP address
wire [31:0] my_ip_addr;
setting_reg #(.my_addr(BASE+0)) sreg_ip_addr(
.clk(clk),.rst(rst),
.strobe(set_stb),.addr(set_addr),.in(set_data),
.out(my_ip_addr),.changed()
);
//setting register to program the UDP DSP port
wire [15:0] dsp_udp_port;
setting_reg #(.my_addr(BASE+1), .width(16)) sreg_data_port(
.clk(clk),.rst(rst),
.strobe(set_stb),.addr(set_addr),.in(set_data),
.out(dsp_udp_port),.changed()
);
////////////////////////////////////////////////////////////////////
// Communication input inspector
// - inspect com input and send it to DSP, EXT, CPU, or BOTH
////////////////////////////////////////////////////////////////////
localparam PD_STATE_READ_COM_PRE = 0;
localparam PD_STATE_READ_COM = 1;
localparam PD_STATE_WRITE_REGS = 2;
localparam PD_STATE_WRITE_LIVE = 3;
localparam PD_DEST_DSP = 0;
localparam PD_DEST_EXT = 1;
localparam PD_DEST_CPU = 2;
localparam PD_DEST_BOF = 3;
localparam PD_MAX_NUM_DREGS = 13; //padded_eth + ip + udp + seq + vrt_hdr
localparam PD_DREGS_DSP_OFFSET = 11; //offset to start dsp at
//output inspector interfaces
wire [35:0] pd_out_dsp_data;
wire pd_out_dsp_valid;
wire pd_out_dsp_ready;
wire [35:0] pd_out_ext_data;
wire pd_out_ext_valid;
wire pd_out_ext_ready;
wire [35:0] pd_out_cpu_data;
wire pd_out_cpu_valid;
wire pd_out_cpu_ready;
wire [35:0] pd_out_bof_data;
wire pd_out_bof_valid;
wire pd_out_bof_ready;
reg [1:0] pd_state;
reg [1:0] pd_dest;
reg [3:0] pd_dreg_count; //data registers to buffer headers
wire [3:0] pd_dreg_count_next = pd_dreg_count + 1'b1;
wire pd_dreg_counter_done = (pd_dreg_count_next == PD_MAX_NUM_DREGS)? 1'b1 : 1'b0;
reg [35:0] pd_dregs [PD_MAX_NUM_DREGS-1:0];
reg is_eth_dst_mac_bcast;
reg is_eth_type_ipv4;
reg is_eth_ipv4_proto_udp;
reg is_eth_ipv4_dst_addr_here;
reg is_eth_udp_dst_port_here;
wire is_vrt_size_zero = (com_inp_data[15:0] == 16'h0); //needed on the same cycle, so it cant be registered
//Inspector output flags special case:
//Inject SOF into flags at first DSP line.
wire [3:0] pd_out_flags = (
(pd_dreg_count == PD_DREGS_DSP_OFFSET) &&
(pd_dest == PD_DEST_DSP)
)? 4'b0001 : pd_dregs[pd_dreg_count][35:32];
//The communication inspector ouput data and valid signals:
//Mux between com input and data registers based on the state.
wire [35:0] pd_out_data = (pd_state == PD_STATE_WRITE_REGS)?
{pd_out_flags, pd_dregs[pd_dreg_count][31:0]} : com_inp_data
;
wire pd_out_valid =
(pd_state == PD_STATE_WRITE_REGS)? 1'b1 : (
(pd_state == PD_STATE_WRITE_LIVE)? com_inp_valid : (
1'b0));
//The communication inspector ouput ready signal:
//Mux between the various destination ready signals.
wire pd_out_ready =
(pd_dest == PD_DEST_DSP)? pd_out_dsp_ready : (
(pd_dest == PD_DEST_EXT)? pd_out_ext_ready : (
(pd_dest == PD_DEST_CPU)? pd_out_cpu_ready : (
(pd_dest == PD_DEST_BOF)? pd_out_bof_ready : (
1'b0))));
//Always connected output data lines.
assign pd_out_dsp_data = pd_out_data;
assign pd_out_ext_data = pd_out_data;
assign pd_out_cpu_data = pd_out_data;
assign pd_out_bof_data = pd_out_data;
//Destination output valid signals:
//Comes from inspector valid when destination is selected, and otherwise low.
assign pd_out_dsp_valid = (pd_dest == PD_DEST_DSP)? pd_out_valid : 1'b0;
assign pd_out_ext_valid = (pd_dest == PD_DEST_EXT)? pd_out_valid : 1'b0;
assign pd_out_cpu_valid = (pd_dest == PD_DEST_CPU)? pd_out_valid : 1'b0;
assign pd_out_bof_valid = (pd_dest == PD_DEST_BOF)? pd_out_valid : 1'b0;
//The communication inspector ouput ready signal:
//Always ready when storing to data registers,
//comes from inspector ready output when live,
//and otherwise low.
assign com_inp_ready =
(pd_state == PD_STATE_READ_COM_PRE) ? 1'b1 : (
(pd_state == PD_STATE_READ_COM) ? 1'b1 : (
(pd_state == PD_STATE_WRITE_LIVE) ? pd_out_ready : (
1'b0)));
//inspect the incoming data and mark register booleans
always @(posedge clk)
if (com_inp_ready & com_inp_valid) begin
case(pd_dreg_count)
0: begin
is_eth_dst_mac_bcast <= (com_inp_data[15:0] == 16'hffff);
end
1: begin
is_eth_dst_mac_bcast <= is_eth_dst_mac_bcast && (com_inp_data[31:0] == 32'hffffffff);
end
3: begin
is_eth_type_ipv4 <= (com_inp_data[15:0] == 16'h800);
end
6: begin
is_eth_ipv4_proto_udp <= (com_inp_data[23:16] == 8'h11);
end
8: begin
is_eth_ipv4_dst_addr_here <= (com_inp_data[31:0] == my_ip_addr);
end
9: begin
is_eth_udp_dst_port_here <= (com_inp_data[15:0] == dsp_udp_port);
end
endcase //pd_dreg_count
end
always @(posedge clk)
if(rst | clr) begin
pd_state <= PD_STATE_READ_COM_PRE;
pd_dreg_count <= 0;
end
else begin
case(pd_state)
PD_STATE_READ_COM_PRE: begin
if (com_inp_ready & com_inp_valid & com_inp_data[32]) begin
pd_state <= PD_STATE_READ_COM;
pd_dreg_count <= pd_dreg_count_next;
pd_dregs[pd_dreg_count] <= com_inp_data;
end
end
PD_STATE_READ_COM: begin
if (com_inp_ready & com_inp_valid) begin
pd_dregs[pd_dreg_count] <= com_inp_data;
if (pd_dreg_counter_done | com_inp_data[33]) begin
pd_state <= PD_STATE_WRITE_REGS;
pd_dreg_count <= 0;
//---------- begin inspection decision -----------//
//EOF or bcast or not IPv4 or not UDP:
if (
com_inp_data[33] || is_eth_dst_mac_bcast ||
~is_eth_type_ipv4 || ~is_eth_ipv4_proto_udp
) begin
pd_dest <= PD_DEST_BOF;
end
//not my IP address:
else if (~is_eth_ipv4_dst_addr_here) begin
pd_dest <= PD_DEST_EXT;
end
//UDP data port and VRT:
else if (is_eth_udp_dst_port_here && ~is_vrt_size_zero) begin
pd_dest <= PD_DEST_DSP;
pd_dreg_count <= PD_DREGS_DSP_OFFSET;
end
//other:
else begin
pd_dest <= PD_DEST_CPU;
end
//---------- end inspection decision -------------//
end
else begin
pd_dreg_count <= pd_dreg_count_next;
end
end
end
PD_STATE_WRITE_REGS: begin
if (pd_out_ready & pd_out_valid) begin
if (pd_out_data[33]) begin
pd_state <= PD_STATE_READ_COM_PRE;
pd_dreg_count <= 0;
end
else if (pd_dreg_counter_done) begin
pd_state <= PD_STATE_WRITE_LIVE;
pd_dreg_count <= 0;
end
else begin
pd_dreg_count <= pd_dreg_count_next;
end
end
end
PD_STATE_WRITE_LIVE: begin
if (pd_out_ready & pd_out_valid & pd_out_data[33]) begin
pd_state <= PD_STATE_READ_COM_PRE;
end
end
endcase //pd_state
end
//connect this fast-path signals directly to the DSP out
assign dsp_out_data = pd_out_dsp_data;
assign dsp_out_valid = pd_out_dsp_valid;
assign pd_out_dsp_ready = dsp_out_ready;
////////////////////////////////////////////////////////////////////
// Splitter and output muxes for the bof packets
// - split the bof packets into two streams
// - mux split packets into cpu out and ext out
////////////////////////////////////////////////////////////////////
//dummy signals to join the the splitter and muxes below
wire [35:0] _split_to_ext_data, _split_to_cpu_data;
wire _split_to_ext_valid, _split_to_cpu_valid;
wire _split_to_ext_ready, _split_to_cpu_ready;
splitter36 bof_out_splitter(
.clk(clk), .rst(rst), .clr(clr),
.inp_data(pd_out_bof_data), .inp_valid(pd_out_bof_valid), .inp_ready(pd_out_bof_ready),
.out0_data(_split_to_ext_data), .out0_valid(_split_to_ext_valid), .out0_ready(_split_to_ext_ready),
.out1_data(_split_to_cpu_data), .out1_valid(_split_to_cpu_valid), .out1_ready(_split_to_cpu_ready)
);
fifo36_mux ext_out_mux(
.clk(clk), .reset(rst), .clear(clr),
.data0_i(pd_out_ext_data), .src0_rdy_i(pd_out_ext_valid), .dst0_rdy_o(pd_out_ext_ready),
.data1_i(_split_to_ext_data), .src1_rdy_i(_split_to_ext_valid), .dst1_rdy_o(_split_to_ext_ready),
.data_o(ext_out_data), .src_rdy_o(ext_out_valid), .dst_rdy_i(ext_out_ready)
);
fifo36_mux cpu_out_mux(
.clk(clk), .reset(rst), .clear(clr),
.data0_i(pd_out_cpu_data), .src0_rdy_i(pd_out_cpu_valid), .dst0_rdy_o(pd_out_cpu_ready),
.data1_i(_split_to_cpu_data), .src1_rdy_i(_split_to_cpu_valid), .dst1_rdy_o(_split_to_cpu_ready),
.data_o(cpu_out_data), .src_rdy_o(cpu_out_valid), .dst_rdy_i(cpu_out_ready)
);
endmodule // packet_dispatcher36_x3
|