diff --git a/rtl/ethernet-udp/tests/eth_axis/ethernet_test_minimal.v b/rtl/ethernet-udp/tests/eth_axis/ethernet_test_minimal.v new file mode 100644 index 0000000..bce1ae5 --- /dev/null +++ b/rtl/ethernet-udp/tests/eth_axis/ethernet_test_minimal.v @@ -0,0 +1,333 @@ +`timescale 1 ns / 1 ns + +module ethernet_test_minimal +( + input sys_clk_p, + input sys_clk_n, + input rst_n, + output [3:0] led, + output e_reset, + output e_mdc, + inout e_mdio, + output [3:0] rgmii_txd, + output rgmii_txctl, + output rgmii_txc, + input [3:0] rgmii_rxd, + input rgmii_rxctl, + input rgmii_rxc +); + + // ------------------------------------------------------------ + // Internal GMII-side signals + // ------------------------------------------------------------ + wire [7:0] gmii_txd; + wire gmii_tx_en; + wire gmii_tx_er; + wire gmii_tx_clk; + wire gmii_crs; + wire gmii_col; + wire [7:0] gmii_rxd_i; + wire gmii_rx_dv; + wire gmii_rx_er; + wire gmii_rx_clk; + + wire [31:0] pack_total_len; + + wire e_rx_dv; + wire [7:0] e_rxd; + wire e_tx_en; + wire [7:0] e_txd; + wire e_rst_n; + wire sys_clk; + + wire duplex_mode; + + assign duplex_mode = 1'b1; + + // ------------------------------------------------------------ + // System clock buffer + // ------------------------------------------------------------ + IBUFDS sys_clk_ibufgds + ( + .O (sys_clk), + .I (sys_clk_p), + .IB (sys_clk_n) + ); + + // ------------------------------------------------------------ + // IDELAYCTRL + // ------------------------------------------------------------ + (* IODELAY_GROUP = "rgmii_idelay_group" *) + IDELAYCTRL IDELAYCTRL_inst ( + .RDY(), + .REFCLK(sys_clk), + .RST(1'b0) + ); + + // ------------------------------------------------------------ + // GMII <-> RGMII conversion + // ------------------------------------------------------------ + util_gmii_to_rgmii util_gmii_to_rgmii_m0 + ( + .reset (1'b0), + .rgmii_td (rgmii_txd), + .rgmii_tx_ctl (rgmii_txctl), + .rgmii_txc (rgmii_txc), + .rgmii_rd (rgmii_rxd), + .rgmii_rx_ctl (rgmii_rxctl), + .gmii_rx_clk (gmii_rx_clk), + .gmii_txd (e_txd), + .gmii_tx_en (e_tx_en), + .gmii_tx_er (1'b0), + .gmii_tx_clk (gmii_tx_clk), + .gmii_crs (gmii_crs), + .gmii_col (gmii_col), + .gmii_rxd (gmii_rxd_i), + .rgmii_rxc (rgmii_rxc), + .gmii_rx_dv (gmii_rx_dv), + .gmii_rx_er (gmii_rx_er), + .speed_selection (2'b10), + .duplex_mode (duplex_mode) + ); + + // ------------------------------------------------------------ + // GMII arbitration / adaptation + // ------------------------------------------------------------ + gmii_arbi arbi_inst + ( + .clk (gmii_tx_clk), + .rst_n (rst_n), + .speed (2'b10), + .link (1'b1), + .pack_total_len (pack_total_len), + .e_rst_n (e_rst_n), + .gmii_rx_dv (gmii_rx_dv), + .gmii_rxd (gmii_rxd_i), + .gmii_tx_en (gmii_tx_en), + .gmii_txd (gmii_txd), + .e_rx_dv (e_rx_dv), + .e_rxd (e_rxd), + .e_tx_en (e_tx_en), + .e_txd (e_txd) + ); + + // ------------------------------------------------------------ + // axis_mac interface + // ------------------------------------------------------------ + (* MARK_DEBUG="true" *)wire req_ready; + + (* MARK_DEBUG="true" *)reg send_req; + reg [15:0] data_length; + + reg [7:0] s_axis_tx_tdata; + reg s_axis_tx_tvalid; + wire s_axis_tx_tready; + reg s_axis_tx_tlast; + + wire [7:0] m_axis_rx_tdata; + wire m_axis_rx_tvalid; + reg m_axis_rx_tready; + wire m_axis_rx_tlast; + + // ------------------------------------------------------------ + // axis_mac + // ------------------------------------------------------------ + axis_mac axis_mac0 + ( + .gmii_tx_clk (gmii_tx_clk), + .gmii_rx_clk (gmii_rx_clk), + .rst_n (e_rst_n), + + .gmii_rx_dv (e_rx_dv), + .gmii_rxd (e_rxd), + .gmii_tx_en (gmii_tx_en), + .gmii_txd (gmii_txd), + + .send_req (send_req), + .data_length (data_length), + .req_ready (req_ready), + + .s_axis_tx_tdata (s_axis_tx_tdata), + .s_axis_tx_tvalid (s_axis_tx_tvalid), + .s_axis_tx_tready (s_axis_tx_tready), + .s_axis_tx_tlast (s_axis_tx_tlast), + + .m_axis_rx_tdata (m_axis_rx_tdata), + .m_axis_rx_tvalid (m_axis_rx_tvalid), + .m_axis_rx_tready (m_axis_rx_tready), + .m_axis_rx_tlast (m_axis_rx_tlast) + ); + + // ------------------------------------------------------------ + // LEDs + // Просто чтобы не висели в воздухе + // ------------------------------------------------------------ + assign led[0] = req_ready; + assign led[1] = !m_axis_rx_tvalid; + assign led[2] = !s_axis_tx_tvalid; + assign led[3] = e_rst_n; + + // ------------------------------------------------------------ + // Minimal one-packet echo buffer + // ------------------------------------------------------------ + localparam BUFFER_SIZE = 256; + + reg [7:0] pkt_mem [0:BUFFER_SIZE-1]; + + // ---------------- RX domain ---------------- + reg [15:0] rx_wr_ptr; + reg [15:0] rx_pkt_len; + reg rx_pkt_toggle; + + // TX->RX "done" toggle synchronizer + reg tx_done_toggle; + reg tx_done_toggle_rx_d0, tx_done_toggle_rx_d1; + wire tx_done_pulse_rx; + + assign tx_done_pulse_rx = tx_done_toggle_rx_d1 ^ tx_done_toggle_rx_d0; + + always @(posedge gmii_rx_clk or negedge e_rst_n) begin + if (!e_rst_n) begin + tx_done_toggle_rx_d0 <= 1'b0; + tx_done_toggle_rx_d1 <= 1'b0; + end else begin + tx_done_toggle_rx_d0 <= tx_done_toggle; + tx_done_toggle_rx_d1 <= tx_done_toggle_rx_d0; + end + end + + always @(posedge gmii_rx_clk or negedge e_rst_n) begin + if (!e_rst_n) begin + rx_wr_ptr <= 16'd0; + rx_pkt_len <= 16'd0; + rx_pkt_toggle <= 1'b0; + m_axis_rx_tready <= 1'b0; + end else begin + // accept only one packet at a time + m_axis_rx_tready <= 1'b1; + + if (tx_done_pulse_rx) begin + rx_pkt_toggle <= 1'b0; + rx_wr_ptr <= 16'd0; + end + + if (m_axis_rx_tvalid && m_axis_rx_tready) begin + pkt_mem[rx_wr_ptr] <= m_axis_rx_tdata; + + if (m_axis_rx_tlast) begin + rx_pkt_len <= rx_wr_ptr + 16'd1; + rx_pkt_toggle <= 1'b1; + end + + rx_wr_ptr <= rx_wr_ptr + 16'd1; + end + end + end + + // ---------------- RX->TX toggle sync ---------------- + reg rx_pkt_toggle_tx_d0, rx_pkt_toggle_tx_d1; + (* MARK_DEBUG="true" *) wire rx_pkt_pulse_tx; + + assign rx_pkt_pulse_tx = rx_pkt_toggle_tx_d1 ^ rx_pkt_toggle_tx_d0; + + always @(posedge gmii_tx_clk or negedge e_rst_n) begin + if (!e_rst_n) begin + rx_pkt_toggle_tx_d0 <= 1'b0; + rx_pkt_toggle_tx_d1 <= 1'b0; + end else begin + rx_pkt_toggle_tx_d0 <= rx_pkt_toggle; + rx_pkt_toggle_tx_d1 <= rx_pkt_toggle_tx_d0; + end + end + + // ---------------- TX domain ---------------- + localparam TX_IDLE = 2'd0; + localparam TX_REQ = 2'd1; + localparam TX_STREAM = 2'd2; + + (* MARK_DEBUG="true" *)reg [1:0] test_state; + reg tx_pkt_pending; + reg [15:0] tx_pkt_len; + reg [15:0] tx_rd_ptr; + + always @(posedge gmii_tx_clk or negedge e_rst_n) begin + if (!e_rst_n) begin + test_state <= TX_IDLE; + tx_pkt_pending <= 1'b0; + tx_pkt_len <= 16'd0; + tx_rd_ptr <= 16'd0; + + send_req <= 1'b0; + data_length <= 16'd0; + + s_axis_tx_tdata <= 8'd0; + s_axis_tx_tvalid <= 1'b0; + s_axis_tx_tlast <= 1'b0; + + tx_done_toggle <= 1'b0; + end else begin + send_req <= 1'b0; + + if (rx_pkt_pulse_tx) begin + tx_pkt_pending <= 1'b1; + tx_pkt_len <= rx_pkt_len; + tx_rd_ptr <= 16'd0; + end + + case (test_state) + TX_IDLE: begin + s_axis_tx_tvalid <= 1'b0; + s_axis_tx_tlast <= 1'b0; + tx_rd_ptr <= 16'd0; + + if (tx_pkt_pending && req_ready) begin + data_length <= tx_pkt_len; + send_req <= 1'b1; + test_state <= TX_REQ; + end + end + + TX_REQ: begin + if (s_axis_tx_tready) begin + s_axis_tx_tdata <= pkt_mem[0]; + s_axis_tx_tvalid <= 1'b1; + s_axis_tx_tlast <= (tx_pkt_len == 16'd1); + tx_rd_ptr <= 16'd0; + test_state <= TX_STREAM; + end + end + + TX_STREAM: begin + if (s_axis_tx_tvalid && s_axis_tx_tready) begin + if (tx_rd_ptr == tx_pkt_len - 16'd1) begin + s_axis_tx_tvalid <= 1'b0; + s_axis_tx_tlast <= 1'b0; + tx_pkt_pending <= 1'b0; + tx_done_toggle <= 1'b1; + test_state <= TX_IDLE; + end else begin + tx_rd_ptr <= tx_rd_ptr + 16'd1; + s_axis_tx_tdata <= pkt_mem[tx_rd_ptr + 16'd1]; + s_axis_tx_tlast <= (tx_rd_ptr + 16'd1 == tx_pkt_len - 16'd1); + end + end + end + + default: begin + test_state <= TX_IDLE; + end + endcase + end + end + + // ------------------------------------------------------------ + // PHY reset generation + // ------------------------------------------------------------ + reset reset_m0 + ( + .clk (sys_clk), + .key1 (rst_n), + .rst_n (e_reset) + ); + +endmodule \ No newline at end of file