[米聯客-安路飛龍DR1-FPSOC] UDP通訊篇連載-08 模擬驗證

米联客(milianke)發表於2024-08-10

軟體版本:Anlogic -TD5.9.1-DR1_ES1.1

作業系統:WIN10 64bit

硬體平臺:適用安路(Anlogic)FPGA

實驗平臺:米聯客-MLK-L1-CZ06-DR1M90G開發板

板卡獲取平臺:https://milianke.tmall.com/

登入"米聯客"FPGA社群 http://www.uisrc.com 影片課程、答疑解惑!

4 模擬驗證

模擬程式碼的頂層如下:

`timescale 1ns / 1ps

module sim_top;

reg I_reset;

reg I_clk;

wire b_r_udp_valid;

wire [7 :0] b_r_udp_data;

wire [15:0] b_r_udp_data_len;

wire [15:0] b_r_udp_src_port;

wire O_a_ip_rx_error;

wire O_a_mac_rx_error;

wire O_b_ip_rx_error;

wire O_b_mac_rx_error;

test_udp_loop test_udp_loop_u(

.I_reset (I_reset),

.I_clk (I_clk),

.b_r_udp_valid (b_r_udp_valid),

.b_r_udp_data (b_r_udp_data),

.b_r_udp_data_len (b_r_udp_data_len),

.b_r_udp_src_port (b_r_udp_src_port),

.O_a_ip_rx_error (O_a_ip_rx_error),

.O_a_mac_rx_error (O_a_mac_rx_error),

.O_b_ip_rx_error (O_b_ip_rx_error),

.O_b_mac_rx_error (O_b_mac_rx_error)

);

initial begin

I_clk = 0;

I_reset = 1;

#2000;

I_reset = 0;

end

always #4 I_clk <= ~I_clk;

endmodule

4.1 資料通訊模擬

例化兩個UDP協議棧模組,分別為主機A和主機B,主機A將使用者端輸入的資料打包,透過GMII介面傳送給主機B,主機B將資料解包後輸出至使用者端,觀察各層的訊號變化。

4.1.1 模擬程式碼編寫

初始狀態機為WAIT_UDP_RDY,等待主機AO_W_udp_busy訊號為低時,使用者端將I_W_udp_req訊號拉高,狀態機進入WAIT_UDP_ACK狀態。待主機AO_W_udp_busy拉高時,使用者端將I_W_udp_req拉低,狀態機跳轉至SEND_DATA狀態,計數器開始計數,傳送的資料為計數器的低8位。當資料都傳送完畢時,狀態機跳回WAIT_UDP_RDY狀態,等待下一次資料的傳送。模擬程式碼如下:

`timescale 1ns / 1ps

module test_udp_loop(

input wire I_reset,

input wire I_clk,

output wire b_r_udp_valid,

output wire [7 :0] b_r_udp_data,

output wire [15:0] b_r_udp_data_len,

output wire [15:0] b_r_udp_src_port,

output wire O_a_ip_rx_error,

output wire O_a_mac_rx_error,

output wire O_b_ip_rx_error,

output wire O_b_mac_rx_error

);

wire a_w_udp_rdy;

reg a_w_udp_req;

reg a_w_udp_valid;

wire [7:0] a_w_udp_data;

reg [15:0] a_w_udp_len;

reg a_w_udp_data_read;

wire b_w_udp_rdy;

reg b_w_udp_req;

reg b_w_udp_valid;

wire [7:0] b_w_udp_data;

reg [15:0] b_w_udp_len;

reg b_w_udp_data_read;

wire a_r_udp_valid;

wire [7 :0] a_r_udp_data;

wire [15:0] a_r_udp_data_len;

wire [15:0] a_r_udp_src_port;

reg [9 :0] test_data;

reg [1 :0] STATE;

parameter WAIT_UDP_READY = 0;

parameter WAIT_UDP_ACK = 1;

parameter SEND_DATA = 2;

always@(posedge I_clk or posedge I_reset)begin

if(I_reset) begin

a_w_udp_req <= 1'b0;

a_w_udp_valid <= 1'b0;

a_w_udp_len <= 16'd0;

test_data <= 10'd0;

STATE <= WAIT_UDP_READY;

end

else begin

case(STATE)

WAIT_UDP_READY:begin

if(~a_w_udp_rdy) begin

a_w_udp_req <= 1'b1;

STATE <= WAIT_UDP_ACK;

end

else begin

a_w_udp_req <= 1'b0;

STATE <= WAIT_UDP_READY;

end

end

WAIT_UDP_ACK:begin

if(a_w_udp_rdy) begin

a_w_udp_len <= 16'd768;

a_w_udp_valid <= 1'b1;

a_w_udp_req <= 1'b0;

STATE <= SEND_DATA;

end

else

STATE <= WAIT_UDP_ACK;

end

SEND_DATA:begin

if(test_data == 10'd767) begin

a_w_udp_valid <= 1'b0;

a_w_udp_len <= 16'd0;

test_data <= 0;

STATE <= WAIT_UDP_READY;

end

else begin

a_w_udp_valid <= 1'b1;

test_data <= test_data + 1'b1;

STATE <= SEND_DATA;

end

end

endcase

end

end

//以下實現A傳送,B接收的模擬測試

wire [7:0] a_gmii_tdata;

wire a_gmii_tvalid;

wire [7:0] b_gmii_tdata;

wire b_gmii_tvalid;

assign a_w_udp_data = test_data[7:0];

udp_stack #

(

.CRC_GEN_EN (1'b1),

.INTER_FRAME_GAP (4'd12)

)

A_udp_stack

(

.I_uclk (I_clk),

.I_reset (I_reset),

.I_mac_local_addr (48'h0123456789a2),//本地MAC地址

.I_udp_local_port (16'd6002 ), //本地埠號

.I_ip_local_addr (32'hc0a88902 ), //本地ip地址

.I_udp_dest_port (16'd6001 ), //目的埠

.I_ip_dest_addr (32'hc0a88901 ), //目的IP地址

.O_W_udp_busy (a_w_udp_rdy),

.I_W_udp_req (a_w_udp_req),

.I_W_udp_valid (a_w_udp_valid),

.I_W_udp_data (a_w_udp_data),

.I_W_udp_len (a_w_udp_len),

.O_R_udp_valid (),

.O_R_udp_data (),

.O_R_udp_len (),

.O_R_udp_src_port (),

.I_gmii_rclk (I_clk),

.I_gmii_rvalid (b_gmii_tvalid),

.I_gmii_rdata (b_gmii_tdata),

.I_gmii_tclk (I_clk),

.O_gmii_tvalid (a_gmii_tvalid),

.O_gmii_tdata (a_gmii_tdata),

.O_ip_rerror (O_a_ip_rx_error),

.O_mac_rerror (O_a_mac_rx_error)

);

udp_stack #

(

.CRC_GEN_EN (1'b1),

.INTER_FRAME_GAP (4'd12)

)

B_udp_stack

(

.I_uclk (I_clk),

.I_reset (I_reset),

.I_mac_local_addr (48'h0123456789a1),//本地MAC地址

.I_udp_local_port (16'd6001 ), //本地埠號

.I_ip_local_addr (32'hc0a88901 ), //本地ip地址

.I_udp_dest_port (16'd6002 ), //目的埠

.I_ip_dest_addr (32'hc0a88902 ), //目的IP地址

.O_W_udp_busy (),

.I_W_udp_req (0),

.I_W_udp_valid (0),

.I_W_udp_data (0),

.I_W_udp_len (0),

.O_R_udp_valid (b_r_udp_valid),

.O_R_udp_data (b_r_udp_data),

.O_R_udp_len (b_r_udp_data_len),

.O_R_udp_src_port (b_r_udp_src_port),

.I_gmii_rclk (I_clk),

.I_gmii_rvalid (a_gmii_tvalid),

.I_gmii_rdata (a_gmii_tdata),

.I_gmii_tclk (I_clk),

.O_gmii_tvalid (b_gmii_tvalid),

.O_gmii_tdata (b_gmii_tdata),

.O_ip_rerror (O_b_ip_rx_error),

.O_mac_rerror (O_b_mac_rx_error)

);

endmodule

4.1.2 ARP請求模擬結果

主機A將資料打包傳送給主機B時,由於主機Acache中查詢不到主機BMAC地址,主機A會先傳送一個ARP請求包給主機B

當資料幀傳送至ip_arp_tx模組時,該模組向ARP層的cache傳送一個MAC地址查詢請求I_mac_cache_ren和需要查詢的IP地址I_mac_cache_rip_addr,查詢結束後O_mac_cache_rdone拉高,返回的MAC地址為48'h0,說明未查詢到MAC地址,ip_arp_tx模組將I_arp_treq_en拉高,準備傳送ARP廣播。arp_tx模組接收到I_arp_treq_en高電平時,傳送ARP請求O_arp_reqip_arp_tx模組將I_arp_busy拉高,表示握手成功,arp_tx模組開始組ARP廣播包。下圖為GMII介面傳送ARP廣播模擬波形圖。

最後訊號經過MAC層組幀後透過GMII介面傳送至主機B

4.1.3 ARP應答模擬結果

主機B接收到ARP請求包後,會將ARP包中的MAC地址解析,並將自己的MAC地址透過ARP應答包傳送給主機A。主機A收到ARP應答包後,將主機BMAC地址存入cache中。下圖為解包後傳送至arp_rx模組的資料。

MAC層解析資料的型別為ARP包,將該包資料透過ip_arp_rx模組傳送給arp_rx模組,解析出IP地址、MAC地址,並將該包識別為ARP請求包。arp_rx傳送arp_req_valid,訊號給arp_tx模組,請求傳送ARP應答包,同時將ARP請求包中的主機AMAC地址寫入cache中。arp_tx模組接收到應答請求並寄存,向ip_arp_tx模組傳送請求,ip_arp_tx模組將busy訊號拉高以表示握手成功。busy訊號為高後,arp_tx模組組ARP應答包,將本地MAC地址等資訊傳送至下層協議。

ARP層發出的應答資料包經MAC層組幀,透過GMII介面傳送至主機A。下圖為主機A GMII介面接收到的ARP請求包資料。

主機AMAC層識別資料為ARP資料包型別,傳送至arp_rx模組中,arp_rx模組解析對方傳送的IP地址和MAC地址,將MAC地址存入cache中。至此,地址解析完成,兩機之間可以完成正常資料通訊。

4.1.4 UDP傳送模擬結果

udp_tx模組與下層模組握手成功後,將資料透過移位暫存器延遲8個週期,組成UDP包,傳送至ip_tx模組,組成IP資料包,然後資料經ip_arp_tx模組仲裁,傳送至mac_tx模組,組成MAC包後透過GMII介面傳送。

下圖為UDP層組UDP包的模擬波形圖

下圖為IP層組IP包的模擬波形圖

由於資料都寫入了data_fifo,當資料有效資料全部寫入完成後,才會將資料讀出,所以圖中組的MAC包是上一個資料包正在傳送的資料包IP頭部的標識為16'h0000,而從上層傳入的IP資料包包頭標識為16'h0001

下圖為MAC層組MAC包的模擬波形圖

4.1.5 UDP接收模擬結果

主機BGMII介面接收到主機A傳送的資料包,會將資料先存入FIFO做跨時鐘域,當資料全部接收完成後,才會將資料讀出,圖中正在接收的資料包IP頭部標識為16'h0003,傳送至上層協議的資料包標識為16'h0002,即傳送至IP層的資料包為上一個幀。下圖為過濾MAC頭部的模擬波形圖

透過計數器去掉IP頭部和UDP頭部,最終得到有效資料,和傳送的資料一致,如圖所示。

4.2 PAUSE流控模擬

傳送資料的內容和速率與上一節的模擬中一致,每隔一定的時間,在使用者端組一個PAUSE幀傳送至主機A,暫停時間設定為16'h007F,即主機A實際暫停時間為8128個時鐘週期(7Fh << 6 = 8128d))。

4.2.1 模擬程式碼編寫

透過狀態機和計數器,控制PAUSE幀傳送到主機A的時序和間隔,同時不斷地向主機A的使用者端寫資料。模擬程式碼如下:

always@(posedge I_clk or posedge I_reset)begin

if(I_reset) begin

pause_data <= 8'd0;

pause_vld <= 1'b0;

cnt1 <= 'd0;

data_cnt <= 'd0;

STATE2 <= WAIT_PAUSE_RDY;

end

else begin

case(STATE2)

WAIT_PAUSE_RDY:begin

data_cnt <= 'd0;

if(cnt1 == 16'd5000) begin

cnt1 <= 'd0;

STATE2 <= SEND_PAUSE_DATA;

end

else begin

cnt1 <= cnt1 + 1'b1;

STATE2 <= WAIT_PAUSE_RDY;

end

end

SEND_PAUSE_DATA:begin

data_cnt <= data_cnt + 1'b1;

case(data_cnt)

0 :begin pause_data <= 8'h55; pause_vld <= 1'b1;end

1 :begin pause_data <= 8'h55;end

2 :begin pause_data <= 8'h55;end

3 :begin pause_data <= 8'h55;end

4 :begin pause_data <= 8'h55;end

5 :begin pause_data <= 8'h55;end

6 :begin pause_data <= 8'h55;end

7 :begin pause_data <= 8'hd5;end

8 :begin pause_data <= 8'h01;end

9 :begin pause_data <= 8'h80;end

10 :begin pause_data <= 8'hc2;end

11 :begin pause_data <= 8'h00;end

12 :begin pause_data <= 8'h00;end

13 :begin pause_data <= 8'h01;end//pause廣播地址

14 :begin pause_data <= 8'h01;end

15 :begin pause_data <= 8'h23;end

16 :begin pause_data <= 8'h45;end

17 :begin pause_data <= 8'h67;end

18 :begin pause_data <= 8'h89;end

19 :begin pause_data <= 8'ha1;end

20 :begin pause_data <= 8'h88;end

21 :begin pause_data <= 8'h08;end

22 :begin pause_data <= 8'h00;end

23 :begin pause_data <= 8'h01;end

24 :begin pause_data <= 8'h00;end

25 :begin pause_data <= 8'h7f;end

26 :begin pause_data <= 8'hff;end

27 :begin pause_data <= 8'hff;end

36 :begin pause_data <= 8'h15;end

37 :begin pause_data <= 8'hbf;end

38 :begin pause_data <= 8'h4b;end

39 :begin pause_data <= 8'h6c;end

40 :begin

pause_data <= 8'h00;

pause_vld <= 1'b0;

STATE2 <= WAIT_PAUSE_RDY;

end

default:pause_data <= 8'h00;

endcase

end

default: begin

pause_data <= 8'd0;

pause_vld <= 1'b0;

cnt1 <= 'd0;

data_cnt <= 'd0;

STATE2 <= WAIT_PAUSE_RDY;

end

endcase

end

end

4.2.2 PAUSE流控模擬結果

主機A接收到PAUSE幀後,會將PAUSE幀裡的資訊送入mac_tx_frame_ctrl模組中進行解析,得到暫停時間,併傳送給至mac_tx模組,如圖所示。

mac_tx模組中的讀狀態機進入幀間隔狀態時,透過計數器將pause_flag拉高一定的時間。檢測到下一幀傳送方的MAC地址與PAUSE幀傳送方的MAC地址相同,均為48'h0123456789a1,進入暫停狀態。

模擬波形圖如圖,由下圖可知,pause_flag拉高的時間為65024ns,即為8128個時鐘週期。

4.3 ICMP層模擬

向主機A傳送一個ping請求包,主機A成功接收到ping請求包後,傳送一個ping應答包,其中的額外資料與請求包相同。

4.3.1 模擬程式碼編寫

組一個ping請求包給主機A,其中IP頭部的協議型別為8'h01ICMP頭部的type欄位為8'h08code欄位為8'h00,表示主動請求。模擬程式碼如下:

4.3.2 ICMP回顯應答模擬結果

如圖所示,ip_rx模組接收到ICMP資料包文會將識別符號、序列號、校驗和等資訊拆解出來,並將有效資料存入FIFO。一幀資料接收完成後,將傳送ping應答請求訊號給ip_tx模組。

請求訊號icmp_req_en拉高後,icmp_pkg_tx模組中的icmp_pkg_req訊號也拉高,併傳送給ip_tx模組,等待ip_tx模組將icmp_pkg_req拉高,表示握手成功,開始傳送icmp回顯應答資料。ping應答包的type欄位為8'h00code欄位為8'h00,表示回顯應答,其有效資料和接收到的ping請求包額外資料保持一致。

相關文章