Files
b210-k7-fpga/top/x300/x300_sfpp_io_core.v
T
+18 6b67702ad7 Merge FPGA repository back into UHD repository
The FPGA codebase was removed from the UHD repository in 2014 to reduce
the size of the repository. However, over the last half-decade, the
split between the repositories has proven more burdensome than it has
been helpful. By merging the FPGA code back, it will be possible to
create atomic commits that touch both FPGA and UHD codebases. Continuous
integration testing is also simplified by merging the repositories,
because it was previously difficult to automatically derive the correct
UHD branch when testing a feature branch on the FPGA repository.

This commit also updates the license files and paths therein.

We are therefore merging the repositories again. Future development for
FPGA code will happen in the same repository as the UHD host code and
MPM code.

== Original Codebase and Rebasing ==

The original FPGA repository will be hosted for the foreseeable future
at its original local location: https://github.com/EttusResearch/fpga/

It can be used for bisecting, reference, and a more detailed history.

The final commit from said repository to be merged here is
05003794e2da61cabf64dd278c45685a7abad7ec. This commit is tagged as
v4.0.0.0-pre-uhd-merge.

If you have changes in the FPGA repository that you want to rebase onto
the UHD repository, simply run the following commands:

- Create a directory to store patches (this should be an empty
  directory):

    mkdir ~/patches

- Now make sure that your FPGA codebase is based on the same state as
  the code that was merged:

    cd src/fpga # Or wherever your FPGA code is stored
    git rebase v4.0.0.0-pre-uhd-merge

  Note: The rebase command may look slightly different depending on what
  exactly you're trying to rebase.

- Create a patch set for your changes versus v4.0.0.0-pre-uhd-merge:

    git format-patch v4.0.0.0-pre-uhd-merge -o ~/patches

  Note: Make sure that only patches are stored in your output directory.
  It should otherwise be empty. Make sure that you picked the correct
  range of commits, and only commits you wanted to rebase were exported
  as patch files.

- Go to the UHD repository and apply the patches:

    cd src/uhd # Or wherever your UHD repository is stored
    git am --directory fpga ~/patches/*
    rm -rf ~/patches # This is for cleanup

== Contributors ==

The following people have contributed mainly to these files (this list
is not complete):

Co-authored-by: Alex Williams <alex.williams@ni.com>
Co-authored-by: Andrej Rode <andrej.rode@ettus.com>
Co-authored-by: Ashish Chaudhari <ashish@ettus.com>
Co-authored-by: Ben Hilburn <ben.hilburn@ettus.com>
Co-authored-by: Ciro Nishiguchi <ciro.nishiguchi@ni.com>
Co-authored-by: Daniel Jepson <daniel.jepson@ni.com>
Co-authored-by: Derek Kozel <derek.kozel@ettus.com>
Co-authored-by: EJ Kreinar <ej@he360.com>
Co-authored-by: Humberto Jimenez <humberto.jimenez@ni.com>
Co-authored-by: Ian Buckley <ian.buckley@gmail.com>
Co-authored-by: Jörg Hofrichter <joerg.hofrichter@ni.com>
Co-authored-by: Jon Kiser <jon.kiser@ni.com>
Co-authored-by: Josh Blum <josh@joshknows.com>
Co-authored-by: Jonathon Pendlum <jonathan.pendlum@ettus.com>
Co-authored-by: Martin Braun <martin.braun@ettus.com>
Co-authored-by: Matt Ettus <matt@ettus.com>
Co-authored-by: Michael West <michael.west@ettus.com>
Co-authored-by: Moritz Fischer <moritz.fischer@ettus.com>
Co-authored-by: Nick Foster <nick@ettus.com>
Co-authored-by: Nicolas Cuervo <nicolas.cuervo@ettus.com>
Co-authored-by: Paul Butler <paul.butler@ni.com>
Co-authored-by: Paul David <paul.david@ettus.com>
Co-authored-by: Ryan Marlow <ryan.marlow@ettus.com>
Co-authored-by: Sugandha Gupta <sugandha.gupta@ettus.com>
Co-authored-by: Sylvain Munaut <tnt@246tNt.com>
Co-authored-by: Trung Tran <trung.tran@ettus.com>
Co-authored-by: Vidush Vishwanath <vidush.vishwanath@ettus.com>
Co-authored-by: Wade Fife <wade.fife@ettus.com>


Original-commit: bafa9d95453387814ef25e6b6256ba8db2df612f
2020-01-28 09:35:36 -08:00

509 lines
19 KiB
Verilog

//
// Copyright 2016-2017 Ettus Research LLC
// Copyright 2017 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// sfpp_io_core
// - mdio_master
// - One Gige phy + MAC
// - Ten Gige phy + MAC
// - Aurora phy + MAC
//
//////////////////////////////////////////////////////////////////////
module x300_sfpp_io_core #(
parameter PROTOCOL = "10GbE", // Must be {10GbE, 1GbE, Aurora}
parameter PORTNUM = 8'd0
)(
input areset,
input bus_rst,
input bus_rst_div2,
input gt_refclk,
input gb_refclk,
input misc_clk,
input bus_clk,
input bus_clk_div2,
output txp,
output txn,
input rxp,
input rxn,
input sfpp_rxlos,
input sfpp_tx_fault,
output sfpp_tx_disable,
input [63:0] s_axis_tdata,
input [3:0] s_axis_tuser,
input s_axis_tlast,
input s_axis_tvalid,
output s_axis_tready,
output [63:0] m_axis_tdata,
output [3:0] m_axis_tuser,
output m_axis_tlast,
output m_axis_tvalid,
input m_axis_tready,
input [7:0] wb_adr_i,
input wb_cyc_i,
input [31:0] wb_dat_i,
input wb_stb_i,
input wb_we_i,
output wb_ack_o,
output [31:0] wb_dat_o,
output wb_int_o,
output [15:0] phy_status,
output link_up,
output activity
);
wire mdc, mdio_in, mdio_out;
// Flush logic: If the link is not up, we will flush all packets coming from
// the device. This avoids the MAC backpressuring when the PHY is down.
// The device will always send discovery packets to the transports during
// initialization, and they have no way of knowing if it's safe to travel
// down this route. c2mac == "CHDR to MAC"
wire [63:0] c2mac_tdata;
wire [3:0] c2mac_tuser;
wire c2mac_tlast;
wire c2mac_tvalid;
wire c2mac_tready;
axis_packet_flush #(
.WIDTH(64+3), // tdata + tuser
.TIMEOUT_W(1), // Not using timeout
.FLUSH_PARTIAL_PKTS(0),
.PIPELINE("NONE")
) linkup_flush (
.clk(bus_clk),
.reset(bus_rst),
.enable(~link_up), // enable flushing when link down
.timeout(1'b0),
.flushing(/* not required */),
.done(/* not required */),
// Input from device/crossbar
.s_axis_tdata ({s_axis_tuser, s_axis_tdata}),
.s_axis_tlast (s_axis_tlast),
.s_axis_tvalid (s_axis_tvalid),
.s_axis_tready (s_axis_tready),
// Output to MAC
.m_axis_tdata ({c2mac_tuser, c2mac_tdata}),
.m_axis_tlast (c2mac_tlast),
.m_axis_tvalid (c2mac_tvalid),
.m_axis_tready (c2mac_tready)
);
generate
if (PROTOCOL == "10GbE") begin
//-----------------------------------------------------------------
// 10 Gigabit Ethernet
//-----------------------------------------------------------------
wire [63:0] xgmii_txd;
wire [7:0] xgmii_txc;
wire [63:0] xgmii_rxd;
wire [7:0] xgmii_rxc;
wire [7:0] xgmii_status;
wire xge_phy_resetdone;
ten_gige_phy ten_gige_phy_i
(
// Clocks and Reset
.areset(areset), // Asynchronous reset for entire core.
.refclk(gt_refclk), // Transciever reference clock: 156.25MHz
.clk156(gb_refclk), // Globally buffered core clock: 156.25MHz
.dclk(misc_clk), // Management/DRP clock: 78.125MHz
.sim_speedup_control(1'b0),
// GMII Interface (client MAC <=> PCS)
.xgmii_txd(xgmii_txd), // Transmit data from client MAC.
.xgmii_txc(xgmii_txc), // Transmit control signal from client MAC.
.xgmii_rxd(xgmii_rxd), // Received Data to client MAC.
.xgmii_rxc(xgmii_rxc), // Received control signal to client MAC.
// Tranceiver Interface
.txp(txp), // Differential +ve of serial transmission from PMA to PMD.
.txn(txn), // Differential -ve of serial transmission from PMA to PMD.
.rxp(rxp), // Differential +ve for serial reception from PMD to PMA.
.rxn(rxn), // Differential -ve for serial reception from PMD to PMA.
// Management: MDIO Interface
.mdc(mdc), // Management Data Clock
.mdio_in(mdio_in), // Management Data In
.mdio_out(mdio_out), // Management Data Out
.mdio_tri(), // Management Data Tristate
.prtad(5'd4), // MDIO address is 4
// General IO's
.core_status(xgmii_status), // Core status
.resetdone(xge_phy_resetdone),
.signal_detect(~sfpp_rxlos), // Input from PMD to indicate presence of optical input. (Undocumented, but it seems Xilinx expect this to be inverted.)
.tx_fault(sfpp_tx_fault),
.tx_disable(sfpp_tx_disable)
);
xge_mac_wrapper #(
.PORTNUM(PORTNUM),
.WISHBONE(1)
) xge_mac_wrapper_i (
// XGMII
.xgmii_clk(gb_refclk),
.xgmii_txd(xgmii_txd),
.xgmii_txc(xgmii_txc),
.xgmii_rxd(xgmii_rxd),
.xgmii_rxc(xgmii_rxc),
// MDIO
.mdc(mdc),
.mdio_in(mdio_in),
.mdio_out(mdio_out),
// Wishbone I/F
.wb_clk_i(bus_clk_div2),
.wb_rst_i(bus_rst_div2),
.wb_adr_i(wb_adr_i),
.wb_cyc_i(wb_cyc_i),
.wb_dat_i(wb_dat_i),
.wb_stb_i(wb_stb_i),
.wb_we_i(wb_we_i),
.wb_ack_o(wb_ack_o),
.wb_dat_o(wb_dat_o),
.wb_int_o(wb_int_o),
// Client FIFO Interfaces
.sys_clk(bus_clk),
.sys_rst(bus_rst),
.rx_tdata(m_axis_tdata),
.rx_tuser(m_axis_tuser),
.rx_tlast(m_axis_tlast),
.rx_tvalid(m_axis_tvalid),
.rx_tready(m_axis_tready),
.tx_tdata(c2mac_tdata),
.tx_tuser(c2mac_tuser), // Bit[3] (error) is ignored for now.
.tx_tlast(c2mac_tlast),
.tx_tvalid(c2mac_tvalid),
.tx_tready(c2mac_tready),
// Other
.phy_ready(xge_phy_resetdone)
);
assign phy_status = {8'h00, xgmii_status};
// Use the PCS Block Lock signal to drive the link_up LED on the FP.
// For further details, see Xilinx' PG068, Table 2-11 (core_status[0] signal).
synchronizer #(.INITIAL_VAL(1'b0)) link_up_sync (
.clk(bus_clk), .rst(1'b0 /* no reset */), .in(xgmii_status[0]), .out(link_up));
end else if (PROTOCOL == "1GbE") begin
//-----------------------------------------------------------------
// 1 Gigabit Ethernet
//-----------------------------------------------------------------
wire [7:0] gmii_txd, gmii_rxd;
wire gmii_tx_en, gmii_tx_er, gmii_rx_dv, gmii_rx_er;
wire gmii_clk;
assign sfpp_tx_disable = 1'b0; // Always on.
one_gige_phy one_gige_phy_i
(
.reset(areset), // Asynchronous reset for entire core.
.independent_clock(bus_clk),
// Tranceiver Interface
.gtrefclk(gt_refclk), // Reference clock for MGT: 125MHz, very high quality.
.gtrefclk_bufg(gb_refclk), // Reference clock routed through a BUFG
.txp(txp), // Differential +ve of serial transmission from PMA to PMD.
.txn(txn), // Differential -ve of serial transmission from PMA to PMD.
.rxp(rxp), // Differential +ve for serial reception from PMD to PMA.
.rxn(rxn), // Differential -ve for serial reception from PMD to PMA.
// GMII Interface (client MAC <=> PCS)
.gmii_clk(gmii_clk), // Clock to client MAC.
.gmii_txd(gmii_txd), // Transmit data from client MAC.
.gmii_tx_en(gmii_tx_en), // Transmit control signal from client MAC.
.gmii_tx_er(gmii_tx_er), // Transmit control signal from client MAC.
.gmii_rxd(gmii_rxd), // Received Data to client MAC.
.gmii_rx_dv(gmii_rx_dv), // Received control signal to client MAC.
.gmii_rx_er(gmii_rx_er), // Received control signal to client MAC.
// Management: MDIO Interface
.mdc(mdc), // Management Data Clock
.mdio_i(mdio_in), // Management Data In
.mdio_o(mdio_out), // Management Data Out
.mdio_t(), // Management Data Tristate
.configuration_vector(5'd0), // Alternative to MDIO interface.
.configuration_valid(1'b1), // Validation signal for Config vector (MUST be 1 for proper functionality...undocumented)
// General IO's
.status_vector(phy_status), // Core status.
.signal_detect(1'b1 /*Optical module not supported*/) // Input from PMD to indicate presence of optical input.
);
simple_gemac_wrapper #(.RX_FLOW_CTRL(0), .PORTNUM(PORTNUM)) simple_gemac_wrapper_i
(
.clk125(gmii_clk),
.reset(areset),
.GMII_GTX_CLK(),
.GMII_TX_EN(gmii_tx_en),
.GMII_TX_ER(gmii_tx_er),
.GMII_TXD(gmii_txd),
.GMII_RX_CLK(gmii_clk),
.GMII_RX_DV(gmii_rx_dv),
.GMII_RX_ER(gmii_rx_er),
.GMII_RXD(gmii_rxd),
.sys_clk(bus_clk),
.rx_tdata(m_axis_tdata),
.rx_tuser(m_axis_tuser),
.rx_tlast(m_axis_tlast),
.rx_tvalid(m_axis_tvalid),
.rx_tready(m_axis_tready),
.tx_tdata(c2mac_tdata),
.tx_tuser(c2mac_tuser),
.tx_tlast(c2mac_tlast),
.tx_tvalid(c2mac_tvalid),
.tx_tready(c2mac_tready),
// MDIO
.mdc(mdc),
.mdio_in(mdio_in),
.mdio_out(mdio_out),
.mdio_tri(),
// Wishbone I/F
.wb_clk_i(bus_clk_div2),
.wb_rst_i(bus_rst_div2),
.wb_adr_i(wb_adr_i),
.wb_cyc_i(wb_cyc_i),
.wb_dat_i(wb_dat_o),
.wb_stb_i(wb_stb_i),
.wb_we_i(wb_we_i),
.wb_ack_o(wb_ack_o),
.wb_dat_o(wb_dat_i),
.wb_int_o(wb_int_o),
// Debug
.debug_tx(), .debug_rx()
);
// Use the Link Status signal to drive the link_up LED on the FP.
// For further details, see Xilinx' PG047, Table 2-76 (status_vector[0]).
synchronizer #(.INITIAL_VAL(1'b0)) link_up_sync (
.clk(bus_clk), .rst(1'b0 /* no reset */), .in(phy_status[0]), .out(link_up));
end else if (PROTOCOL == "Aurora") begin
//-----------------------------------------------------------------
// Aurora
//-----------------------------------------------------------------
wire au_user_clk, au_user_rst, phy_areset;
wire [63:0] i_tdata, o_tdata;
wire i_tvalid, i_tready, o_tvalid;
wire channel_up, hard_err, soft_err;
wire mac_clear;
assign sfpp_tx_disable = 1'b0; // Always on.
aurora_phy_x1 aurora_phy_i (
// Resets
.areset(areset | phy_areset),
// Clocks
.refclk(gt_refclk),
.init_clk(misc_clk),
.user_clk(au_user_clk),
.user_rst(au_user_rst),
// GTX Serial I/O
.tx_p(txp),
.tx_n(txn),
.rx_p(rxp),
.rx_n(rxn),
// AXI4-Stream TX Interface
.s_axis_tdata(i_tdata),
.s_axis_tvalid(i_tvalid),
.s_axis_tready(i_tready),
// AXI4-Stream RX Interface
.m_axis_tdata(o_tdata),
.m_axis_tvalid(o_tvalid),
// AXI4-Lite Config Interface: TODO: Hook up to WB->AXI4Lite converter
.s_axi_awaddr(32'h0),
.s_axi_araddr(32'h0),
.s_axi_awvalid(1'b0),
.s_axi_awready(),
.s_axi_wdata(32'h0),
.s_axi_wvalid(1'b0),
.s_axi_wstrb(1'b0),
.s_axi_wready(),
.s_axi_bvalid(),
.s_axi_bresp(),
.s_axi_bready(1'b1),
.s_axi_arready(),
.s_axi_arvalid(1'b0),
.s_axi_rdata(),
.s_axi_rvalid(),
.s_axi_rresp(),
.s_axi_rready(1'b1),
// Status and Error Reporting Interface
.channel_up(channel_up),
.hard_err(hard_err),
.soft_err(soft_err)
);
assign phy_status = {14'd0, hard_err, channel_up};
wire bist_gen_en, bist_checker_en, bist_loopback_en;
wire bist_checker_locked;
wire [5:0] bist_gen_rate;
wire [47:0] bist_checker_samps, bist_checker_errors;
wire [31:0] overruns, checksum_errors;
aurora_axis_mac #(
.PHY_ENDIANNESS ("LITTLE"),
.PACKET_MODE (1),
.MAX_PACKET_SIZE(1024),
.BIST_ENABLED (1)
) aurora_mac_i (
// Clocks and resets
.phy_clk(au_user_clk), .phy_rst(au_user_rst),
.sys_clk(bus_clk), .sys_rst(bus_rst),
.clear(mac_clear),
// PHY Interface (Synchronous to phy_clk)
.phy_s_axis_tdata(o_tdata),
.phy_s_axis_tvalid(o_tvalid),
.phy_m_axis_tdata(i_tdata),
.phy_m_axis_tvalid(i_tvalid),
.phy_m_axis_tready(i_tready),
// User Interface (Synchronous to sys_clk)
.s_axis_tdata(c2mac_tdata),
.s_axis_tlast(c2mac_tlast),
.s_axis_tvalid(c2mac_tvalid),
.s_axis_tready(c2mac_tready),
.m_axis_tdata(m_axis_tdata),
.m_axis_tlast(m_axis_tlast),
.m_axis_tvalid(m_axis_tvalid),
.m_axis_tready(m_axis_tready),
// PHY Status Inputs (Synchronous to phy_clk)
.channel_up(channel_up),
.hard_err(hard_err),
.soft_err(soft_err),
// Status and Error Outputs (Synchronous to sys_clk)
.overruns(overruns),
.soft_errors(),
.checksum_errors(checksum_errors),
.critical_err(mac_crit_err),
// BIST Interface (Synchronous to sys_clk)
.bist_gen_en(bist_gen_en),
.bist_gen_rate(bist_gen_rate),
.bist_checker_en(bist_checker_en),
.bist_loopback_en(bist_loopback_en),
.bist_checker_locked(bist_checker_locked),
.bist_checker_samps(bist_checker_samps),
.bist_checker_errors(bist_checker_errors)
);
reg mac_crit_err_latch;
always @(posedge bus_clk) begin
if (bus_rst | mac_clear) begin
mac_crit_err_latch <= 1'b0;
end else begin
if (mac_crit_err_bclk)
mac_crit_err_latch <= 1'b1;
end
end
assign m_axis_tuser = 4'd0;
wire set_stb;
wire [3:0] set_addr, rb_addr;
wire [31:0] set_data;
reg [31:0] rb_data;
settings_bus #(.AWIDTH(8), .DWIDTH(32), .SWIDTH(4)) settings_bus_i (
.wb_clk(bus_clk), .wb_rst(bus_rst),
.wb_adr_i(wb_adr_i), .wb_dat_i(wb_dat_i),
.wb_stb_i(wb_stb_i), .wb_we_i(wb_we_i), .wb_ack_o(wb_ack_o),
.strobe(set_stb), .addr(set_addr), .data(set_data)
);
settings_readback #(.AWIDTH(8),.DWIDTH(32), .RB_ADDRW(4)) settings_readback_i (
.wb_clk(bus_clk), .wb_rst(bus_rst),
.wb_adr_i(wb_adr_i), .wb_stb_i(wb_stb_i), .wb_we_i(wb_we_i), .wb_dat_o(wb_dat_o),
.rb_data(rb_data), .rb_addr(rb_addr), .rb_rd_stb()
);
setting_reg #(.my_addr(4'd0), .awidth(4), .width(11), .at_reset(11'h000)) set_core_control_i (
.clk(bus_clk), .rst(bus_rst),
.strobe(set_stb), .addr(set_addr), .in(set_data),
.out({mac_clear, phy_areset, bist_gen_rate, bist_loopback_en, bist_gen_en, bist_checker_en}), .changed()
);
wire channel_up_bclk, hard_err_bclk, soft_err_bclk, mac_crit_err_bclk;
synchronizer #(.INITIAL_VAL(1'b0)) channel_up_sync (
.clk(bus_clk), .rst(1'b0 /* no reset */), .in(channel_up), .out(channel_up_bclk));
synchronizer #(.INITIAL_VAL(1'b0)) hard_err_sync (
.clk(bus_clk), .rst(1'b0 /* no reset */), .in(hard_err), .out(hard_err_bclk));
synchronizer #(.INITIAL_VAL(1'b0)) soft_err_sync (
.clk(bus_clk), .rst(1'b0 /* no reset */), .in(soft_err), .out(soft_err_bclk));
synchronizer #(.INITIAL_VAL(1'b0)) mac_crit_err_sync (
.clk(bus_clk), .rst(1'b0 /* no reset */), .in(mac_crit_err), .out(mac_crit_err_bclk));
reg [19:0] bist_lock_latency;
always @(posedge bus_clk) begin
if (!bist_checker_en && !bist_checker_locked)
bist_lock_latency <= 20'd0;
else if (bist_checker_en && !bist_checker_locked)
bist_lock_latency <= bist_lock_latency + 20'd1;
end
reg mac_crit_err_latch;
always @(posedge bus_clk) begin
if (bus_rst | mac_clear) begin
mac_crit_err_latch <= 1'b0;
end else begin
if (mac_crit_err_bclk)
mac_crit_err_latch <= 1'b1;
end
end
wire [31:0] core_status = {
6'h0, //[31:26]
mac_crit_err_latch, //[25]
1, //[24] mmcm_locked_bclk
1, //[23] gt_pll_locked_bclk
0, //[22] qpll_refclklost_bclk
1, //[21] qpll_lock_bclk
0, //[20] qpll_reset_bclk
bist_lock_latency[19:4], //[19:4]
bist_checker_locked, //[3]
soft_err_bclk, //[2]
hard_err_bclk, //[1]
channel_up_bclk //[0]
};
assign link_up = channel_up_bclk;
always @(*)
case (rb_addr)
4'd0: rb_data = core_status;
4'd1: rb_data = overruns;
4'd2: rb_data = checksum_errors;
4'd3: rb_data = bist_checker_samps[47:16]; //Scale num sample by 2^16
4'd4: rb_data = bist_checker_errors[31:0]; //Dont scale errors
default: rb_data = 32'h0;
endcase // case (rb_addr)
end else begin
//Invalid protocol
end
endgenerate
//-----------------------------------------------------------------
// Activity detector
//-----------------------------------------------------------------
pulse_stretch act_pulse_str_i (
.clk(bus_clk),
.rst(bus_rst | ~link_up),
.pulse((s_axis_tvalid & s_axis_tready) | (m_axis_tvalid & m_axis_tready)),
.pulse_stretched(activity)
);
endmodule