56,Verilog-2005标准篇:UDP端口声明

UDP应包含输入和输出端口声明。输出端口声明以关键字output开头,后面跟一个输出端口名称。输入端口声明以关键字input开头,后面跟一个或多个输入端口名称。

时序式 UDP 应包含输出端口的 reg 声明,组合式UDP 不能包含 reg 声明。输出端口的reg初始值可在时序式UDP 的初始语句中指定。时序式UDP初始语句指定仿真开始时输出端口的reg值。该语句以关键字initial开始,随后的语句应为赋值语句,为输出端口分配一个单比特值。

虽然UDP 的最大输入端口数量受到一定限制,但verilog规定必须允许时序式 UDP 至少能容纳9 个输入端口数量,组合式UDP至少能容纳10个输入端口数量。

点赞加关注博主(ID:FPGA小飞)的博文,咱们一起系统学习verilog最终标准IEEE Std 1364-2005吧!

`timescale 1ns / 1ps module tb_fpga_core_udp; // clocks & resets reg clk = 0; reg rst = 1; reg qsfp_tx_clk_1 = 0; reg qsfp_rx_clk_1 = 0; reg qsfp_tx_rst_1 = 1; reg qsfp_rx_rst_1 = 1; // XGMII inputs to DUT (default idle) reg [63:0] qsfp_rxd_1 = 64'h0707070707070707; reg [7:0] qsfp_rxc_1 = 8'hFF; // XGMII outputs from DUT wire [63:0] qsfp_txd_1; wire [7:0] qsfp_txc_1; // other lanes idle reg qsfp_tx_clk_2 = 0, qsfp_rx_clk_2 = 0, qsfp_tx_rst_2 = 1, qsfp_rx_rst_2 = 1; reg [63:0] qsfp_rxd_2 = 64'h0707070707070707; reg [7:0] qsfp_rxc_2 = 8'hFF; wire [63:0] qsfp_txd_2; wire [7:0] qsfp_txc_2; reg qsfp_tx_clk_3 = 0, qsfp_rx_clk_3 = 0, qsfp_tx_rst_3 = 1, qsfp_rx_rst_3 = 1; reg [63:0] qsfp_rxd_3 = 64'h0707070707070707; reg [7:0] qsfp_rxc_3 = 8'hFF; wire [63:0] qsfp_txd_3; wire [7:0] qsfp_txc_3; reg qsfp_tx_clk_4 = 0, qsfp_rx_clk_4 = 0, qsfp_tx_rst_4 = 1, qsfp_rx_rst_4 = 1; reg [63:0] qsfp_rxd_4 = 64'h0707070707070707; reg [7:0] qsfp_rxc_4 = 8'hFF; wire [63:0] qsfp_txd_4; wire [7:0] qsfp_txc_4; reg [7:0] pkt [0:63]; // 156.25 MHz clocks always #3.2 clk = ~clk; always #3.2 qsfp_tx_clk_1 = ~qsfp_tx_clk_1; always #3.2 qsfp_rx_clk_1 = ~qsfp_rx_clk_1; // DUT fpga_core UUT ( .clk(clk), .rst(rst), .qsfp_tx_clk_1(qsfp_tx_clk_1), .qsfp_tx_rst_1(qsfp_tx_rst_1), .qsfp_txd_1(qsfp_txd_1), .qsfp_txc_1(qsfp_txc_1), .qsfp_rx_clk_1(qsfp_rx_clk_1), .qsfp_rx_rst_1(qsfp_rx_rst_1), .qsfp_rxd_1(qsfp_rxd_1), .qsfp_rxc_1(qsfp_rxc_1), .qsfp_tx_clk_2(qsfp_tx_clk_2), .qsfp_tx_rst_2(qsfp_tx_rst_2), .qsfp_txd_2(qsfp_txd_2), .qsfp_txc_2(qsfp_txc_2), .qsfp_rx_clk_2(qsfp_rx_clk_2), .qsfp_rx_rst_2(qsfp_rx_rst_2), .qsfp_rxd_2(qsfp_rxd_2), .qsfp_rxc_2(qsfp_rxc_2), .qsfp_tx_clk_3(qsfp_tx_clk_3), .qsfp_tx_rst_3(qsfp_tx_rst_3), .qsfp_txd_3(qsfp_txd_3), .qsfp_txc_3(qsfp_txc_3), .qsfp_rx_clk_3(qsfp_rx_clk_3), .qsfp_rx_rst_3(qsfp_rx_rst_3), .qsfp_rxd_3(qsfp_rxd_3), .qsfp_rxc_3(qsfp_rxc_3), .qsfp_tx_clk_4(qsfp_tx_clk_4), .qsfp_tx_rst_4(qsfp_tx_rst_4), .qsfp_txd_4(qsfp_txd_4), .qsfp_txc_4(qsfp_txc_4), .qsfp_rx_clk_4(qsfp_rx_clk_4), .qsfp_rx_rst_4(qsfp_rx_rst_4), .qsfp_rxd_4(qsfp_rxd_4), .qsfp_rxc_4(qsfp_rxc_4) ); // ----------------------------- // // ----------------------------- integer f_xgmii, f_axis; initial begin f_xgmii = $fopen("xgmii_rx_log.txt","w"); if (!f_xgmii) begin $display("ERROR: cannot open xgmii_rx_log.txt"); $stop; end f_axis = $fopen("axis_rx_log.txt","w"); if (!f_axis) begin $display("ERROR: cannot open axis_rx_log.txt"); $stop; end end always @(posedge qsfp_rx_clk_1) begin $fwrite(f_xgmii, "%0t ns | rxc=%02x rxd=%016h\n", $time, qsfp_rxc_1, qsfp_rxd_1); end // // always @(posedge clk) begin $fwrite(f_axis, "%0t ns | tvalid=%b tready=%b tlast=%b tuser=%b tkeep=%02x tdata=%016h\n", $time, UUT.rx_axis_tvalid, UUT.rx_axis_tready, UUT.rx_axis_tlast, UUT.rx_axis_tuser, UUT.rx_axis_tkeep, UUT.rx_axis_tdata); end // ----------------------------- // IPv4 header checksum( // ----------------------------- task automatic ipv4_header_checksum_calc; inout [7:0] pkt [0:63]; integer j; integer sum; begin sum = 0; pkt[24] = 8'h00; pkt[25] = 8'h00; // 先清零 for (j = 14; j < 34; j = j+2) begin sum = sum + {pkt[j], pkt[j+1]}; end // 折返進位 while (sum >> 16) sum = (sum & 16'hFFFF) + (sum >> 16); sum = ~sum & 16'hFFFF; pkt[24] = sum[15:8]; pkt[25] = sum[7:0]; end endtask // ----------------------------- // UDP over IPv4 // ----------------------------- task automatic send_udp_frame; integer i; integer payload_len; integer ip_tot_len; integer udp_len; integer length; // 整個 Ethernet payload 長度(IP header + UDP header + payload) integer rem; // 最後一拍剩餘 bytes reg [63:0] w; reg [7:0] c; begin // for (i = 0; i < 64; i = i+1) pkt[i] = 8'h00; // Ethernet header {pkt[0],pkt[1],pkt[2],pkt[3],pkt[4],pkt[5]} = 48'h02_00_00_00_00_00; // Dst MAC {pkt[6],pkt[7],pkt[8],pkt[9],pkt[10],pkt[11]} = 48'h5A_51_52_53_54_55; // Src MAC pkt[12] = 8'h08; pkt[13] = 8'h00; // Ethertype IPv4 // Payload payload_len = 4; pkt[42] = "H"; pkt[43] = "I"; pkt[44] = "!"; pkt[45] = 8'h00; // IPv4 header ip_tot_len = 20 + 8 + payload_len; // IP header (20) + UDP header (8) + payload pkt[14] = 8'h45; pkt[15] = 8'h00; // Version/IHL, DSCP/ECN pkt[16] = ip_tot_len[15:8]; pkt[17] = ip_tot_len[7:0]; // Total length pkt[18] = 8'h00; pkt[19] = 8'h01; // ID pkt[20] = 8'h00; pkt[21] = 8'h00; // Flags/Fragment pkt[22] = 8'h40; pkt[23] = 8'h11; // TTL=64, Protocol=UDP(17) pkt[24] = 8'h00; pkt[25] = 8'h00; // Header checksum (先清零,待計算) pkt[26] = 8'hC0; pkt[27] = 8'hA8; pkt[28] = 8'h01; pkt[29] = 8'h01; // Src IP 192.168.1.1 pkt[30] = 8'hC0; pkt[31] = 8'hA8; pkt[32] = 8'h01; pkt[33] = 8'h80; // Dst IP 192.168.1.128 // UDP header udp_len = 8 + payload_len; pkt[34] = 8'h04; pkt[35] = 8'hD2; // Src port 1234 pkt[36] = 8'h04; pkt[37] = 8'hD2; // Dst port 1234 pkt[38] = udp_len[15:8]; pkt[39] = udp_len[7:0]; // UDP length pkt[40] = 8'h00; pkt[41] = 8'h00; // UDP checksum=0(允許) // ipv4_header_checksum_calc(pkt); // Ethernet payload length = 14 + ip_tot_len - 14; // 就是 ip_tot_len(Ethernet payload=IP封包) length = 20 + 8 + payload_len; // 等同 ip_tot_len,保險起見再指定 // ==================== //+ 6x55 + D5 qsfp_rxd_1 <= {8'hD5, 8'h55, 8'h55, 8'h55, 8'h55, 8'h55, 8'h55, 8'hFB}; qsfp_rxc_1 <= 8'b00000001; // lane0 control @(posedge qsfp_rx_clk_1); // i = 0; while (length - i >= 8) begin qsfp_rxd_1 <= {pkt[i+7], pkt[i+6], pkt[i+5], pkt[i+4], pkt[i+3], pkt[i+2], pkt[i+1], pkt[i]}; qsfp_rxc_1 <= 8'h00; i = i + 8; @(posedge qsfp_rx_clk_1); end //rem bytes + Terminate + Idle rem = length - i; w = 64'h0707070707070707; // c = 8'hFF; // case (rem) 0: begin w[7:0] = 8'hFD; // lane0 terminate end 1: begin w[7:0] = pkt[i]; w[15:8] = 8'hFD; c = 8'b11111110; end 2: begin w[7:0] = pkt[i]; w[15:8] = pkt[i+1]; w[23:16] = 8'hFD; c = 8'b11111100; end 3: begin w[7:0] = pkt[i]; w[15:8] = pkt[i+1]; w[23:16] = pkt[i+2]; w[31:24] = 8'hFD; c = 8'b11111000; end 4: begin w[7:0] = pkt[i]; w[15:8] = pkt[i+1]; w[23:16] = pkt[i+2]; w[31:24] = pkt[i+3]; w[39:32] = 8'hFD; c = 8'b11110000; end 5: begin w[7:0] = pkt[i]; w[15:8] = pkt[i+1]; w[23:16] = pkt[i+2]; w[31:24] = pkt[i+3]; w[39:32] = pkt[i+4]; w[47:40] = 8'hFD; c = 8'b11100000; end 6: begin w[7:0] = pkt[i]; w[15:8] = pkt[i+1]; w[23:16] = pkt[i+2]; w[31:24] = pkt[i+3]; w[39:32] = pkt[i+4]; w[47:40] = pkt[i+5]; w[55:48] = 8'hFD; c = 8'b11000000; end 7: begin w[7:0] = pkt[i]; w[15:8] = pkt[i+1]; w[23:16] = pkt[i+2]; w[31:24] = pkt[i+3]; w[39:32] = pkt[i+4]; w[47:40] = pkt[i+5]; w[55:48] = pkt[i+6]; w[63:56] = 8'hFD; c = 8'b10000000; end endcase qsfp_rxd_1 <= w; qsfp_rxc_1 <= c; @(posedge qsfp_rx_clk_1); // Idle qsfp_rxd_1 <= 64'h0707070707070707; qsfp_rxc_1 <= 8'hFF; @(posedge qsfp_rx_clk_1); qsfp_rxd_1 <= 64'h0707070707070707; qsfp_rxc_1 <= 8'hFF; @(posedge qsfp_rx_clk_1); end endtask // ----------------------------- // Test sequence // ----------------------------- initial begin // 上電:保持 reset rst = 1; qsfp_rx_rst_1 = 1; qsfp_tx_rst_1 = 1; // repeat (10) @(posedge clk); rst = 0; // //XGMII resets repeat (4) @(posedge qsfp_rx_clk_1); qsfp_rx_rst_1 = 0; repeat (4) @(posedge qsfp_tx_clk_1); qsfp_tx_rst_1 = 0; // repeat (200) @(posedge qsfp_rx_clk_1); // // wait (UUT.rx_axis_tready === 1'b1); // send_udp_frame(); // repeat (2000) @(posedge clk); // $fclose(f_xgmii); $fclose(f_axis); $stop; end endmodule 這個模組有哪裡需要改進的嗎
09-06
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值