`timescale 1 ns / 1 ns module eth_ctrl_debug_top #( parameter int unsigned DAC_DATA_WIDTH = 12 )( 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 (200 MHz differential input) // ------------------------------------------------------------------------- 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) ); // ------------------------------------------------------------------------- // Generated clocks for controller // Need to create this IP in Vivado: // input : 200 MHz // output0: 130 MHz // output1: 65 MHz // ------------------------------------------------------------------------- wire dac_clk; wire adc_clk; wire clk_wiz_locked; clk_wiz_ctrl_inst clk_wiz_ctrl_inst ( .clk_in1 (sys_clk), .reset (~rst_n), .clk_out1 (dac_clk), // 130 MHz .clk_out2 (adc_clk), // 65 MHz .locked (clk_wiz_locked) ); // ------------------------------------------------------------------------- // 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 // RX stream from Ethernet goes into controller // TX stream is unused for now // ------------------------------------------------------------------------- wire req_ready; 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; (* MARK_DEBUG="true" *) wire [7:0] m_axis_rx_tdata; (* MARK_DEBUG="true" *) wire m_axis_rx_tvalid; (* MARK_DEBUG="true" *) wire m_axis_rx_tlast; (* MARK_DEBUG="true" *) wire m_axis_rx_tready; // Always ready to accept RX payload bytes assign m_axis_rx_tready = 1'b1; // TX disabled always @(*) begin 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; end 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) ); // PHY reset helper from your original example reset reset_m0 ( .clk (sys_clk), .key1 (rst_n), .rst_n (e_reset) ); // MDIO lines are not driven here yet assign e_mdc = 1'b0; assign e_mdio = 1'bz; // ------------------------------------------------------------------------- // Controller reset // Use both external reset and clk_wiz lock // ------------------------------------------------------------------------- wire ctrl_rst_n = rst_n & clk_wiz_locked; // ------------------------------------------------------------------------- // Debug finish generator // // After each adc_start pulse generates one finish pulse after some delay. // This is just for first bring-up so the controller can leave busy state // If you don't want this, replace with: // wire finish_dbg = 1'b0; // ------------------------------------------------------------------------- (* MARK_DEBUG="true" *) logic finish_dbg; (* MARK_DEBUG="true" *) logic [7:0] finish_cnt; (* MARK_DEBUG="true" *) logic finish_pending; // Controller outputs to debug (* MARK_DEBUG="true" *) wire [31:0] dac_pulse_width_dbg; (* MARK_DEBUG="true" *) wire [31:0] dac_pulse_period_dbg; (* MARK_DEBUG="true" *) wire [DAC_DATA_WIDTH-1:0] dac_pulse_height_dbg; (* MARK_DEBUG="true" *) wire [15:0] dac_pulse_num_dbg; (* MARK_DEBUG="true" *) wire [31:0] adc_pulse_period_dbg; (* MARK_DEBUG="true" *) wire [15:0] adc_pulse_num_dbg; (* MARK_DEBUG="true" *) wire dac_start_dbg; (* MARK_DEBUG="true" *) wire adc_start_dbg; (* MARK_DEBUG="true" *) wire dac_rst_dbg; (* MARK_DEBUG="true" *) wire adc_rst_dbg; always_ff @(posedge adc_clk or negedge ctrl_rst_n) begin if (!ctrl_rst_n) begin finish_dbg <= 1'b0; finish_cnt <= 8'd0; finish_pending <= 1'b0; end else begin finish_dbg <= 1'b0; if (adc_start_dbg) begin finish_pending <= 1'b1; finish_cnt <= 8'd80; end else if (finish_pending) begin if (finish_cnt == 8'd0) begin finish_dbg <= 1'b1; finish_pending <= 1'b0; end else begin finish_cnt <= finish_cnt - 8'd1; end end end end // ------------------------------------------------------------------------- // Controller // ETH domain = gmii_rx_clk, because RX AXI master comes from axis_mac RX side // ------------------------------------------------------------------------- control #( .DAC_DATA_WIDTH(DAC_DATA_WIDTH) ) udp_ctrl_inst ( .eth_clk_in (gmii_rx_clk), .dac_clk_in (dac_clk), .adc_clk_in (adc_clk), .rst_n (ctrl_rst_n), .s_axis_tdata (m_axis_rx_tdata), .s_axis_tvalid (m_axis_rx_tvalid), .s_axis_tready (), // controller internally always ready in current version .s_axis_tlast (m_axis_rx_tlast), .finish (finish_dbg), .dac_pulse_width (dac_pulse_width_dbg), .dac_pulse_period (dac_pulse_period_dbg), .dac_pulse_height (dac_pulse_height_dbg), .dac_pulse_num (dac_pulse_num_dbg), .adc_pulse_period (adc_pulse_period_dbg), .adc_pulse_num (adc_pulse_num_dbg), .dac_start (dac_start_dbg), .adc_start (adc_start_dbg), .dac_rst (dac_rst_dbg), .adc_rst (adc_rst_dbg) ); // ------------------------------------------------------------------------- // Simple LED status // ------------------------------------------------------------------------- assign led[0] = clk_wiz_locked; assign led[1] = m_axis_rx_tvalid; assign led[2] = dac_start_dbg; assign led[3] = adc_rst_dbg; endmodule