1// 2// Copyright 2011 Ettus Research LLC 3// 4// This program is free software: you can redistribute it and/or modify 5// it under the terms of the GNU General Public License as published by 6// the Free Software Foundation, either version 3 of the License, or 7// (at your option) any later version. 8// 9// This program is distributed in the hope that it will be useful, 10// but WITHOUT ANY WARRANTY; without even the implied warranty of 11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12// GNU General Public License for more details. 13// 14// You should have received a copy of the GNU General Public License 15// along with this program. If not, see <http://www.gnu.org/licenses/>. 16// 17 18 19module prot_eng_tx 20 #(parameter BASE=0) 21 (input clk, input reset, input clear, 22 input set_stb, input [7:0] set_addr, input [31:0] set_data, 23 input [35:0] datain, input src_rdy_i, output dst_rdy_o, 24 output [35:0] dataout, output src_rdy_o, input dst_rdy_i); 25 26 wire src_rdy_int1, dst_rdy_int1; 27 wire src_rdy_int2, dst_rdy_int2; 28 wire [35:0] data_int1, data_int2; 29 30 // Shortfifo on input to guarantee no deadlock 31 fifo_short #(.WIDTH(36)) head_fifo 32 (.clk(clk),.reset(reset),.clear(clear), 33 .datain(datain), .src_rdy_i(src_rdy_i), .dst_rdy_o(dst_rdy_o), 34 .dataout(data_int1), .src_rdy_o(src_rdy_int1), .dst_rdy_i(dst_rdy_int1), 35 .space(),.occupied() ); 36 37 // Store header values in a small dual-port (distributed) ram 38 reg [31:0] header_ram[0:63]; 39 reg [3:0] state; 40 reg [1:0] port_sel; 41 42 always @(posedge clk) 43 if(set_stb & ((set_addr & 8'hC0) == BASE)) 44 header_ram[set_addr[5:0]] <= set_data; 45 46 wire [31:0] header_word = header_ram[{port_sel[1:0],state[3:0]}]; 47 48 reg [15:0] pre_checksums [0:3]; 49 always @(posedge clk) 50 if(set_stb & ((set_addr & 8'hCF)== (BASE+7))) 51 pre_checksums[set_addr[5:4]] <= set_data[15:0]; 52 53 wire [15:0] pre_checksum = pre_checksums[port_sel[1:0]]; 54 55 // Protocol State Machine 56 reg [15:0] length; 57 wire [15:0] ip_length = length + 28; // IP HDR + UDP HDR 58 wire [15:0] udp_length = length + 8; // UDP HDR 59 reg sof_o; 60 reg [31:0] prot_data; 61 62 always @(posedge clk) 63 if(reset) 64 begin 65 state <= 0; 66 sof_o <= 0; 67 end 68 else 69 if(src_rdy_int1 & dst_rdy_int2) 70 case(state) 71 0 : 72 begin 73 port_sel <= data_int1[18:17]; 74 length <= data_int1[15:0]; 75 sof_o <= 1; 76 if(data_int1[16]) 77 state <= 1; 78 else 79 state <= 12; 80 end 81 12 : 82 begin 83 sof_o <= 0; 84 if(data_int1[33]) // eof 85 state <= 0; 86 end 87 default : 88 begin 89 sof_o <= 0; 90 state <= state + 1; 91 end 92 endcase // case (state) 93 94 wire [15:0] ip_checksum; 95 add_onescomp #(.WIDTH(16)) add_onescomp 96 (.A(pre_checksum),.B(ip_length),.SUM(ip_checksum)); 97 reg [15:0] ip_checksum_reg; 98 always @(posedge clk) ip_checksum_reg <= ip_checksum; 99 100 always @* 101 case(state) 102 1 : prot_data <= header_word; // ETH, top half ignored 103 2 : prot_data <= header_word; // ETH 104 3 : prot_data <= header_word; // ETH 105 4 : prot_data <= header_word; // ETH 106 5 : prot_data <= { header_word[31:16], ip_length }; // IP 107 6 : prot_data <= header_word; // IP 108 7 : prot_data <= { header_word[31:16], (16'hFFFF ^ ip_checksum_reg) }; // IP 109 8 : prot_data <= header_word; // IP 110 9 : prot_data <= header_word; // IP 111 10: prot_data <= header_word; // UDP 112 11: prot_data <= { udp_length, header_word[15:0]}; // UDP 113 default : prot_data <= data_int1[31:0]; 114 endcase // case (state) 115 116 assign data_int2 = { data_int1[35:33] & {3{state[3]}}, sof_o, prot_data }; 117 assign dst_rdy_int1 = dst_rdy_int2 & ((state == 0) | (state == 12)); 118 assign src_rdy_int2 = src_rdy_int1 & (state != 0); 119 120 // Shortfifo on output to guarantee no deadlock 121 fifo_short #(.WIDTH(36)) tail_fifo 122 (.clk(clk),.reset(reset),.clear(clear), 123 .datain(data_int2), .src_rdy_i(src_rdy_int2), .dst_rdy_o(dst_rdy_int2), 124 .dataout(dataout), .src_rdy_o(src_rdy_o), .dst_rdy_i(dst_rdy_i), 125 .space(),.occupied() ); 126 127endmodule // prot_eng_tx 128