558 lines
15 KiB
Verilog
558 lines
15 KiB
Verilog
//////////////////////////////////////////////////////////////////////////////////////
|
|
//Module Name : icmp_reply
|
|
//Description : This module is used to receive icmp and reply
|
|
//
|
|
|
|
module icmp_reply
|
|
(
|
|
input clk,
|
|
input rst_n,
|
|
|
|
input mac_send_end,
|
|
input ip_tx_ack,
|
|
input [7:0] icmp_rx_data, //received data
|
|
input icmp_rx_req, //receive request
|
|
input icmp_rev_error, //receive error from MAC or IP
|
|
input [15:0] upper_layer_data_length, //data length received from IP layer
|
|
|
|
input icmp_data_req, //IP layer request data
|
|
output reg icmp_tx_ready, //icmp reply data ready
|
|
output reg [7:0] icmp_tx_data, //icmp reply data
|
|
output icmp_tx_end, //icmp reply end
|
|
output reg icmp_tx_req //icmp reply request
|
|
|
|
);
|
|
|
|
localparam ECHO_REQUEST = 8'h08 ;
|
|
localparam ECHO_REPLY = 8'h00 ;
|
|
|
|
reg [15:0] icmp_rx_cnt ;
|
|
|
|
reg icmp_rx_end ;
|
|
reg icmp_checksum_error ; //icmp receive checksum error
|
|
reg icmp_type_error ; //if icmp type is not 8'h08, do not reply
|
|
reg [15:0] icmp_data_length ; //data length register
|
|
reg [15:0] icmp_data_length_d0 ;
|
|
reg [10:0] icmp_rec_ram_read_addr ; //icmp ram read address
|
|
wire [7:0] icmp_rec_ram_rdata ; //icmp ram read data
|
|
reg [7:0] icmp_code ; //icmp code
|
|
reg [15:0] icmp_id ; //icmp id
|
|
reg [15:0] icmp_seq ; //icmp seq
|
|
reg checksum_finish ; //icmp reply checksum generated finish
|
|
|
|
reg [10:0] ram_write_addr ; //icmp ram write address, when receive icmp, write ram
|
|
reg ram_wr_en ; //icmp ram write enable
|
|
reg icmp_rev_error_d0 ;
|
|
|
|
reg [15:0] timeout ; //timeout counter
|
|
reg [7:0] icmp_rx_data_d0 ; //register for receive data
|
|
|
|
reg mac_send_end_d0 ;
|
|
|
|
//receive and reply FSM
|
|
parameter IDLE = 12'b00000_0000_001 ;
|
|
parameter REC_DATA = 12'b00000_0000_010 ;
|
|
parameter REC_ODD_DATA = 12'b00000_0000_100 ;
|
|
parameter VERIFY_CHECKSUM = 12'b00000_0001_000 ;
|
|
parameter REC_ERROR = 12'b00000_0010_000 ;
|
|
parameter REC_END_WAIT = 12'b00000_0100_000 ;
|
|
parameter GEN_CHECKSUM = 12'b00000_1000_000 ;
|
|
parameter SEND_WAIT_0 = 12'b00001_0000_000 ;
|
|
parameter SEND_WAIT_1 = 12'b00010_0000_000 ;
|
|
parameter SEND = 12'b00100_0000_000 ;
|
|
parameter REC_END = 12'b01000_0000_000 ;
|
|
parameter SEND_END = 12'b10000_0000_000 ;
|
|
|
|
|
|
|
|
reg [11:0] state ;
|
|
reg [11:0] next_state ;
|
|
|
|
always @(posedge clk or negedge rst_n)
|
|
begin
|
|
if (~rst_n)
|
|
state <= IDLE ;
|
|
else
|
|
state <= next_state ;
|
|
end
|
|
|
|
always @(*)
|
|
begin
|
|
case(state)
|
|
IDLE :
|
|
begin
|
|
if (icmp_rx_req == 1'b1)
|
|
next_state <= REC_DATA ;
|
|
else
|
|
next_state <= IDLE ;
|
|
end
|
|
REC_DATA :
|
|
begin
|
|
if (icmp_rev_error_d0 || icmp_type_error)
|
|
next_state <= REC_ERROR ;
|
|
else if (icmp_data_length[0] == 1'b0 && icmp_rx_cnt == icmp_data_length - 1)
|
|
next_state <= VERIFY_CHECKSUM ;
|
|
else if (icmp_data_length[0] == 1'b1 && icmp_rx_cnt == icmp_data_length - 2)
|
|
next_state <= REC_ODD_DATA ;
|
|
else if (icmp_rx_cnt == 16'hffff)
|
|
next_state <= IDLE ;
|
|
else
|
|
next_state <= REC_DATA ;
|
|
end
|
|
REC_ODD_DATA :
|
|
begin
|
|
if (icmp_rev_error_d0 || icmp_type_error)
|
|
next_state <= REC_ERROR ;
|
|
else if (icmp_rx_cnt == icmp_data_length - 1)
|
|
next_state <= VERIFY_CHECKSUM ;
|
|
else
|
|
next_state <= REC_ODD_DATA ;
|
|
end
|
|
VERIFY_CHECKSUM:
|
|
begin
|
|
if (icmp_checksum_error)
|
|
next_state <= REC_ERROR ;
|
|
else if (icmp_rx_end && checksum_finish)
|
|
next_state <= REC_END_WAIT ;
|
|
else if (icmp_rx_cnt == 16'hffff)
|
|
next_state <= IDLE ;
|
|
else
|
|
next_state <= VERIFY_CHECKSUM ;
|
|
end
|
|
REC_ERROR :
|
|
next_state <= IDLE ;
|
|
REC_END_WAIT :
|
|
begin
|
|
if (icmp_rx_cnt == 16'd63)
|
|
next_state <= REC_END ;
|
|
else
|
|
next_state <= REC_END_WAIT ;
|
|
end
|
|
SEND_WAIT_0 :
|
|
begin
|
|
if (ip_tx_ack)
|
|
next_state <= SEND_WAIT_1 ;
|
|
else
|
|
next_state <= SEND_WAIT_0 ;
|
|
end
|
|
SEND_WAIT_1 :
|
|
begin
|
|
if (icmp_data_req)
|
|
next_state <= SEND ;
|
|
else if (timeout == 16'hffff)
|
|
next_state <= IDLE ;
|
|
else
|
|
next_state <= SEND_WAIT_1 ;
|
|
end
|
|
SEND :
|
|
begin
|
|
if (icmp_rx_cnt == icmp_data_length)
|
|
next_state <= SEND_END ;
|
|
else if (icmp_rx_cnt == 16'hffff)
|
|
next_state <= IDLE ;
|
|
else
|
|
next_state <= SEND ;
|
|
end
|
|
REC_END :
|
|
next_state <= SEND_WAIT_0 ;
|
|
SEND_END :
|
|
begin
|
|
if (mac_send_end_d0)
|
|
next_state <= IDLE ;
|
|
else
|
|
next_state <= SEND_END ;
|
|
end
|
|
default :
|
|
next_state <= IDLE ;
|
|
endcase
|
|
end
|
|
|
|
|
|
always @(posedge clk or negedge rst_n)
|
|
begin
|
|
if (~rst_n)
|
|
mac_send_end_d0 <= 1'b0 ;
|
|
else
|
|
mac_send_end_d0 <= mac_send_end ;
|
|
end
|
|
|
|
always @(posedge clk or negedge rst_n)
|
|
begin
|
|
if (~rst_n)
|
|
icmp_tx_req <= 1'b0 ;
|
|
else if (state == SEND_WAIT_1)
|
|
icmp_tx_req <= 1'b0 ;
|
|
else if (state == REC_END)
|
|
icmp_tx_req <= 1'b1 ;
|
|
end
|
|
|
|
always @(posedge clk or negedge rst_n)
|
|
begin
|
|
if (~rst_n)
|
|
icmp_tx_ready <= 1'b0 ;
|
|
else if (state == SEND_WAIT_1)
|
|
icmp_tx_ready <= 1'b1 ;
|
|
else
|
|
icmp_tx_ready <= 1'b0 ;
|
|
end
|
|
|
|
always @(posedge clk or negedge rst_n)
|
|
begin
|
|
if (~rst_n)
|
|
ram_wr_en <= 1'b0 ;
|
|
else if (state == REC_DATA || state == REC_ODD_DATA)
|
|
begin
|
|
if (icmp_rx_cnt < icmp_data_length && icmp_rx_cnt > 16'd7)
|
|
ram_wr_en <= 1'b1 ;
|
|
else
|
|
ram_wr_en <= 1'b0 ;
|
|
end
|
|
else
|
|
ram_wr_en <= 1'b0 ;
|
|
end
|
|
|
|
always @(posedge clk or negedge rst_n)
|
|
begin
|
|
if (~rst_n)
|
|
ram_write_addr <= 11'b0 ;
|
|
else if (state == REC_DATA || state == REC_ODD_DATA)
|
|
ram_write_addr <= icmp_rx_cnt - 8 ;
|
|
else
|
|
ram_write_addr <= 11'b0 ;
|
|
end
|
|
|
|
//timeout counter
|
|
always @(posedge clk or negedge rst_n)
|
|
begin
|
|
if (~rst_n)
|
|
timeout <= 16'd0 ;
|
|
else if (state == SEND_WAIT_1)
|
|
timeout <= timeout + 1'b1 ;
|
|
else
|
|
timeout <= 16'd0 ;
|
|
end
|
|
//received data register
|
|
always @(posedge clk or negedge rst_n)
|
|
begin
|
|
if (~rst_n)
|
|
icmp_rx_data_d0 <= 8'd0 ;
|
|
else
|
|
icmp_rx_data_d0 <= icmp_rx_data ;
|
|
end
|
|
|
|
always @(posedge clk or negedge rst_n)
|
|
begin
|
|
if (~rst_n)
|
|
icmp_rev_error_d0 <= 1'b0 ;
|
|
else
|
|
icmp_rev_error_d0 <= icmp_rev_error ;
|
|
end
|
|
|
|
always @(posedge clk or negedge rst_n)
|
|
begin
|
|
if (~rst_n)
|
|
icmp_data_length <= 16'd0 ;
|
|
else if (state == IDLE)
|
|
icmp_data_length <= upper_layer_data_length ;
|
|
end
|
|
|
|
|
|
//icmp receive and reply counter
|
|
always @(posedge clk or negedge rst_n)
|
|
begin
|
|
if (~rst_n)
|
|
icmp_rx_cnt <= 16'd0 ;
|
|
else if (state == REC_DATA || state == REC_END_WAIT || state == SEND)
|
|
icmp_rx_cnt <= icmp_rx_cnt + 1'b1 ;
|
|
else
|
|
icmp_rx_cnt <= 16'd0 ;
|
|
end
|
|
|
|
|
|
//icmp type is not request
|
|
always @(posedge clk or negedge rst_n)
|
|
begin
|
|
if (~rst_n)
|
|
icmp_type_error <= 1'b0 ;
|
|
else if (state == REC_DATA && icmp_rx_cnt == 16'd0 && icmp_rx_data != ECHO_REQUEST)
|
|
icmp_type_error <= 1'b1 ;
|
|
else
|
|
icmp_type_error <= 1'b0 ;
|
|
end
|
|
|
|
//icmp code
|
|
always @(posedge clk or negedge rst_n)
|
|
begin
|
|
if (~rst_n)
|
|
icmp_code <= 8'd0 ;
|
|
else if (state == REC_DATA && icmp_rx_cnt == 16'd1)
|
|
icmp_code <= icmp_rx_data ;
|
|
end
|
|
|
|
//icmp id
|
|
always @(posedge clk or negedge rst_n)
|
|
begin
|
|
if (~rst_n)
|
|
icmp_id <= 16'd0 ;
|
|
else if (state == REC_DATA && icmp_rx_cnt == 16'd4)
|
|
icmp_id[15:8] <= icmp_rx_data ;
|
|
else if (state == REC_DATA && icmp_rx_cnt == 16'd5)
|
|
icmp_id[7:0] <= icmp_rx_data ;
|
|
end
|
|
|
|
//icmp seq
|
|
always @(posedge clk or negedge rst_n)
|
|
begin
|
|
if (~rst_n)
|
|
icmp_seq <= 16'd0 ;
|
|
else if (state == REC_DATA && icmp_rx_cnt == 16'd6)
|
|
icmp_seq[15:8] <= icmp_rx_data ;
|
|
else if (state == REC_DATA && icmp_rx_cnt == 16'd7)
|
|
icmp_seq[7:0] <= icmp_rx_data ;
|
|
end
|
|
|
|
|
|
//read ram address when reply
|
|
always @(posedge clk or negedge rst_n)
|
|
begin
|
|
if (~rst_n)
|
|
icmp_rec_ram_read_addr <= 11'd0 ;
|
|
else if (state == SEND && icmp_rx_cnt > 5)
|
|
icmp_rec_ram_read_addr <= icmp_rx_cnt - 6 ;
|
|
else
|
|
icmp_rec_ram_read_addr <= 11'd0 ;
|
|
end
|
|
//received ram: depth 256 width 8
|
|
icmp_rx_ram_8_256 icmp_receive_ram
|
|
(
|
|
.clka(clk), // input wire clka
|
|
.wea(ram_wr_en), // input wire [0 : 0] wea
|
|
.addra(ram_write_addr), // input wire [7 : 0] addra
|
|
.dina(icmp_rx_data_d0), // input wire [7 : 0] dina
|
|
.clkb(clk), // input wire clkb
|
|
.addrb(icmp_rec_ram_read_addr), // input wire [7 : 0] addrb
|
|
.doutb(icmp_rec_ram_rdata) // output wire [7 : 0] doutb
|
|
);
|
|
|
|
|
|
//***************************************************************************//
|
|
//verify checksum 32 bit adder, in the end, add itself until high 16 bit is 0
|
|
//** ************************************************************************//
|
|
reg [31:0] checksum_tmp ;
|
|
reg [31:0] checksum_buf ;
|
|
reg [31:0] check_out ;
|
|
reg [31:0] checkout_buf ;
|
|
wire [15:0] checksum ;
|
|
reg [2:0] checksum_cnt ;
|
|
|
|
//checksum function
|
|
function [31:0] checksum_adder
|
|
(
|
|
input [31:0] dataina,
|
|
input [31:0] datainb
|
|
);
|
|
begin
|
|
checksum_adder = dataina + datainb;
|
|
end
|
|
endfunction
|
|
|
|
function [31:0] checksum_out
|
|
(
|
|
input [31:0] dataina
|
|
);
|
|
begin
|
|
checksum_out = dataina[15:0]+dataina[31:16];
|
|
end
|
|
endfunction
|
|
|
|
always @(posedge clk or negedge rst_n)
|
|
begin
|
|
if(rst_n == 1'b0)
|
|
checksum_tmp <= 32'd0;
|
|
else if (state == REC_DATA)
|
|
begin
|
|
if(icmp_rx_cnt[0] == 1'b1)
|
|
checksum_tmp <= checksum_adder({icmp_rx_data_d0,icmp_rx_data},checksum_buf);
|
|
end
|
|
else if (state == REC_ODD_DATA)
|
|
checksum_tmp <= checksum_adder({icmp_rx_data,8'h00},checksum_tmp); //if udp data length is odd, fill with one byte 8'h00
|
|
else if (state == IDLE)
|
|
checksum_tmp <= 32'd0;
|
|
end
|
|
|
|
always @(posedge clk or negedge rst_n)
|
|
begin
|
|
if(rst_n == 1'b0)
|
|
checksum_cnt <= 3'd0 ;
|
|
else if (state == VERIFY_CHECKSUM)
|
|
checksum_cnt <= checksum_cnt + 1'b1 ;
|
|
else
|
|
checksum_cnt <= 3'd0 ;
|
|
end
|
|
|
|
always @(posedge clk or negedge rst_n)
|
|
begin
|
|
if(rst_n == 1'b0)
|
|
check_out <= 32'd0;
|
|
else if (state == VERIFY_CHECKSUM)
|
|
begin
|
|
if (checksum_cnt == 3'd0)
|
|
check_out <= checksum_out(checksum_tmp) ;
|
|
else if (checksum_cnt == 3'd1)
|
|
check_out <= checksum_out(check_out) ;
|
|
end
|
|
end
|
|
|
|
always @(posedge clk or negedge rst_n)
|
|
begin
|
|
if (~rst_n)
|
|
checksum_buf <= 32'd0 ;
|
|
else if (state == REC_DATA)
|
|
checksum_buf <= checksum_tmp ;
|
|
else
|
|
checksum_buf <= 32'd0 ;
|
|
end
|
|
|
|
always @(posedge clk or negedge rst_n)
|
|
begin
|
|
if (~rst_n)
|
|
checkout_buf <= 32'd0 ;
|
|
else
|
|
checkout_buf <= check_out ;
|
|
end
|
|
|
|
assign checksum = ~checkout_buf[15:0] ;
|
|
|
|
//generate checksum error signal and rx end signal
|
|
always @(posedge clk or negedge rst_n)
|
|
begin
|
|
if (~rst_n)
|
|
begin
|
|
icmp_checksum_error <= 1'b0 ;
|
|
icmp_rx_end <= 1'b0 ;
|
|
end
|
|
else if (state == VERIFY_CHECKSUM && checksum_cnt == 3'd3)
|
|
begin
|
|
if (checksum == 16'd0)
|
|
begin
|
|
icmp_checksum_error <= 1'b0 ;
|
|
icmp_rx_end <= 1'b1 ;
|
|
end
|
|
else
|
|
begin
|
|
icmp_checksum_error <= 1'b1 ;
|
|
icmp_rx_end <= 1'b0 ;
|
|
end
|
|
end
|
|
else
|
|
begin
|
|
icmp_checksum_error <= 1'b0 ;
|
|
icmp_rx_end <= 1'b0 ;
|
|
end
|
|
end
|
|
|
|
|
|
|
|
//*******************************************************************//
|
|
//reply checksum
|
|
//*******************************************************************//
|
|
reg [31:0] reply_checksum_tmp ;
|
|
reg [31:0] reply_checksum_buf ;
|
|
reg [31:0] reply_check_out ;
|
|
reg [31:0] reply_checkout_buf ;
|
|
wire [15:0] reply_checksum ;
|
|
|
|
|
|
always @(posedge clk or negedge rst_n)
|
|
begin
|
|
if(rst_n == 1'b0)
|
|
reply_checksum_tmp <= 32'd0;
|
|
else if (state == REC_DATA)
|
|
begin
|
|
if (icmp_rx_cnt == 16'd1)
|
|
reply_checksum_tmp <= checksum_adder({8'h00,icmp_rx_data}, 16'h0000); //source ip address
|
|
else if (icmp_rx_cnt == 16'd3)
|
|
reply_checksum_tmp <= reply_checksum_tmp ; //source ip address
|
|
else
|
|
begin
|
|
if(icmp_rx_cnt[0] == 1'b1)
|
|
reply_checksum_tmp <= checksum_adder({icmp_rx_data_d0,icmp_rx_data},reply_checksum_buf);
|
|
end
|
|
end
|
|
else if (state == REC_ODD_DATA)
|
|
reply_checksum_tmp <= checksum_adder({icmp_rx_data,8'h00},reply_checksum_tmp); //if udp data length is odd, fill with one byte 8'h00
|
|
else if (state == IDLE)
|
|
reply_checksum_tmp <= 32'd0;
|
|
end
|
|
|
|
|
|
always @(posedge clk or negedge rst_n)
|
|
begin
|
|
if(rst_n == 1'b0)
|
|
reply_check_out <= 32'd0;
|
|
else if (state == VERIFY_CHECKSUM)
|
|
begin
|
|
if (checksum_cnt == 3'd0)
|
|
reply_check_out <= checksum_out(reply_checksum_tmp) ;
|
|
else if (checksum_cnt == 3'd1)
|
|
reply_check_out <= checksum_out(reply_check_out) ;
|
|
end
|
|
end
|
|
|
|
always @(posedge clk or negedge rst_n)
|
|
begin
|
|
if (~rst_n)
|
|
reply_checksum_buf <= 32'd0 ;
|
|
else if (state == REC_DATA)
|
|
reply_checksum_buf <= reply_checksum_tmp ;
|
|
else
|
|
reply_checksum_buf <= 32'd0 ;
|
|
end
|
|
|
|
always @(posedge clk or negedge rst_n)
|
|
begin
|
|
if (~rst_n)
|
|
reply_checkout_buf <= 32'd0 ;
|
|
else if (state == VERIFY_CHECKSUM)
|
|
reply_checkout_buf <= reply_check_out ;
|
|
end
|
|
|
|
assign reply_checksum = ~reply_checkout_buf[15:0] ;
|
|
|
|
always @(posedge clk or negedge rst_n)
|
|
begin
|
|
if (~rst_n)
|
|
checksum_finish <= 1'b0 ;
|
|
else if (state == VERIFY_CHECKSUM && checksum_cnt == 3'd3)
|
|
checksum_finish <= 1'b1 ;
|
|
else
|
|
checksum_finish <= 1'b0 ;
|
|
end
|
|
|
|
|
|
//*****************************************************************************************//
|
|
//send icmp data
|
|
//*****************************************************************************************//
|
|
always @(posedge clk or negedge rst_n)
|
|
begin
|
|
if (~rst_n)
|
|
icmp_tx_data <= 8'h00 ;
|
|
else if (state == SEND)
|
|
begin
|
|
case(icmp_rx_cnt)
|
|
16'd0 : icmp_tx_data <= ECHO_REPLY ;
|
|
16'd1 : icmp_tx_data <= icmp_code ;
|
|
16'd2 : icmp_tx_data <= reply_checksum[15:8];
|
|
16'd3 : icmp_tx_data <= reply_checksum[7:0] ;
|
|
16'd4 : icmp_tx_data <= icmp_id[15:8] ;
|
|
16'd5 : icmp_tx_data <= icmp_id[7:0] ;
|
|
16'd6 : icmp_tx_data <= icmp_seq[15:8] ;
|
|
16'd7 : icmp_tx_data <= icmp_seq[7:0] ;
|
|
default : icmp_tx_data <= icmp_rec_ram_rdata ;
|
|
endcase
|
|
end
|
|
else
|
|
icmp_tx_data <= 8'h00 ;
|
|
end
|
|
|
|
endmodule |