aboutsummaryrefslogtreecommitdiffstats
path: root/fpga/usrp2/udp/prot_eng_tx.v
diff options
context:
space:
mode:
Diffstat (limited to 'fpga/usrp2/udp/prot_eng_tx.v')
-rw-r--r--fpga/usrp2/udp/prot_eng_tx.v146
1 files changed, 146 insertions, 0 deletions
diff --git a/fpga/usrp2/udp/prot_eng_tx.v b/fpga/usrp2/udp/prot_eng_tx.v
new file mode 100644
index 000000000..c642842f6
--- /dev/null
+++ b/fpga/usrp2/udp/prot_eng_tx.v
@@ -0,0 +1,146 @@
+
+// The input FIFO contents should be 16 bits wide
+// The first word is 1 for fast path (accelerated protocol)
+// 0 for software implemented protocol
+// The second word is the number of bytes in the packet,
+// and must be valid even if we are in slow path mode
+// Odd means the last word is half full
+// Flags[1:0] is {eop, sop}
+// Protocol word format is:
+// 21 UDP Source Port Here
+// 20 UDP Dest Port Here
+// 19 Last Header Line
+// 18 IP Header Checksum XOR
+// 17 IP Length Here
+// 16 UDP Length Here
+// 15:0 data word to be sent
+
+module prot_eng_tx
+ #(parameter BASE=0)
+ (input clk, input reset, input clear,
+ input set_stb, input [7:0] set_addr, input [31:0] set_data,
+ input [18:0] datain, input src_rdy_i, output dst_rdy_o,
+ output [18:0] dataout, output src_rdy_o, input dst_rdy_i);
+
+ wire [2:0] flags_i = datain[18:16];
+ reg [15:0] dataout_int;
+ reg fast_path, sof_o;
+
+ wire [2:0] flags_o = {flags_i[2], flags_i[1], sof_o}; // OCC, EOF, SOF
+
+ assign dataout = {flags_o[2:0], dataout_int[15:0]};
+
+ reg [4:0] state;
+ wire do_payload = (state == 31);
+
+ assign dst_rdy_o = dst_rdy_i & (do_payload | (state==0) | (state==1) | (state==30));
+ assign src_rdy_o = src_rdy_i & ~((state==0) | (state==1) | (state==30));
+
+ localparam HDR_WIDTH = 16 + 6; // 16 bits plus flags
+ localparam HDR_LEN = 32; // Up to 64 bytes of protocol
+
+ // Store header values in a small dual-port (distributed) ram
+ reg [HDR_WIDTH-1:0] header_ram[0:HDR_LEN-1];
+ wire [HDR_WIDTH-1:0] header_word;
+
+ reg [1:0] port_sel;
+ reg [31:0] per_port_data[0:3];
+ reg [15:0] udp_src_port, udp_dst_port, chk_precompute;
+
+ always @(posedge clk) udp_src_port <= per_port_data[port_sel][31:16];
+ always @(posedge clk) udp_dst_port <= per_port_data[port_sel][15:0];
+
+ always @(posedge clk)
+ if(set_stb & ((set_addr & 8'hE0) == BASE))
+ header_ram[set_addr[4:0]] <= set_data;
+
+ always @(posedge clk)
+ if(set_stb & (set_addr == (BASE + 14)))
+ chk_precompute <= set_data[15:0];
+
+ always @(posedge clk)
+ if(set_stb & ((set_addr & 8'hFC) == (BASE+24)))
+ per_port_data[set_addr[1:0]] <= set_data;
+
+ wire do_udp_src_port = header_word[21];
+ wire do_udp_dst_port = header_word[20];
+ wire last_hdr_line = header_word[19];
+ wire do_ip_chk = header_word[18];
+ wire do_ip_len = header_word[17];
+ wire do_udp_len = header_word[16];
+
+ assign header_word = header_ram[state];
+
+ // Protocol State Machine
+ reg [15:0] length;
+ wire [15:0] ip_length = length + 28; // IP HDR + UDP HDR
+ wire [15:0] udp_length = length + 8; // UDP HDR
+
+ always @(posedge clk)
+ if(reset)
+ begin
+ state <= 0;
+ fast_path <= 0;
+ sof_o <= 0;
+ end
+ else
+ if(src_rdy_i & dst_rdy_i)
+ case(state)
+ 0 :
+ begin
+ fast_path <= datain[0];
+ port_sel <= datain[2:1];
+ state <= 1;
+ end
+ 1 :
+ begin
+ length <= datain[15:0];
+ sof_o <= 1;
+ if(fast_path)
+ state <= 2;
+ else
+ state <= 30; // Skip 1 word for alignment
+ end
+ 30 :
+ state <= 31;
+ 31 :
+ begin
+ sof_o <= 0;
+ if(flags_i[1]) // eop
+ state <= 0;
+ end
+ default :
+ begin
+ sof_o <= 0;
+ if(~last_hdr_line)
+ state <= state + 1;
+ else
+ state <= 31;
+ end
+ endcase // case (state)
+
+ wire [15:0] checksum;
+ add_onescomp #(.WIDTH(16)) add_onescomp
+ (.A(chk_precompute),.B(ip_length),.SUM(checksum));
+
+ reg [15:0] checksum_reg;
+ always @(posedge clk)
+ checksum_reg <= checksum;
+
+ always @*
+ if(do_payload)
+ dataout_int <= datain[15:0];
+ else if(do_ip_chk)
+ dataout_int <= 16'hFFFF ^ checksum_reg;
+ else if(do_ip_len)
+ dataout_int <= ip_length;
+ else if(do_udp_len)
+ dataout_int <= udp_length;
+ else if(do_udp_src_port)
+ dataout_int <= udp_src_port;
+ else if(do_udp_dst_port)
+ dataout_int <= udp_dst_port;
+ else
+ dataout_int <= header_word[15:0];
+
+endmodule // prot_eng_tx