Menu Close

以太网UDP 实验(eth_ip_tx.v)

eth_ip_tx.v 模块是从UDP_TX_DRAM双端口中读取数据,加上MAC头 + 0800 + IP头 ,计算好IP头的checksum ,之后将数据流发送到TX_IP_FIFO中去.

ethernet verilog code flowchart

图1

ip tx interface

图2

ip_tx_st 状态机解析:

状态0: 初始化相关的数据, 将UDP_TX_DRAM 的子地址指向 1023,跳转到状态机1。

状态1: 等待1个时钟周期,跳转到状态机2。

状态2: 检查UDP_TX_DRAM 的子地址1023,查看双端口读取出的数据,看看UDP是否有数据准备发送,如果有,跳转到状态机3。

状态3: 根据读出的UDP长度,计算出IP包的长度和以太网包的长度,跳转到状态机4。

状态4: 查看FIFO是否有空间可以存储数据,如果有足够的空间,跳转到状态机5。

状态5: 首先将长度信息写入到FIFO中去,跳转到状态机6。

状态6 – 8: 写入目的MAC地址,跳转到状态机9。

状态9 – 11: 写入源MAC地址,跳转到状态机12。

状态12: 写入0800 以太网类型 ,跳转到状态机13。

状态13- 22: 写入IP头信息 ,跳转到状态机23。

状态23: 读取UDP的数据,写入到FIFO中去,跳转到状态机24。

状态24: 清除UDP双端口,写入FIFO封口信息,跳转到状态机25。

状态25: 清除相关的寄存器 ,跳转到状态机26。

状态26: UDP乒乓buffer 地址转换,跳转到状态机0。

 

副状态机(ip_chk_st)计算IP头checksum :

在发送ip 包时,4500, 4000, 4011  , 前面6 bytes 的信息是固定的,直接计算好checksum 即可。

状态0: 计算 length 的checksum, 跳转状态1。

状态1: 计算 源IP的checksum, 跳转状态2。

状态2: 计算 源IP的checksum, 跳转状态3。

状态3: 计算 目的IP的checksum, 跳转状态4。

状态4: 计算 目的IP的checksum, 跳转状态5。

状态5: 计算 最终的checksum结果, 跳转状态6。

状态6: 表示checksum 计算结束。

 

状态机的示意图如图3(注意省略了状态转移条件不满足时,停留在当前状态的箭头)所示:

 

图3 状态机示意图

 

eth_ip_tx.v 代码:

`timescale 1ns / 1ps



module eth_ip_tx #
(
    parameter [47:0] TX_MAC_SRC    = 48'h66_72_61_73_65_72,
    parameter [47:0] TX_MAC_DES    = 48'hff_ff_ff_ff_ff_ff,

    parameter [31:0] TX_IP_SRC     = 32'hc0a8003d,
    parameter [31:0] TX_IP_DES     = 32'hc0a800ff,

    parameter IP_BUF_SIZE = 10,
    parameter IP_IDX_BIT = 1
)
(
    input           sys_clk,
    
    input           udp_tx_wea,
    input  [IP_BUF_SIZE + IP_IDX_BIT - 1:0] udp_tx_addra,
    input  [15:0]   udp_tx_dina,
    output [15:0]   udp_tx_douta,

    output [17:0]   ip_fifo_din,
    output reg      ip_fifo_we = 0,
    input  [15:0]   ip_fifo_cnt,   //write sync cnt, the max fifo depth is 2047

    input           reset
);
//=========================================================================
reg  udp_tx_web = 0;
reg  [IP_BUF_SIZE - 1:0] udp_tx_addrb_sub = 0;
reg  [IP_IDX_BIT - 1:0] udp_tx_idb = 0;
wire [IP_BUF_SIZE + IP_IDX_BIT - 1:0] udp_tx_addrb = {udp_tx_idb, udp_tx_addrb_sub};
wire [15:0] udp_tx_doutb;
    
UDP_DRAM   UDP_TX_DRAM_inst
(
    .clka   (sys_clk),      // input wire clka
    .wea    (udp_tx_wea),   // input wire [0 : 0] wea
    .addra  (udp_tx_addra), // input wire [10 : 0] addra
    .dina   (udp_tx_dina),  // input wire [15 : 0] dina
    .douta  (udp_tx_douta), // output wire [15 : 0] douta
    
    .clkb   (sys_clk),      // input wire clkb
    .web    (udp_tx_web),   // input wire [0 : 0] web
    .addrb  (udp_tx_addrb), // input wire [10 : 0] addrb
    .dinb   (0),            // input wire [15 : 0] dinb
    .doutb  (udp_tx_doutb)  // output wire [15 : 0] doutb
);    
//=========================================================================
reg  [1:0]  ip_fifo_flag = 0;
reg  [15:0] ip_fifo_data = 0;
assign ip_fifo_din = {ip_fifo_flag[1], ip_fifo_data[15:8], ip_fifo_flag[0], ip_fifo_data[7:0]};

wire [15:0] ip_fifo_blank = 2047 - ip_fifo_cnt;
//=======================================================================   
reg  [15:0] ip_tx_len = 0;    //udp包长 + 20
reg  [15:0] eth_tx_len = 0;   //udp包长 + 36
reg  [15:0] ip_tx_cnt = 0;

reg  ip_chk_start = 0;
reg  ip_chk_end = 0;
reg [23:0] ip_checksum = 16'hc511;  //4500(版本,首部长度,tos) + 4000(标志,片位移) + 4011(TTL + protocol)

reg  [4:0]  ip_tx_st = 0;
always @ (posedge sys_clk)
if(reset)
begin
    udp_tx_idb <= 0;
    udp_tx_web <= 0;
    
    ip_fifo_we <= 0;
    ip_tx_st <= 0;
end 
else case (ip_tx_st)
0:
begin
    ip_tx_cnt <= 0;
    ip_chk_start <= 0;
    
    udp_tx_addrb_sub <= {IP_BUF_SIZE{1'b1}};
    udp_tx_web <= 0;
    
    ip_fifo_we <= 0;
    ip_tx_st <= 1;
end
1:
begin
    udp_tx_addrb_sub <= {IP_BUF_SIZE{1'b1}};
    udp_tx_web <= 0;

    ip_tx_st <= 2;
end
2:
begin
    if(udp_tx_doutb[15] == 1)
    begin
        ip_tx_st <= 3;
    end
end
3:
begin
    ip_tx_len <= udp_tx_doutb[11:0] + 20; 
    eth_tx_len <= udp_tx_doutb[11:0] + 36; // des_mac(6) + src_mac(6) + 0800(2) + ip_header(20) + package_len(2)
    ip_chk_start <= 1;
    ip_tx_st <= 4;
end
4:
begin
    if( ip_fifo_blank > eth_tx_len)
    begin
        ip_tx_st <= 5;
    end
end
5:
begin
    // used for handle odd bytes
    ip_fifo_flag <= 0;
    ip_fifo_data <= eth_tx_len - 2; // mac + 0800 + ip_header + payload
    ip_fifo_we <= 1;

    ip_tx_st <= 6;
end
6:
begin
    ip_fifo_flag <= 0;
    ip_fifo_data <= TX_MAC_DES[47:32];
    ip_fifo_we <= 1;

    ip_tx_st <= 7;
end
7:
begin
    ip_fifo_flag <= 0;
    ip_fifo_data <= TX_MAC_DES[31:16];
    ip_fifo_we <= 1;

    ip_tx_st <= 8;
end
8:
begin
    ip_fifo_flag <= 0;
    ip_fifo_data <= TX_MAC_DES[15:00];
    ip_fifo_we <= 1;

    ip_tx_st <= 9;
end
9:
begin
    ip_fifo_flag <= 0;
    ip_fifo_data <= TX_MAC_SRC[47:32];
    ip_fifo_we <= 1;

    ip_tx_st <= 10;
end
10:
begin
    ip_fifo_flag <= 0;
    ip_fifo_data <= TX_MAC_SRC[31:16];
    ip_fifo_we <= 1;

    ip_tx_st <= 11;
end
11:
begin
    ip_fifo_flag <= 0;
    ip_fifo_data <= TX_MAC_SRC[15:00];
    ip_fifo_we <= 1;

    ip_tx_st <= 12;
end
12:
begin
    ip_fifo_flag <= 0;
    ip_fifo_data <= 16'h0800;  // ethernet type
    ip_fifo_we <= 1;

    ip_tx_st <= 13;
end
13:
begin
    ip_tx_cnt <= ip_tx_cnt + 2;
    
    ip_fifo_flag <= 0;
    ip_fifo_data <= 16'h4500; // ip header
    ip_fifo_we <= 1;

    ip_tx_st <= 14;
end
14:
begin
    ip_tx_cnt <= ip_tx_cnt + 2;
    
    ip_fifo_flag <= 0;
    ip_fifo_data <= ip_tx_len; // ip package length
    ip_fifo_we <= 1;

    ip_tx_st <= 15;
end
15:
begin
    ip_tx_cnt <= ip_tx_cnt + 2;
    
    ip_fifo_flag <= 0;
    ip_fifo_data <= 16'h0000;    // random value
    ip_fifo_we <= 1;

    ip_tx_st <= 16;
end
16:
begin
    ip_tx_cnt <= ip_tx_cnt + 2;
    
    ip_fifo_flag <= 0;
    ip_fifo_data <= 16'h4000;    // flags ,fragment
    ip_fifo_we <= 1;

    ip_tx_st <= 17;
end
17:
begin
    ip_tx_cnt <= ip_tx_cnt + 2;
    
    ip_fifo_flag <= 0;
    ip_fifo_data <= 16'h4011;    // ttl , protocol
    ip_fifo_we <= 1;

    ip_tx_st <= 18;
end
18:
begin
    if(ip_chk_end)
    begin
        ip_tx_cnt <= ip_tx_cnt + 2;
        
        ip_fifo_flag <= 0;
        ip_fifo_data <= ip_checksum[15:0];    // checksum
        ip_fifo_we <= 1;

        ip_chk_start <= 0;
        ip_tx_st <= 19;
    end
    else ip_fifo_we <= 0;
end
19:
begin
    ip_tx_cnt <= ip_tx_cnt + 2;
    
    ip_fifo_flag <= 0;
    ip_fifo_data <= TX_IP_SRC[31:16];    // src ip address
    ip_fifo_we <= 1;

    ip_tx_st <= 20;
end
20:
begin
    ip_tx_cnt <= ip_tx_cnt + 2;
    
    ip_fifo_flag <= 0;
    ip_fifo_data <= TX_IP_SRC[15:0];    // src ip address
    ip_fifo_we <= 1;

    ip_tx_st <= 21;
end
21:
begin
    udp_tx_addrb_sub <= udp_tx_addrb_sub + 1;
    ip_tx_cnt <= ip_tx_cnt + 2;
    
    ip_fifo_flag <= 0;
    ip_fifo_data <= TX_IP_DES[31:16];    // des ip address
    ip_fifo_we <= 1;

    ip_tx_st <= 22;
end
22:
begin
    udp_tx_addrb_sub <= udp_tx_addrb_sub + 1;
    ip_tx_cnt <= ip_tx_cnt + 2;
    
    ip_fifo_flag <= 0;
    ip_fifo_data <= TX_IP_DES[15:0];    // des ip address
    ip_fifo_we <= 1;

    ip_tx_st <= 23;
end
23:
begin
    if(ip_tx_cnt >= ip_tx_len)
    begin
        ip_fifo_we <= 0;
        ip_tx_st <= 24;
    end
    else
    begin
        udp_tx_addrb_sub <= udp_tx_addrb_sub + 1;
        ip_tx_cnt <= ip_tx_cnt + 2;
        
        ip_fifo_flag <= 0;
//        ip_fifo_data <= {udp_tx_doutb[7:0], udp_tx_doutb[15:8]};
        ip_fifo_data <= udp_tx_doutb;
        ip_fifo_we <= 1;
    end
end
24:
begin
    udp_tx_addrb_sub <=  {IP_BUF_SIZE{1'b1}};
    udp_tx_web <= 1;

    ip_fifo_flag <= 2'b11;
    ip_fifo_data <= 16'hffff;
    ip_fifo_we <= 1;
    
    ip_tx_st <= 25;
end
25:
begin
    udp_tx_web <= 0;
    ip_fifo_flag <= 0;
    ip_fifo_we <= 0;
    
    ip_tx_st <= 26;
end
26: // normal finished
begin
    udp_tx_idb <= udp_tx_idb + 1;
    udp_tx_web <= 0;
    
    ip_tx_st <= 0;
end
default: ip_tx_st <= 0;
endcase

//=========================================================================
// ip header checksum calculate
reg [2:0] ip_chk_st = 0;
always @ (posedge sys_clk)
if(!ip_chk_start)
begin
    ip_chk_end <= 0;
    ip_checksum <= 16'hc511; //4500 + 4000 + 4011
    ip_chk_st <= 0;
end
else case(ip_chk_st)
0:
begin
    ip_chk_end <= 0;
    ip_checksum <= ip_checksum + ip_tx_len;
    ip_chk_st <= 1;
end
1:
begin
    ip_checksum <= ip_checksum + TX_IP_SRC[31:16];
    ip_chk_st <= 2;
end
2:
begin
    ip_checksum <= ip_checksum + TX_IP_SRC[15:0];
    ip_chk_st <= 3;
end
3:
begin
    ip_checksum <= ip_checksum + TX_IP_DES[31:16];
    ip_chk_st <= 4;
end
4:
begin
    ip_checksum <= ip_checksum + TX_IP_DES[15:0];
    ip_chk_st <= 5;
end
5:
begin
    if(|ip_checksum[23:16])
        ip_checksum <= ip_checksum[15:0] + ip_checksum[23:16];
    else
    begin
        ip_checksum[15:0] <= ~ip_checksum[15:0];
        ip_chk_end <= 1;
        ip_chk_st <= 6;
    end
end
6:
begin
    ip_chk_end <= 1;
    ip_chk_st <= 6;
end
default: ip_chk_st <= 0;
endcase
//=========================================================================

endmodule

 

Posted in FPGA, FPGA 教材教案, RISC-V, Verilog, Verilog, 教材与教案, 文章

发表回复

相关链接