FPGA千兆網系列1-----ARP發送與接收(自動)

開發環境

  • 小梅哥AC6102開發板(內含RTL8211E千兆以太網phy芯片)
  • quartus prime17.1
  • win10
  • 千兆網卡 這個需要電腦支持,不支持就玩不了了
  • 本教程是根據小梅哥的百兆網arp教程改編過來的
    千兆網卡

GMII接口介紹

phy

  • gmii_tx_clk是由fpga輸出給phy的,注意方向,gmii_rx_clk則是phy輸出給fpga,所以我們系統時鐘就採用了gmii_rx_clk即可
    時鐘與復位
    全局時鐘
  • 由於系統時鐘採用了gmii_rx_clk,這個引腳並沒有連接到全局時鐘上,所以我們可以使用altclkctrl ip核,使該時鐘連接到全局時鐘上,即便這樣,系統時鐘到了125Mhz,頻率比較高,最好是要做一下時鐘的約束,我們只需要簡單了寫個clk的時序約束就可以了,告訴fpga我們的系統時鐘是125Mhz,然後他就會按這個頻率去優化時序的
    時序約束
  • 綁定引腳時,可以寫個引腳的配置文件,但是要注意總線也是要一個一個綁定的,如gmii_tx_data[0],gmii_tx_data[1]…千萬不要寫成了gmii_tx_data0,gmii_tx_data1…
    pin
  • 異步釋放,同步復位,避免復位引起亞穩態
    復位
//異步釋放,同步復位
always  @(posedge clk or negedge s_rst_n)begin
    if(s_rst_n==1'b0)begin
        rst_n_r <=  0;
    end
    else begin
        rst_n_r <=  {rst_n_r[0],1'b1};
    end
end
 
assign  rst_n   =   rst_n_r[1];
  • 以上是我自己遇到過的部分bug,如果實驗失敗了,首先要檢查時鐘是否有效,引腳是否綁定正確,時序是否違規。
    gmii
    gmii

以太網幀介紹

以太網幀

ARP幀介紹

ARP幀存在的目的

在網絡通訊時,源主機的應用程序知道目的主機的 IP 地址和端口號,卻不知道目的主機的硬件地址,
而數據包首先是被網卡接收到再去處理上層協議的,如果接收到的數據包的硬件地址與本機不符,則直接丟棄。
因此在通訊前必須獲得目的主機的硬件地址。 ARP 協議就起到這個作用。

ARP 幀工作原理

源主機發出 ARP 請求,詢問“IP 地址是 192.168.0.1 的主機的硬件地址是多少”,並將這
個請求廣播到本地網段(以太網幀首部的硬件地址填 FF:FF:FF:FF:FF:FF 表示廣播),目的主機
接收到廣播的 ARP 請求,發現其中的 IP 地址與本機相符,則發送一個 ARP 應答數據包給源
主機,將自己的硬件地址填寫在應答包中。
每臺主機都維護一個 ARP 緩存表,可以用 arp -a 命令查看。緩存表中的表項有過期時間
(一般爲 20 分鐘),如果 20 分鐘內沒有再次使用某個表項,則該表項失效,下次還要發 ARP
請求來獲得目的主機的硬件地址。想一想,爲什麼表項要有過期時間而不是一直有效?
ARP 數據報的格式如下圖所示(該圖出自[TCPIP]):

ARP數據報格式

使用以太網發包工具組ARP包

發包工具
arp
注意到源 MAC 地址、目的 MAC 地址在以太網首部和 ARP 請求中各出現一次,對於鏈路層爲以太網的情況
是多餘的,但如果鏈路層是其它類型的網絡則有可能是必要的。硬件類型指鏈路層網絡類型, 1 爲以太網,
協議類型指要轉換的地址類型, 0x0800 爲 IP 地址,後面兩個地址長度對於以太網地址和 IP 地址分別爲
6 和 4(字節), op 字段爲 1 表示 ARP 請求, op字段爲 2 表示 ARP 應答。
arp字段

發包

用wireshark軟件抓包

wireshark

用CRC計算軟件計算CRC校驗值

手動計算CRC

完整的以太網數據包結尾是幀校驗(FCS), 即 CRC32 值, 由於整個過程中都沒有出現
CRC 校驗字段的內容,而我們使用 FPGA 發包需要計算 CRC 校驗字段, CRC 校驗字段的產生
可以使用軟件或硬件的形式產生,本節實驗,爲了降低難度, 使用 CRC 計算軟件手動計算出
數據報的 CRC 值, 因此使用專用 CRC 校驗工具對數據內容進行計算以得到校驗字:
CRC 校驗軟件計算校驗內容
crc

第一次發的時候,我將arp中的des_mac默認爲00_00_00_00_00_00的,後面通過arp應答包,解析出des_mac的值後,crc就要做相應的更新,爲了方便,我是直接用crc計算校正值的,不同的電腦mac不一樣,所以需要自己計算一下。

always	@(posedge clk or negedge rst_n)begin
	if(rst_n == 1'b0)begin
		crc_value	<=	32'h967d1d69;
	end
	else begin
		crc_value	<=	32'h24495d2f;	//這個值要根據你們自己電腦的mac來計算
	end
end

自動計算CRC

自己看代碼研究一下吧,關鍵點是要時序對齊,注意下降沿採集的技巧(可提前半拍把crc送走,否則時序會出問題!!!),這個crc算法倒是不用過於深究,直接用就可以了。

/************************************************************************
 * Author        : Wen Chunyang
 * Email         : [email protected]
 * Create time   : 2018-11-19 22:27
 * Last modified : 2018-11-19 22:27
 * Filename      : crc.v
 * Description   : 
 * *********************************************************************/
module  crc(
    input                       clk                             ,
    input                       rst_n                           ,
    input         [ 7: 0]       din                             ,
    input                       en                              ,
    input                       init                            ,
    output  reg   [31: 0]       crc                             
);
//======================================================================\
//************** Define Parameter and Internal Signals *****************
//======================================================================/
wire    [ 7: 0]                 data                            ;
wire    [31: 0]                 crc_next                        ;
//======================================================================\
//**************************** Main Code *******************************
//======================================================================/
assign data={din[0],din[1],din[2],din[3],din[4],din[5],din[6],din[7]};

assign crc_next[0]  = crc[24] ^ crc[30] ^ data[0] ^ data[6];
assign crc_next[1]  = crc[24] ^ crc[25] ^ crc[30] ^ crc[31] ^ data[0] ^ data[1] ^ data[6] ^ data[7];
assign crc_next[2]  = crc[24] ^ crc[25] ^ crc[26] ^ crc[30] ^ crc[31] ^ data[0] ^ data[1] ^ data[2] ^ data[6] ^ data[7];
assign crc_next[3]  = crc[25] ^ crc[26] ^ crc[27] ^ crc[31] ^ data[1] ^ data[2] ^ data[3] ^ data[7];
assign crc_next[4]  = crc[24] ^ crc[26] ^ crc[27] ^ crc[28] ^ crc[30] ^ data[0] ^ data[2] ^ data[3] ^ data[4] ^ data[6];
assign crc_next[5]  = crc[24] ^ crc[25] ^ crc[27] ^ crc[28] ^ crc[29] ^ crc[30] ^ crc[31] ^ data[0] ^ data[1] ^ data[3] ^ data[4] ^ data[5] ^ data[6] ^ data[7];
assign crc_next[6]  = crc[25] ^ crc[26] ^ crc[28] ^ crc[29] ^ crc[30] ^ crc[31] ^ data[1] ^ data[2] ^ data[4] ^ data[5] ^ data[6] ^ data[7];
assign crc_next[7]  = crc[24] ^ crc[26] ^ crc[27] ^ crc[29] ^ crc[31] ^ data[0] ^ data[2] ^ data[3] ^ data[5] ^ data[7];
assign crc_next[8]  = crc[0]  ^ crc[24] ^ crc[25] ^ crc[27] ^ crc[28] ^ data[0] ^ data[1] ^ data[3] ^ data[4];
assign crc_next[9]  = crc[1]  ^ crc[25] ^ crc[26] ^ crc[28] ^ crc[29] ^ data[1] ^ data[2] ^ data[4] ^ data[5];
assign crc_next[10] = crc[2]  ^ crc[24] ^ crc[26] ^ crc[27] ^ crc[29] ^ data[0] ^ data[2] ^ data[3] ^ data[5];
assign crc_next[11] = crc[3]  ^ crc[24] ^ crc[25] ^ crc[27] ^ crc[28] ^ data[0] ^ data[1] ^ data[3] ^ data[4];
assign crc_next[12] = crc[4]  ^ crc[24] ^ crc[25] ^ crc[26] ^ crc[28] ^ crc[29] ^ crc[30] ^ data[0] ^ data[1] ^ data[2] ^ data[4] ^ data[5] ^ data[6];
assign crc_next[13] = crc[5]  ^ crc[25] ^ crc[26] ^ crc[27] ^ crc[29] ^ crc[30] ^ crc[31] ^ data[1] ^ data[2] ^ data[3] ^ data[5] ^ data[6] ^ data[7];
assign crc_next[14] = crc[6]  ^ crc[26] ^ crc[27] ^ crc[28] ^ crc[30] ^ crc[31] ^ data[2] ^ data[3] ^ data[4] ^ data[6] ^ data[7];
assign crc_next[15] = crc[7]  ^ crc[27] ^ crc[28] ^ crc[29] ^ crc[31] ^ data[3] ^ data[4] ^ data[5] ^ data[7];
assign crc_next[16] = crc[8]  ^ crc[24] ^ crc[28] ^ crc[29] ^ data[0] ^ data[4] ^ data[5];
assign crc_next[17] = crc[9]  ^ crc[25] ^ crc[29] ^ crc[30] ^ data[1] ^ data[5] ^ data[6];
assign crc_next[18] = crc[10] ^ crc[26] ^ crc[30] ^ crc[31] ^ data[2] ^ data[6] ^ data[7];
assign crc_next[19] = crc[11] ^ crc[27] ^ crc[31] ^ data[3] ^ data[7];
assign crc_next[20] = crc[12] ^ crc[28] ^ data[4];
assign crc_next[21] = crc[13] ^ crc[29] ^ data[5];
assign crc_next[22] = crc[14] ^ crc[24] ^ data[0];
assign crc_next[23] = crc[15] ^ crc[24] ^ crc[25] ^ crc[30] ^ data[0] ^ data[1] ^ data[6];
assign crc_next[24] = crc[16] ^ crc[25] ^ crc[26] ^ crc[31] ^ data[1] ^ data[2] ^ data[7];
assign crc_next[25] = crc[17] ^ crc[26] ^ crc[27] ^ data[2] ^ data[3];
assign crc_next[26] = crc[18] ^ crc[24] ^ crc[27] ^ crc[28] ^ crc[30] ^ data[0] ^ data[3] ^ data[4] ^ data[6];
assign crc_next[27] = crc[19] ^ crc[25] ^ crc[28] ^ crc[29] ^ crc[31] ^ data[1] ^ data[4] ^ data[5] ^ data[7];
assign crc_next[28] = crc[20] ^ crc[26] ^ crc[29] ^ crc[30] ^ data[2] ^ data[5] ^ data[6];
assign crc_next[29] = crc[21] ^ crc[27] ^ crc[30] ^ crc[31] ^ data[3] ^ data[6] ^ data[7];
assign crc_next[30] = crc[22] ^ crc[28] ^ crc[31] ^ data[4] ^ data[7];
assign crc_next[31] = crc[23] ^ crc[29] ^ data[5];

//crc 這裏用下降沿採集,是爲了crc能提前半拍送到eth_mac_send模塊中,這個很重要
//否則crc高8位會發送出錯,自己可以修改代碼試試看
always  @(negedge clk or negedge rst_n)begin
    if(rst_n == 1'b0)begin
        crc <=  {32{1'b1}};
    end
    else if(init)begin
        crc <=  {32{1'b1}};
    end
    else if(en)begin
        crc <=  crc_next;
    end
end


endmodule

發送與接收模塊設計

發送模塊

  • 首先是上電等待10ms,電壓穩定後,再去準備arp包,並且每隔1s發送一次arp包
/************************************************************************
 * Author        : Wen Chunyang
 * Email         : [email protected]
 * Create time   : 2018-11-16 22:20
 * Last modified : 2018-11-16 22:20
 * Filename      : eth_send_test.v
 * Description   : 
 * *********************************************************************/
module  eth_send(
        input                   clk                             ,
        input                   rst_n                           ,
        //Eth
        input         [47: 0]   des_mac                         ,
        input                   update                          ,
        output  wire            tx_trig                         ,
        output  wire  [31: 0]   crc                             ,
        output  reg   [ 9: 0]   wr_addr                         ,
        output  wire            wr_clk                          ,
        output  reg             wr_en                           ,
        output  reg   [ 7: 0]   wr_data 
);
//======================================================================\
//************** Define Parameter and Internal Signals *****************
//======================================================================/
parameter   DELAY_1S    =       27'd125_000_000                 ;
parameter   DELAY_10MS  =       25'd125_000_0                   ;
//cnt0
reg     [24: 0]                 cnt0                            ;
wire                            add_cnt0                        ;
wire                            end_cnt0                        ;
//cnt
reg     [27: 0]                 cnt                             ;
wire                            add_cnt                         ;
wire                            end_cnt                         ;
//cnt1
reg     [ 9: 0]                 cnt1                            ;
wire                            add_cnt1                        ;
wire                            end_cnt1                        ;

reg                             flag_wr                         ;
reg                             flag                            ;
reg     [31: 0]                 crc_value                       ;
//======================================================================\
//**************************** Main Code *******************************
//======================================================================/
assign  crc         =   {crc_value[7:0],crc_value[15:8],crc_value[23:16],crc_value[31:24]};

//crc_value 後續的會專門寫crc生成電路的,現在只是爲了簡單起見,比較剛剛入門
always  @(posedge clk or negedge rst_n)begin
    if(rst_n == 1'b0)begin
        crc_value   <=  32'h967D1D69;
    end
    else if(update)begin
        crc_value   <=  32'h24495D2F;
    end
end

//cnt0 上電後等待10ms,使電平穩定後
always @(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        cnt0 <= 0;
    end
    else if(add_cnt0)begin
        if(end_cnt0)
            cnt0 <= 0;
        else
            cnt0 <= cnt0 + 1;
    end
end

assign  add_cnt0        =       flag;       
assign  end_cnt0        =       add_cnt0 && cnt0 == DELAY_10MS-1;

//flag
always  @(posedge clk or negedge rst_n)begin
    if(rst_n == 1'b0)begin
        flag    <=  1'b1;
    end
    else if(end_cnt0)begin
        flag    <=  1'b0;
    end
end

//cnt 1s發送一次
always @(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        cnt <= 0;
    end
    else if(add_cnt)begin
        if(end_cnt)
            cnt <= 0;
        else
            cnt <= cnt + 1;
    end
end

assign  add_cnt     =       flag == 1'b0;       
assign  end_cnt     =       add_cnt && cnt == DELAY_1S-1;   

assign  tx_trig     =       end_cnt;

//cnt1 
always @(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        cnt1 <= 0;
    end
    else if(add_cnt1)begin
        if(end_cnt1)
            cnt1 <= 0;
        else
            cnt1 <= cnt1 + 1;
    end
end

assign  add_cnt1        =       flag_wr;       
assign  end_cnt1        =       add_cnt1 && cnt1 == 46-1;

//flag_wr
always  @(posedge clk or negedge rst_n)begin
    if(rst_n == 1'b0)begin
        flag_wr <=  1'b0;
    end
    else if(end_cnt0 || update)begin
        flag_wr <=  1'b1;
    end
    else if(end_cnt1)begin
        flag_wr <=  1'b0;
    end
end

//wr_en
always  @(posedge clk or negedge rst_n)begin
    if(rst_n == 1'b0)begin
        wr_en   <=  1'b0;
    end
    else begin
        wr_en   <=  flag_wr;
    end
end

//wr_addr
always  @(posedge clk or negedge rst_n)begin
    if(rst_n == 1'b0)begin
        wr_addr <=  10'd0;
    end
    else begin
        wr_addr <=  cnt1;
    end
end

//wr_clk
assign  wr_clk      =   clk;

//wr_data
always  @(posedge clk or negedge rst_n)begin
    if(rst_n == 1'b0)begin
        wr_data   <=  8'h00;
    end
    else if(flag_wr)begin
        case(cnt1)
            //hdwr_type
            00:wr_data    <=  8'h00;
            01:wr_data    <=  8'h01;
            //protocol_type
            02:wr_data    <=  8'h08;
            03:wr_data    <=  8'h00;
            //hdwr_size
            04:wr_data    <=  8'h06;
            //protocol_size
            05:wr_data    <=  8'h04;
            //opcode
            06:wr_data    <=  8'h00;
            07:wr_data    <=  8'h01;
            //sender_mac
            08:wr_data    <=  8'h00;
            09:wr_data    <=  8'h0a;
            10:wr_data    <=  8'h35;
            11:wr_data    <=  8'h01;
            12:wr_data    <=  8'hfe;
            13:wr_data    <=  8'hc0;
            //sender_ip
            14:wr_data    <=  8'd192;
            15:wr_data    <=  8'd168;
            16:wr_data    <=  8'd0;
            17:wr_data    <=  8'd2;
            //target_mac
            18:wr_data    <=  des_mac[47:40];
            19:wr_data    <=  des_mac[39:32];
            20:wr_data    <=  des_mac[31:24];
            21:wr_data    <=  des_mac[23:16];
            22:wr_data    <=  des_mac[15: 8];
            23:wr_data    <=  des_mac[ 7: 0];
            //target_ip
            24:wr_data    <=  8'd192;
            25:wr_data    <=  8'd168;
            26:wr_data    <=  8'd0;
            27:wr_data    <=  8'd3;
            //填充字段
            28:wr_data    <=  8'h00;
            29:wr_data    <=  8'h00;
            30:wr_data    <=  8'hff;
            31:wr_data    <=  8'hff;
            32:wr_data    <=  8'hff;
            33:wr_data    <=  8'hff;
            34:wr_data    <=  8'hff;
            35:wr_data    <=  8'hff;
            36:wr_data    <=  8'h00;
            37:wr_data    <=  8'h23;
            38:wr_data    <=  8'hcd;
            39:wr_data    <=  8'h76;
            40:wr_data    <=  8'h63;
            41:wr_data    <=  8'h1a;
            42:wr_data    <=  8'h08;
            43:wr_data    <=  8'h06;
            44:wr_data    <=  8'h00;
            45:wr_data    <=  8'h01;
            default:begin
                wr_data   <=  8'h00;
            end
        endcase
    end
end

endmodule

接收模塊

  • 接收模塊設計的比較簡單,因爲pc發送的arp應答包大小是固定的,我設計了一個計數器用來計數,以此來定位,然後我解析的標準是前導碼正確,幀分界符正確,fpga mac地址正確,arp應答包,這些都滿足,我就把pc的mac存下來,並且更新到des_mac變量中,用於下次fpga發arp中的des_mac中。這個模塊其實也可以用狀態機來實現。後續的udp教程應該會使用狀態機來做哦。
/************************************************************************
 * Author        : Wen Chunyang
 * Email         : [email protected]
 * Create time   : 2018-11-18 16:37
 * Last modified : 2018-11-18 16:37
 * Filename      : eth_receive.v
 * Description   : 
 * *********************************************************************/
module  eth_receive(
        input                   clk                             ,
        input                   rst_n                           ,
        //gmii
        input                   gmii_rx_dv                      ,
        input         [ 7: 0]   gmii_rx_data                    ,
        input                   gmii_rx_er                      ,
        output  reg             update                          ,
        output  reg   [47: 0]   des_mac 
);
//======================================================================\
//************** Define Parameter and Internal Signals *****************
//======================================================================/
reg     [ 6: 0]                 cnt                             ;
wire                            add_cnt                         ;
wire                            end_cnt                         ;
reg                             preamble_ok                     ;
reg                             frame_start                     ;
reg     [47: 0]                 src_mac                         ;
reg     [47: 0]                 des_mac_tmp                     ;
reg                             src_mac_ok                      ;
reg     [15: 0]                 eth_type                        ;
reg                             is_arp                          ;
reg     [15: 0]                 opcode                          ;
reg                             opcode_ack                      ;
//======================================================================\
//**************************** Main Code *******************************
//======================================================================/
//cnt
always @(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        cnt <= 0;
    end
    else if(add_cnt)begin
        if(end_cnt)
            cnt <= 0;
        else
            cnt <= cnt + 1;
    end
    else begin
    	cnt <= 0;
    end
end

assign  add_cnt     =       gmii_rx_dv && (gmii_rx_er == 1'b0);       
assign  end_cnt     =       add_cnt && cnt == 72-1;   

//preamble_ok
always  @(posedge clk or negedge rst_n)begin
    if(rst_n == 1'b0)begin
        preamble_ok <=  1'd0;
    end
    else if(add_cnt && (cnt <= 7-1) && (gmii_rx_data == 8'h55))begin
        preamble_ok <=  1'b1;
    end
    else begin
        preamble_ok <=  1'b0;
    end
end

//frame_start
always  @(posedge clk or negedge rst_n)begin
    if(rst_n == 1'b0)begin
        frame_start <=  1'b0;
    end
    else if(preamble_ok && add_cnt && (cnt == 8-1) && (gmii_rx_data == 8'hd5))begin
        frame_start <=  1'b1;
    end
    else if(end_cnt)begin
        frame_start <=  1'b0;
    end
end

//src_mac fpga的mac地址 
always  @(posedge clk or negedge rst_n)begin
    if(rst_n == 1'b0)begin
        src_mac <=  48'd0;
    end
    else if(frame_start && add_cnt && (cnt >= 9-1) && (cnt <= 14-1))begin
        src_mac <=  {src_mac[39:0],gmii_rx_data};
    end
    else if(end_cnt)begin
        src_mac <=  48'd0;
    end
end

//src_mac_ok
always  @(posedge clk or negedge rst_n)begin
    if(rst_n == 1'b0)begin
        src_mac_ok  <=  1'b0;
    end
    else if(add_cnt && (cnt == 15-1) && (src_mac == 48'h00_0a_35_01_fe_c0))begin
        src_mac_ok  <=  1'b1;
    end
    else if(end_cnt)begin
        src_mac_ok  <=  1'b0;
    end
end

//eth_type
always  @(posedge clk or negedge rst_n)begin
    if(rst_n == 1'b0)begin
        eth_type    <=  16'd0;
    end
    else if(src_mac_ok && add_cnt && (cnt >= 21-1) && (cnt <= 22-1))begin
        eth_type    <=  {eth_type[7:0],gmii_rx_data};
    end
    else if(end_cnt)begin
        eth_type    <=  16'd0;
    end
end

//is_arp
always  @(posedge clk or negedge rst_n)begin
    if(rst_n == 1'b0)begin
        is_arp  <=  1'b0;
    end
    else if(src_mac_ok && add_cnt && (cnt == 23-1) && (eth_type == 16'h0806))begin
        is_arp  <=  1'b1;
    end
    else if(end_cnt)begin
        is_arp  <=  1'b0;
    end
end

//opcode
always  @(posedge clk or negedge rst_n)begin
    if(rst_n == 1'b0)begin
        opcode  <=  16'd0;
    end
    else if(is_arp && add_cnt && (cnt >= 29-1) && (cnt <= 30-1))begin
        opcode  <=  {opcode[7:0],gmii_rx_data};
    end
    else if(end_cnt)begin
        opcode  <=  16'd0;
    end
end

//opcode_ack
always  @(posedge clk or negedge rst_n)begin
    if(rst_n == 1'b0)begin
        opcode_ack  <=  1'b0;
    end
    else if(add_cnt && (cnt == 31-1) && (opcode == 16'h0002))begin
        opcode_ack  <=  1'b1;
    end
    else if(end_cnt)begin
        opcode_ack  <=  1'b0;
    end
end

//des_mac_tmp
always  @(posedge clk or negedge rst_n)begin
    if(rst_n == 1'b0)begin
        des_mac_tmp <=  48'd0;
    end
    else if(add_cnt && (cnt >= 31-1) && (cnt <= 36-1))begin
        des_mac_tmp <=  {des_mac_tmp[39:0],gmii_rx_data};
    end
end

//des_mac
always  @(posedge clk or negedge rst_n)begin
    if(rst_n == 1'b0)begin
        des_mac <=  48'd0;
    end
    else if(opcode_ack && add_cnt && (cnt == 37-1))begin
        des_mac <=  des_mac_tmp;
    end
end

//update
always  @(posedge clk or negedge rst_n)begin
    if(rst_n == 1'b0)begin
        update  <=  1'b0;
    end
    else if(opcode_ack)begin
        update  <=  end_cnt;
    end
end

endmodule

調試

發送

發送

接收

接收

自動CRC

CRC

wireshark

wireshark

福利

爲了能及時回覆大家,現在獲取源碼方式如下:
微信掃描下面的二維碼關注【春哥筆記】公衆號,回覆“arp”即可Get源碼的獲取方式:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章