top.v 是整个网络综合实验工程的顶层模块,如图1所示。在这个模块里例化了PLL时钟模块IP核,和网络综合实验的核心模块ETH_CORE.v。
图1 top.v模块
代码如下:
`timescale 1ns / 1ps module top # ( parameter MAC_TX_CRC_EN = 1, // 0: MAC DON'T CALC CRC; 1: MAC CALC CRC parameter [47:0] TX_MAC_SRC = 48'h46_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'hc0a800a8, parameter [15:0] UDP_TX_SRC_PORT = 10000, parameter [15:0] UDP_TX_DES_PORT = 10000, parameter UDP_TX_CHECKSUM_EN = 1, // 0: UDP checksum = 16'h0000; 1: calc checksum parameter [31:0] RX_IP_SRC = 32'hc0a800a8, parameter RX_IP_SRC_EN = 1, // 0: don't check src ip address; 1: check src ip address parameter [31:0] RX_IP_DES = 32'hc0a8003d, parameter RX_IP_DES_EN = 1, // 0: don't check des ip address; 1: check des ip address parameter [15:0] UDP_RX_SRC_PORT = 10000, parameter UDP_RX_SRC_PORT_EN = 1, // 0: don't check udp src port; 1: check udp src port parameter [15:0] UDP_RX_DES_PORT = 10000, parameter UDP_RX_DES_PORT_EN = 1, // 0: don't check udp des port; 1: check udp des port parameter MAIN_CLK = 125, parameter PHY_SPEED = "AUTO" // "AUTO", "1G", "100M", "10M" ) ( input OSC_CLK, output E_MDC, inout E_MDIO, input E_RXC, input E_RXDV, input [3:0] E_RXD, output E_TXC, //以太网发送时钟 output E_TXEN, //发送使能 output [3:0] E_TXD, //发送数据 output ETH_RSTN, input ETH_IRQ, // input [7:0] SW, output [7:0] LED //发送指示灯 ); //========================================================================= //时钟模块 wire locked; wire clk_200m; wire clk_125m; wire clk_125m_90; MMCM SYS_DCM_inst ( // Clock in ports .clk_in1 (OSC_CLK), // Clock out ports .clk_out1 (clk_200m), // 200M .clk_out2 (clk_125m), // 125M .clk_out3 (clk_125m_90), // 125M // Status and control signals .reset (1'b0), // input reset .locked (locked) // output locked ); wire sys_clk = clk_125m; wire ref_clk = clk_200m; reg locked_r = 0; always @ (posedge sys_clk) locked_r <= locked; reg [7:0] lock_cnt = 0; reg reset = 1; always @ (posedge sys_clk) if(!locked_r) begin lock_cnt <= 0; reset <= 1; end else begin if(&lock_cnt) reset <= 0; else lock_cnt <= lock_cnt + 1; end wire sys_rst_n = ~reset; //========================================================================= wire e_mdio_i; wire e_mdio_o; wire e_mdio_t; IOBUF #( .SLEW("SLOW") // Specify the output slew rate ) mdio_inst ( .O (e_mdio_i), // Buffer output .IO (E_MDIO), // Buffer inout port (connect directly to top-level port) .I (e_mdio_o), // Buffer input .T (e_mdio_t) // 3-state enable input, high=input, low=output ); wire [7:0] udp_dout; wire udp_dout_en; wire [7:0] udp_din = udp_dout; wire udp_din_vld = udp_dout_en; wire [2:0] eth_speed; ETH_CORE # ( // TX .MAC_TX_CRC_EN (MAC_TX_CRC_EN), .TX_MAC_SRC (TX_MAC_SRC), .TX_MAC_DES (TX_MAC_DES), .TX_IP_SRC (TX_IP_SRC), .TX_IP_DES (TX_IP_DES), .UDP_TX_SRC_PORT (UDP_TX_SRC_PORT), .UDP_TX_DES_PORT (UDP_TX_DES_PORT), .UDP_TX_CHECKSUM_EN (UDP_TX_CHECKSUM_EN), // RX .RX_IP_SRC (RX_IP_SRC), .RX_IP_SRC_EN (RX_IP_SRC_EN), .RX_IP_DES (RX_IP_DES), .RX_IP_DES_EN (RX_IP_DES_EN), .UDP_RX_SRC_PORT (UDP_RX_SRC_PORT), .UDP_RX_SRC_PORT_EN (UDP_RX_SRC_PORT_EN), .UDP_RX_DES_PORT (UDP_RX_DES_PORT), .UDP_RX_DES_PORT_EN (UDP_RX_DES_PORT_EN), .MAIN_CLK (MAIN_CLK), // 125m sys_clk .PHY_SPEED (PHY_SPEED) // "AUTO", "1G", "100M", "10M" ) ETH_CORE_inst ( .ref_clk (ref_clk), .E_RXC (E_RXC), .E_RXDV (E_RXDV), .E_RXD (E_RXD), .E_TXC (E_TXC), //以太网发送时钟 .E_TXEN (E_TXEN), //发送使能 .E_TXD (E_TXD), //发送数据 // sys clk .sys_clk (sys_clk), .e_mdc (E_MDC), .e_mdio_i (e_mdio_i), .e_mdio_o (e_mdio_o), .e_mdio_t (e_mdio_t), .eth_speed (eth_speed), .udp_din (udp_din), .udp_din_vld(udp_din_vld), .udp_din_rdy(udp_din_rdy), .udp_dout (udp_dout), .udp_dout_en(udp_dout_en), .reset (reset) ); reg [31:0] led_cnt; always @ (posedge sys_clk or posedge reset) if(reset) led_cnt <= 0; else led_cnt <= led_cnt + 1; reg [2:0] eth_speed_r = 0; always @ (posedge sys_clk or posedge reset) if(reset) eth_speed_r <= 0; else eth_speed_r <= ~eth_speed; assign LED[0] = 1; assign LED[1] = led_cnt[25]; assign LED[4:2] = 3'b111; assign LED[7:5] = eth_speed_r; assign ETH_RSTN = 1'b1; //========================================================================= endmodule
注意从top.v传递了很多参数到下层模块:
parameter MAC_TX_CRC_EN = 1, // 0: MAC DON’T CALC CRC; 1: MAC CALC CRC
parameter [47:0] TX_MAC_SRC = 48’h46_72_61_73_65_73, //源MAC地址
parameter [47:0] TX_MAC_DES = 48’hff_ff_ff_ff_ff_ff, //目的MAC地址
//发送相关参数
parameter [31:0] TX_IP_SRC = 32’hc0a8003e, //源IP地址(这里指FPGA)
parameter [31:0] TX_IP_DES = 32’hc0a8002e, //目的IP地址(这里指主机)
parameter [15:0] UDP_TX_SRC_PORT = 10000, //源端口(这里指FPGA)
parameter [15:0] UDP_TX_DES_PORT = 10000, //目的端口(这里指主机)
parameter UDP_TX_CHECKSUM_EN = 1, // 0: UDP checksum = 16’h0000; 1: calc checksum
//接收相关参数
parameter [31:0] RX_IP_SRC = 32’hc0a8002e, //源IP地址(这里指主机)
parameter RX_IP_SRC_EN = 1, // 0: don’t check src ip address; 1: check src ip address
parameter [31:0] RX_IP_DES = 32’hc0a8003e, //目的IP地址(这里指FPGA)
parameter RX_IP_DES_EN = 1, // 0: don’t check des ip address; 1: check des ip address
parameter [15:0] UDP_RX_SRC_PORT = 10000, //源端口(这里指主机)
parameter UDP_RX_SRC_PORT_EN = 1, // 0: don’t check udp src port; 1: check udp src port
parameter [15:0] UDP_RX_DES_PORT = 10000, //目的端口(这里指FPGA)
parameter UDP_RX_DES_PORT_EN = 1, // 0: don’t check udp des port; 1: check udp des port
parameter MAIN_CLK = 125, //时钟主频,单位是MHz
parameter PHY_SPEED = “AUTO” // “AUTO”, “1G”, “100M”, “10M”
ETH_CORE.v是网络综合实验的核心模块,如图2所示。例化了ETH_UDP.v,ETH_IP.v,ETH_MAC.v 和eth_phy_core.v四个模块。其代码如下:
图2 ETH_CORE.v模块
`timescale 1ns / 1ps module ETH_CORE # ( // TX parameter MAC_TX_CRC_EN = 1, 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 [15:0] UDP_TX_SRC_PORT = 16'hffff, parameter [15:0] UDP_TX_DES_PORT = 16'hffff, parameter UDP_TX_CHECKSUM_EN = 0, // RX parameter [31:0] RX_IP_SRC = 32'hc0a8003d, parameter RX_IP_SRC_EN = 0, parameter [31:0] RX_IP_DES = 32'hc0a800ff, parameter RX_IP_DES_EN = 0, parameter [15:0] UDP_RX_SRC_PORT = 16'hffff, parameter UDP_RX_SRC_PORT_EN = 0, parameter [15:0] UDP_RX_DES_PORT = 16'hffff, parameter UDP_RX_DES_PORT_EN = 0, parameter MAIN_CLK = 125, parameter PHY_SPEED = "AUTO" // "AUTO", "1G", "100M", "10M" ) ( input ref_clk, input E_RXC, input E_RXDV, input [3:0] E_RXD, output E_TXC, //以太网发送时钟 output E_TXEN, //发送使能 output [3:0] E_TXD, //发送数据 input sys_clk, output e_mdc, input e_mdio_i, output e_mdio_o, output e_mdio_t, output [2:0] eth_speed, input [7:0] udp_din, input udp_din_vld, output udp_din_rdy, (* mark_debug = "true" *) output [7:0] udp_dout, (* mark_debug = "true" *) output udp_dout_en, input reset ); //========================================================================= localparam IP_BUF_SIZE = 10; localparam IP_IDX_BIT = 1; //========================================================================= wire udp_tx_wea; wire [IP_BUF_SIZE + IP_IDX_BIT - 1:0] udp_tx_addra; wire [15:0] udp_tx_dina; wire [15:0] udp_tx_douta; wire udp_rx_web; wire [IP_BUF_SIZE + IP_IDX_BIT - 1:0] udp_rx_addrb; wire [15:0] udp_rx_doutb; (* mark_debug = "true" *)wire [4:0] udp_error; ETH_UDP # ( .TX_IP_SRC (TX_IP_SRC), .TX_IP_DES (TX_IP_DES), .UDP_TX_SRC_PORT (UDP_TX_SRC_PORT), .UDP_TX_DES_PORT (UDP_TX_DES_PORT), .UDP_TX_CHECKSUM_EN (UDP_TX_CHECKSUM_EN), .UDP_RX_SRC_PORT (UDP_RX_SRC_PORT), .UDP_RX_SRC_PORT_EN (UDP_RX_SRC_PORT_EN), .UDP_RX_DES_PORT (UDP_RX_DES_PORT), .UDP_RX_DES_PORT_EN (UDP_RX_DES_PORT_EN), .IP_BUF_SIZE (IP_BUF_SIZE), .IP_IDX_BIT (IP_IDX_BIT) ) ETH_UDP_inst ( .sys_clk (sys_clk), // tx .udp_din (udp_din), .udp_din_vld (udp_din_vld), .udp_din_rdy (udp_din_rdy), .udp_tx_wea (udp_tx_wea), .udp_tx_addra (udp_tx_addra), .udp_tx_dina (udp_tx_dina), .udp_tx_douta (udp_tx_douta), // rx .udp_rx_web (udp_rx_web), .udp_rx_addrb (udp_rx_addrb), .udp_rx_doutb (udp_rx_doutb), .udp_dout (udp_dout), .udp_dout_en (udp_dout_en), .udp_error (udp_error), .reset (reset) ); //========================================================================= localparam MAC_TXBUF_SIZE = IP_BUF_SIZE + 1; localparam MAC_TXIDX_BIT = IP_IDX_BIT; //========================================================================= wire [17:0] ip_fifo_din; wire ip_fifo_we; wire [15:0] ip_fifo_cnt; wire ip_rx_web; wire [IP_BUF_SIZE + IP_IDX_BIT - 1:0] ip_rx_addrb; wire [15:0] ip_rx_doutb; (* mark_debug = "true" *)wire [7:0] rx_ip_err; ETH_IP # ( .TX_MAC_SRC (TX_MAC_SRC), .TX_MAC_DES (TX_MAC_DES), .TX_IP_SRC (TX_IP_SRC), .TX_IP_DES (TX_IP_DES), .RX_IP_SRC (RX_IP_SRC), .RX_IP_SRC_EN (RX_IP_SRC_EN), .RX_IP_DES (RX_IP_DES), .RX_IP_DES_EN (RX_IP_DES_EN), .IP_BUF_SIZE (IP_BUF_SIZE), .IP_IDX_BIT (IP_IDX_BIT) ) ETH_IP_inst ( .sys_clk (sys_clk), .udp_tx_wea (udp_tx_wea), .udp_tx_addra (udp_tx_addra), .udp_tx_dina (udp_tx_dina), .udp_tx_douta (udp_tx_douta), .ip_fifo_din (ip_fifo_din), .ip_fifo_we (ip_fifo_we), .ip_fifo_cnt (ip_fifo_cnt), // ================================= .udp_rx_web (udp_rx_web), .udp_rx_addrb (udp_rx_addrb), .udp_rx_doutb (udp_rx_doutb), .ip_rx_web (ip_rx_web), .ip_rx_addrb (ip_rx_addrb), .ip_rx_doutb (ip_rx_doutb), .rx_ip_err (rx_ip_err), // ================================= .reset (reset) ); //========================================================================= wire phy_rx_clk; (* mark_debug = "true" *)wire [7:0] phy_rx_data; (* mark_debug = "true" *)wire phy_rx_toggle; (* mark_debug = "true" *)wire phy_rx_dv; wire phy_tx_clk = phy_rx_clk; (* mark_debug = "true" *)wire [7:0] phy_tx_data; (* mark_debug = "true" *)wire [1:0] phy_tx_en; (* mark_debug = "true" *)wire [7:0] mac_error; wire smi_done; ETH_MAC # ( .MAC_TX_CRC_EN (MAC_TX_CRC_EN), .IP_BUF_SIZE (IP_BUF_SIZE), .IP_IDX_BIT (IP_IDX_BIT), .MAC_TXBUF_SIZE (MAC_TXBUF_SIZE), .MAC_TXIDX_BIT (MAC_TXIDX_BIT) ) ETH_MAC_inst ( .sys_clk (sys_clk), // tx .ip_fifo_din (ip_fifo_din), .ip_fifo_we (ip_fifo_we), .ip_fifo_cnt (ip_fifo_cnt), // rx .ip_rx_web (ip_rx_web), .ip_rx_addrb (ip_rx_addrb), .ip_rx_doutb (ip_rx_doutb), .mac_error (mac_error), // ================================= .phy_rx_clk (phy_rx_clk), .phy_rx_data (phy_rx_data), .phy_rx_toggle (phy_rx_toggle), .phy_rx_dv (phy_rx_dv), .phy_tx_clk (phy_tx_clk), .phy_tx_data (phy_tx_data), .phy_tx_en (phy_tx_en), .smi_done (smi_done), .eth_speed (eth_speed), // ================================= .reset (reset) ); //========================================================================= eth_phy_core # ( .MAIN_CLK (MAIN_CLK), .PHY_SPEED (PHY_SPEED) ) eth_phy_core_inst ( .ref_clk (ref_clk), .E_RXC (E_RXC), .E_RXDV (E_RXDV), .E_RXD (E_RXD), .E_TXC (E_TXC), //以太网发送时钟 .E_TXEN (E_TXEN), //发送使能 .E_TXD (E_TXD), //发送数据 .sys_clk (sys_clk), .smi_done (smi_done), .e_mdc (e_mdc), .e_mdio_i (e_mdio_i), .e_mdio_o (e_mdio_o), .e_mdio_t (e_mdio_t), .eth_speed (eth_speed), .phy_rx_clk (phy_rx_clk), .phy_rx_dv (phy_rx_dv), .phy_rx_data (phy_rx_data), .phy_rx_toggle (phy_rx_toggle), .phy_tx_clk (phy_tx_clk), .phy_tx_data (phy_tx_data), .phy_tx_en (phy_tx_en), .reset (reset) ); //========================================================================= endmodule
在ETH_CORE.v模块中也有一些参数传递给下层的子模块,如下所示:
localparam IP_BUF_SIZE = 10;
localparam IP_IDX_BIT = 1;
localparam MAC_TXBUF_SIZE = IP_BUF_SIZE + 1;
localparam MAC_TXIDX_BIT = IP_IDX_BIT;
这些参数主要用来参数化IP和MAC层使用的A/B Buffer和FIFO,提高模块的通用性。
这些代码如何获取到呢