From e4762b7a8c5cfda260c99de2b15d563ed354b91b Mon Sep 17 00:00:00 2001 From: Alex Forencich Date: Fri, 30 May 2025 21:14:54 -0700 Subject: [PATCH] eth: Add support for synchronous gearbox to PHY, MAC+PHY, and GT wrappers Signed-off-by: Alex Forencich --- .../ADM_PCIE_9V3/fpga/rtl/fpga_core.sv | 3 + .../fpga/tb/fpga_core/test_fpga_core.py | 35 +- src/eth/example/Alveo/fpga/rtl/fpga_core.sv | 3 + .../Alveo/fpga/tb/fpga_core/test_fpga_core.py | 35 +- src/eth/example/KCU105/fpga/rtl/fpga_core.sv | 3 + .../fpga/tb/fpga_core/test_fpga_core.py | 35 +- src/eth/example/KR260/fpga/rtl/fpga_core.sv | 3 + .../KR260/fpga/tb/fpga_core/test_fpga_core.py | 49 +- .../example/Nexus_K3P_Q/fpga/rtl/fpga_core.sv | 3 + .../fpga/tb/fpga_core/test_fpga_core.py | 35 +- .../example/Nexus_K3P_S/fpga/rtl/fpga_core.sv | 3 + .../fpga/tb/fpga_core/test_fpga_core.py | 35 +- src/eth/example/VCU108/fpga/rtl/fpga_core.sv | 3 + .../fpga/tb/fpga_core/test_fpga_core.py | 35 +- src/eth/example/VCU118/fpga/rtl/fpga_core.sv | 3 + .../fpga/tb/fpga_core/test_fpga_core.py | 35 +- src/eth/example/XUPP3R/fpga/rtl/fpga_core.sv | 3 + .../fpga/tb/fpga_core/test_fpga_core.py | 35 +- src/eth/example/ZCU102/fpga/rtl/fpga_core.sv | 3 + .../fpga/tb/fpga_core/test_fpga_core.py | 35 +- src/eth/example/ZCU106/fpga/rtl/fpga_core.sv | 3 + .../fpga/tb/fpga_core/test_fpga_core.py | 35 +- src/eth/example/ZCU111/fpga/rtl/fpga_core.sv | 3 + .../fpga/tb/fpga_core/test_fpga_core.py | 35 +- src/eth/example/fb2CG/fpga/rtl/fpga_core.sv | 3 + .../fb2CG/fpga/tb/fpga_core/test_fpga_core.py | 35 +- src/eth/rtl/taxi_axis_baser_rx_64.sv | 766 +++++------ src/eth/rtl/taxi_axis_baser_tx_64.sv | 740 +++++------ src/eth/rtl/taxi_eth_mac_phy_10g.sv | 22 +- src/eth/rtl/taxi_eth_mac_phy_10g_fifo.sv | 18 + src/eth/rtl/taxi_eth_mac_phy_10g_rx.sv | 13 + src/eth/rtl/taxi_eth_mac_phy_10g_tx.sv | 30 + src/eth/rtl/taxi_eth_phy_10g.sv | 28 + src/eth/rtl/taxi_eth_phy_10g_rx.sv | 19 +- src/eth/rtl/taxi_eth_phy_10g_rx_ber_mon.sv | 6 +- src/eth/rtl/taxi_eth_phy_10g_rx_frame_sync.sv | 4 + src/eth/rtl/taxi_eth_phy_10g_rx_if.sv | 48 +- src/eth/rtl/taxi_eth_phy_10g_rx_watchdog.sv | 4 +- src/eth/rtl/taxi_eth_phy_10g_tx.sv | 34 +- src/eth/rtl/taxi_eth_phy_10g_tx_if.sv | 58 +- src/eth/rtl/taxi_xgmii_baser_dec_64.sv | 23 +- src/eth/rtl/taxi_xgmii_baser_enc_64.sv | 40 +- src/eth/rtl/us/taxi_eth_mac_25g_us.f | 1 + src/eth/rtl/us/taxi_eth_mac_25g_us.sv | 6 + src/eth/rtl/us/taxi_eth_mac_25g_us_ch.sv | 334 +++-- src/eth/rtl/us/taxi_eth_phy_25g_us_gt.sv | 57 +- src/eth/rtl/us/taxi_eth_phy_25g_us_gt_ll.f | 6 + src/eth/rtl/us/taxi_eth_phy_25g_us_gt_ll.sv | 1127 +++++++++++++++++ .../us/taxi_eth_phy_25g_us_gth_10g_156.tcl | 34 +- .../us/taxi_eth_phy_25g_us_gth_10g_161.tcl | 34 +- .../us/taxi_eth_phy_25g_us_gth_10g_322.tcl | 34 +- .../us/taxi_eth_phy_25g_us_gty_10g_156.tcl | 34 +- .../us/taxi_eth_phy_25g_us_gty_10g_161.tcl | 34 +- .../us/taxi_eth_phy_25g_us_gty_10g_322.tcl | 34 +- .../us/taxi_eth_phy_25g_us_gty_25g_156.tcl | 34 +- .../us/taxi_eth_phy_25g_us_gty_25g_161.tcl | 34 +- .../us/taxi_eth_phy_25g_us_gty_25g_322.tcl | 34 +- src/eth/tb/baser.py | 253 +++- src/eth/tb/taxi_axis_baser_rx_64/Makefile | 1 + .../test_taxi_axis_baser_rx_64.py | 51 +- .../test_taxi_axis_baser_rx_64.sv | 6 + src/eth/tb/taxi_axis_baser_tx_64/Makefile | 2 + .../test_taxi_axis_baser_tx_64.py | 112 +- .../test_taxi_axis_baser_tx_64.sv | 13 + src/eth/tb/taxi_eth_mac_phy_10g/Makefile | 2 + .../test_taxi_eth_mac_phy_10g.py | 142 ++- .../test_taxi_eth_mac_phy_10g.sv | 18 + src/eth/tb/taxi_eth_mac_phy_10g_fifo/Makefile | 2 + .../test_taxi_eth_mac_phy_10g_fifo.py | 85 +- .../test_taxi_eth_mac_phy_10g_fifo.sv | 20 +- src/eth/tb/taxi_eth_phy_10g/Makefile | 2 + .../taxi_eth_phy_10g/test_taxi_eth_phy_10g.py | 26 +- src/eth/tb/taxi_xgmii_baser_dec_64/Makefile | 1 + .../test_taxi_xgmii_baser_dec_64.py | 4 + src/eth/tb/taxi_xgmii_baser_enc_64/Makefile | 1 + .../test_taxi_xgmii_baser_enc_64.py | 4 + 76 files changed, 3853 insertions(+), 1090 deletions(-) create mode 100644 src/eth/rtl/us/taxi_eth_phy_25g_us_gt_ll.f create mode 100644 src/eth/rtl/us/taxi_eth_phy_25g_us_gt_ll.sv diff --git a/src/eth/example/ADM_PCIE_9V3/fpga/rtl/fpga_core.sv b/src/eth/example/ADM_PCIE_9V3/fpga/rtl/fpga_core.sv index f3b71a6..5474300 100644 --- a/src/eth/example/ADM_PCIE_9V3/fpga/rtl/fpga_core.sv +++ b/src/eth/example/ADM_PCIE_9V3/fpga/rtl/fpga_core.sv @@ -145,6 +145,9 @@ for (genvar n = 0; n < 2; n = n + 1) begin : gty_quad .CNT(CNT), + // GT config + .CFG_LOW_LATENCY(1), + // GT type .GT_TYPE("GTY"), diff --git a/src/eth/example/ADM_PCIE_9V3/fpga/tb/fpga_core/test_fpga_core.py b/src/eth/example/ADM_PCIE_9V3/fpga/tb/fpga_core/test_fpga_core.py index 1fb82be..ec64926 100644 --- a/src/eth/example/ADM_PCIE_9V3/fpga/tb/fpga_core/test_fpga_core.py +++ b/src/eth/example/ADM_PCIE_9V3/fpga/tb/fpga_core/test_fpga_core.py @@ -48,11 +48,38 @@ class TB: for inst in dut.gty_quad: for ch in inst.mac_inst.ch: - cocotb.start_soon(Clock(ch.ch_inst.gt_inst.tx_clk, 2.56, units="ns").start()) - cocotb.start_soon(Clock(ch.ch_inst.gt_inst.rx_clk, 2.56, units="ns").start()) + gt_inst = ch.ch_inst.gt.gt_inst - self.qsfp_sources.append(BaseRSerdesSource(ch.ch_inst.serdes_rx_data, ch.ch_inst.serdes_rx_hdr, ch.ch_inst.gt_inst.rx_clk, slip=ch.ch_inst.serdes_rx_bitslip, reverse=True)) - self.qsfp_sinks.append(BaseRSerdesSink(ch.ch_inst.serdes_tx_data, ch.ch_inst.serdes_tx_hdr, ch.ch_inst.gt_inst.tx_clk, reverse=True)) + if ch.ch_inst.CFG_LOW_LATENCY.value: + clk = 2.482 + gbx_cfg = (66, [64, 65]) + else: + clk = 2.56 + gbx_cfg = None + + cocotb.start_soon(Clock(gt_inst.tx_clk, clk, units="ns").start()) + cocotb.start_soon(Clock(gt_inst.rx_clk, clk, units="ns").start()) + + self.qsfp_sources.append(BaseRSerdesSource( + data=gt_inst.serdes_rx_data, + data_valid=gt_inst.serdes_rx_data_valid, + hdr=gt_inst.serdes_rx_hdr, + hdr_valid=gt_inst.serdes_rx_hdr_valid, + clock=gt_inst.rx_clk, + slip=gt_inst.serdes_rx_bitslip, + reverse=True, + gbx_cfg=gbx_cfg + )) + self.qsfp_sinks.append(BaseRSerdesSink( + data=gt_inst.serdes_tx_data, + data_valid=gt_inst.serdes_tx_data_valid, + hdr=gt_inst.serdes_tx_hdr, + hdr_valid=gt_inst.serdes_tx_hdr_valid, + gbx_start=gt_inst.serdes_tx_gbx_start, + clock=gt_inst.tx_clk, + reverse=True, + gbx_cfg=gbx_cfg + )) dut.user_sw.setimmediatevalue(0) diff --git a/src/eth/example/Alveo/fpga/rtl/fpga_core.sv b/src/eth/example/Alveo/fpga/rtl/fpga_core.sv index 07eaf1e..be12700 100644 --- a/src/eth/example/Alveo/fpga/rtl/fpga_core.sv +++ b/src/eth/example/Alveo/fpga/rtl/fpga_core.sv @@ -299,6 +299,9 @@ for (genvar n = 0; n < GTY_QUAD_CNT; n = n + 1) begin : gty_quad .CNT(CNT), + // GT config + .CFG_LOW_LATENCY(1), + // GT type .GT_TYPE("GTY"), diff --git a/src/eth/example/Alveo/fpga/tb/fpga_core/test_fpga_core.py b/src/eth/example/Alveo/fpga/tb/fpga_core/test_fpga_core.py index 8fb8e31..a157558 100644 --- a/src/eth/example/Alveo/fpga/tb/fpga_core/test_fpga_core.py +++ b/src/eth/example/Alveo/fpga/tb/fpga_core/test_fpga_core.py @@ -51,11 +51,38 @@ class TB: for inst in dut.gty_quad: for ch in inst.mac_inst.ch: - cocotb.start_soon(Clock(ch.ch_inst.gt_inst.tx_clk, 2.56, units="ns").start()) - cocotb.start_soon(Clock(ch.ch_inst.gt_inst.rx_clk, 2.56, units="ns").start()) + gt_inst = ch.ch_inst.gt.gt_inst - self.qsfp_sources.append(BaseRSerdesSource(ch.ch_inst.serdes_rx_data, ch.ch_inst.serdes_rx_hdr, ch.ch_inst.gt_inst.rx_clk, slip=ch.ch_inst.serdes_rx_bitslip, reverse=True)) - self.qsfp_sinks.append(BaseRSerdesSink(ch.ch_inst.serdes_tx_data, ch.ch_inst.serdes_tx_hdr, ch.ch_inst.gt_inst.tx_clk, reverse=True)) + if ch.ch_inst.CFG_LOW_LATENCY.value: + clk = 2.482 + gbx_cfg = (66, [64, 65]) + else: + clk = 2.56 + gbx_cfg = None + + cocotb.start_soon(Clock(gt_inst.tx_clk, clk, units="ns").start()) + cocotb.start_soon(Clock(gt_inst.rx_clk, clk, units="ns").start()) + + self.qsfp_sources.append(BaseRSerdesSource( + data=gt_inst.serdes_rx_data, + data_valid=gt_inst.serdes_rx_data_valid, + hdr=gt_inst.serdes_rx_hdr, + hdr_valid=gt_inst.serdes_rx_hdr_valid, + clock=gt_inst.rx_clk, + slip=gt_inst.serdes_rx_bitslip, + reverse=True, + gbx_cfg=gbx_cfg + )) + self.qsfp_sinks.append(BaseRSerdesSink( + data=gt_inst.serdes_tx_data, + data_valid=gt_inst.serdes_tx_data_valid, + hdr=gt_inst.serdes_tx_hdr, + hdr_valid=gt_inst.serdes_tx_hdr_valid, + gbx_start=gt_inst.serdes_tx_gbx_start, + clock=gt_inst.tx_clk, + reverse=True, + gbx_cfg=gbx_cfg + )) dut.sw.setimmediatevalue(0) dut.eth_port_modprsl.setimmediatevalue(0) diff --git a/src/eth/example/KCU105/fpga/rtl/fpga_core.sv b/src/eth/example/KCU105/fpga/rtl/fpga_core.sv index 37b7a85..ba40e82 100644 --- a/src/eth/example/KCU105/fpga/rtl/fpga_core.sv +++ b/src/eth/example/KCU105/fpga/rtl/fpga_core.sv @@ -535,6 +535,9 @@ end else begin : sfp_mac .CNT(2), + // GT config + .CFG_LOW_LATENCY(1), + // GT type .GT_TYPE("GTH"), diff --git a/src/eth/example/KCU105/fpga/tb/fpga_core/test_fpga_core.py b/src/eth/example/KCU105/fpga/tb/fpga_core/test_fpga_core.py index 5579af0..b46b99a 100644 --- a/src/eth/example/KCU105/fpga/tb/fpga_core/test_fpga_core.py +++ b/src/eth/example/KCU105/fpga/tb/fpga_core/test_fpga_core.py @@ -71,11 +71,38 @@ class TB: cocotb.start_soon(Clock(dut.sfp_mgt_refclk_0_p, 6.4, units="ns").start()) for ch in dut.sfp_mac.sfp_mac_inst.ch: - cocotb.start_soon(Clock(ch.ch_inst.gt_inst.tx_clk, 6.4, units="ns").start()) - cocotb.start_soon(Clock(ch.ch_inst.gt_inst.rx_clk, 6.4, units="ns").start()) + gt_inst = ch.ch_inst.gt.gt_inst - self.sfp_sources.append(BaseRSerdesSource(ch.ch_inst.serdes_rx_data, ch.ch_inst.serdes_rx_hdr, ch.ch_inst.gt_inst.rx_clk, slip=ch.ch_inst.serdes_rx_bitslip, reverse=True)) - self.sfp_sinks.append(BaseRSerdesSink(ch.ch_inst.serdes_tx_data, ch.ch_inst.serdes_tx_hdr, ch.ch_inst.gt_inst.tx_clk, reverse=True)) + if ch.ch_inst.CFG_LOW_LATENCY.value: + clk = 6.206 + gbx_cfg = (33, [32]) + else: + clk = 6.4 + gbx_cfg = None + + cocotb.start_soon(Clock(gt_inst.tx_clk, clk, units="ns").start()) + cocotb.start_soon(Clock(gt_inst.rx_clk, clk, units="ns").start()) + + self.sfp_sources.append(BaseRSerdesSource( + data=gt_inst.serdes_rx_data, + data_valid=gt_inst.serdes_rx_data_valid, + hdr=gt_inst.serdes_rx_hdr, + hdr_valid=gt_inst.serdes_rx_hdr_valid, + clock=gt_inst.rx_clk, + slip=gt_inst.serdes_rx_bitslip, + reverse=True, + gbx_cfg=gbx_cfg + )) + self.sfp_sinks.append(BaseRSerdesSink( + data=gt_inst.serdes_tx_data, + data_valid=gt_inst.serdes_tx_data_valid, + hdr=gt_inst.serdes_tx_hdr, + hdr_valid=gt_inst.serdes_tx_hdr_valid, + gbx_start=gt_inst.serdes_tx_gbx_start, + clock=gt_inst.tx_clk, + reverse=True, + gbx_cfg=gbx_cfg + )) self.uart_source = UartSource(dut.uart_rxd, baud=921600, bits=8, stop_bits=1) self.uart_sink = UartSink(dut.uart_txd, baud=921600, bits=8, stop_bits=1) diff --git a/src/eth/example/KR260/fpga/rtl/fpga_core.sv b/src/eth/example/KR260/fpga/rtl/fpga_core.sv index 7bb878a..993aa99 100644 --- a/src/eth/example/KR260/fpga/rtl/fpga_core.sv +++ b/src/eth/example/KR260/fpga/rtl/fpga_core.sv @@ -402,6 +402,9 @@ end else begin : sfp_mac .CNT(1), + // GT config + .CFG_LOW_LATENCY(1), + // GT type .GT_TYPE("GTH"), diff --git a/src/eth/example/KR260/fpga/tb/fpga_core/test_fpga_core.py b/src/eth/example/KR260/fpga/tb/fpga_core/test_fpga_core.py index 7f4b287..b8cf405 100644 --- a/src/eth/example/KR260/fpga/tb/fpga_core/test_fpga_core.py +++ b/src/eth/example/KR260/fpga/tb/fpga_core/test_fpga_core.py @@ -48,23 +48,52 @@ class TB: self.baset_phy3 = RgmiiPhy(dut.phy3_rgmii_txd, dut.phy3_rgmii_tx_ctl, dut.phy3_rgmii_tx_clk, dut.phy3_rgmii_rxd, dut.phy3_rgmii_rx_ctl, dut.phy3_rgmii_rx_clk, speed=speed) + self.sfp_sources = [] + self.sfp_sinks = [] + if dut.SFP_RATE.value == 0: cocotb.start_soon(Clock(dut.sfp_gmii_clk, 8, units="ns").start()) - self.sfp_source = GmiiSource(dut.sfp_gmii_rxd, dut.sfp_gmii_rx_er, dut.sfp_gmii_rx_dv, - dut.sfp_gmii_clk, dut.sfp_gmii_rst, dut.sfp_gmii_clk_en) - self.sfp_sink = GmiiSink(dut.sfp_gmii_txd, dut.sfp_gmii_tx_er, dut.sfp_gmii_tx_en, - dut.sfp_gmii_clk, dut.sfp_gmii_rst, dut.sfp_gmii_clk_en) + self.sfp_sources.append(GmiiSource(dut.sfp_gmii_rxd, dut.sfp_gmii_rx_er, dut.sfp_gmii_rx_dv, + dut.sfp_gmii_clk, dut.sfp_gmii_rst, dut.sfp_gmii_clk_en)) + self.sfp_sinks.append(GmiiSink(dut.sfp_gmii_txd, dut.sfp_gmii_tx_er, dut.sfp_gmii_tx_en, + dut.sfp_gmii_clk, dut.sfp_gmii_rst, dut.sfp_gmii_clk_en)) else: cocotb.start_soon(Clock(dut.sfp_mgt_refclk_p, 6.4, units="ns").start()) ch = dut.sfp_mac.sfp_mac_inst.ch[0] + gt_inst = ch.ch_inst.gt.gt_inst - cocotb.start_soon(Clock(ch.ch_inst.gt_inst.tx_clk, 6.4, units="ns").start()) - cocotb.start_soon(Clock(ch.ch_inst.gt_inst.rx_clk, 6.4, units="ns").start()) + if ch.ch_inst.CFG_LOW_LATENCY.value: + clk = 6.206 + gbx_cfg = (33, [32]) + else: + clk = 6.4 + gbx_cfg = None - self.sfp_source = BaseRSerdesSource(ch.ch_inst.serdes_rx_data, ch.ch_inst.serdes_rx_hdr, ch.ch_inst.gt_inst.rx_clk, slip=ch.ch_inst.serdes_rx_bitslip, reverse=True) - self.sfp_sink = BaseRSerdesSink(ch.ch_inst.serdes_tx_data, ch.ch_inst.serdes_tx_hdr, ch.ch_inst.gt_inst.tx_clk, reverse=True) + cocotb.start_soon(Clock(gt_inst.tx_clk, clk, units="ns").start()) + cocotb.start_soon(Clock(gt_inst.rx_clk, clk, units="ns").start()) + + self.sfp_sources.append(BaseRSerdesSource( + data=gt_inst.serdes_rx_data, + data_valid=gt_inst.serdes_rx_data_valid, + hdr=gt_inst.serdes_rx_hdr, + hdr_valid=gt_inst.serdes_rx_hdr_valid, + clock=gt_inst.rx_clk, + slip=gt_inst.serdes_rx_bitslip, + reverse=True, + gbx_cfg=gbx_cfg + )) + self.sfp_sinks.append(BaseRSerdesSink( + data=gt_inst.serdes_tx_data, + data_valid=gt_inst.serdes_tx_data_valid, + hdr=gt_inst.serdes_tx_hdr, + hdr_valid=gt_inst.serdes_tx_hdr_valid, + gbx_start=gt_inst.serdes_tx_gbx_start, + clock=gt_inst.tx_clk, + reverse=True, + gbx_cfg=gbx_cfg + )) cocotb.start_soon(self._run_clk()) @@ -206,10 +235,10 @@ async def run_test(dut): if dut.SFP_RATE.value == 0: tb.log.info("Start 1G SFP MAC loopback test") - tests.append(cocotb.start_soon(mac_test(tb, tb.sfp_source, tb.sfp_sink))) + tests.append(cocotb.start_soon(mac_test(tb, tb.sfp_sources[0], tb.sfp_sinks[0]))) else: tb.log.info("Start 10G SFP MAC loopback test") - tests.append(cocotb.start_soon(mac_test_10g(tb, tb.sfp_source, tb.sfp_sink))) + tests.append(cocotb.start_soon(mac_test_10g(tb, tb.sfp_sources[0], tb.sfp_sinks[0]))) await Combine(*tests) diff --git a/src/eth/example/Nexus_K3P_Q/fpga/rtl/fpga_core.sv b/src/eth/example/Nexus_K3P_Q/fpga/rtl/fpga_core.sv index 31bed57..b85bd1d 100644 --- a/src/eth/example/Nexus_K3P_Q/fpga/rtl/fpga_core.sv +++ b/src/eth/example/Nexus_K3P_Q/fpga/rtl/fpga_core.sv @@ -160,6 +160,9 @@ for (genvar n = 0; n < 2; n = n + 1) begin : gty_quad .CNT(4), + // GT config + .CFG_LOW_LATENCY(1), + // GT type .GT_TYPE("GTY"), diff --git a/src/eth/example/Nexus_K3P_Q/fpga/tb/fpga_core/test_fpga_core.py b/src/eth/example/Nexus_K3P_Q/fpga/tb/fpga_core/test_fpga_core.py index 96acf54..2e6d516 100644 --- a/src/eth/example/Nexus_K3P_Q/fpga/tb/fpga_core/test_fpga_core.py +++ b/src/eth/example/Nexus_K3P_Q/fpga/tb/fpga_core/test_fpga_core.py @@ -48,11 +48,38 @@ class TB: for inst in dut.gty_quad: for ch in inst.mac_inst.ch: - cocotb.start_soon(Clock(ch.ch_inst.gt_inst.tx_clk, 2.56, units="ns").start()) - cocotb.start_soon(Clock(ch.ch_inst.gt_inst.rx_clk, 2.56, units="ns").start()) + gt_inst = ch.ch_inst.gt.gt_inst - self.qsfp_sources.append(BaseRSerdesSource(ch.ch_inst.serdes_rx_data, ch.ch_inst.serdes_rx_hdr, ch.ch_inst.gt_inst.rx_clk, slip=ch.ch_inst.serdes_rx_bitslip, reverse=True)) - self.qsfp_sinks.append(BaseRSerdesSink(ch.ch_inst.serdes_tx_data, ch.ch_inst.serdes_tx_hdr, ch.ch_inst.gt_inst.tx_clk, reverse=True)) + if ch.ch_inst.CFG_LOW_LATENCY.value: + clk = 2.482 + gbx_cfg = (66, [64, 65]) + else: + clk = 2.56 + gbx_cfg = None + + cocotb.start_soon(Clock(gt_inst.tx_clk, clk, units="ns").start()) + cocotb.start_soon(Clock(gt_inst.rx_clk, clk, units="ns").start()) + + self.qsfp_sources.append(BaseRSerdesSource( + data=gt_inst.serdes_rx_data, + data_valid=gt_inst.serdes_rx_data_valid, + hdr=gt_inst.serdes_rx_hdr, + hdr_valid=gt_inst.serdes_rx_hdr_valid, + clock=gt_inst.rx_clk, + slip=gt_inst.serdes_rx_bitslip, + reverse=True, + gbx_cfg=gbx_cfg + )) + self.qsfp_sinks.append(BaseRSerdesSink( + data=gt_inst.serdes_tx_data, + data_valid=gt_inst.serdes_tx_data_valid, + hdr=gt_inst.serdes_tx_hdr, + hdr_valid=gt_inst.serdes_tx_hdr_valid, + gbx_start=gt_inst.serdes_tx_gbx_start, + clock=gt_inst.tx_clk, + reverse=True, + gbx_cfg=gbx_cfg + )) dut.qsfp_0_modprsl.setimmediatevalue(0) dut.qsfp_0_intl.setimmediatevalue(0) diff --git a/src/eth/example/Nexus_K3P_S/fpga/rtl/fpga_core.sv b/src/eth/example/Nexus_K3P_S/fpga/rtl/fpga_core.sv index 6ad72ee..87678c0 100644 --- a/src/eth/example/Nexus_K3P_S/fpga/rtl/fpga_core.sv +++ b/src/eth/example/Nexus_K3P_S/fpga/rtl/fpga_core.sv @@ -141,6 +141,9 @@ taxi_eth_mac_25g_us #( .CNT(2), + // GT config + .CFG_LOW_LATENCY(1), + // GT type .GT_TYPE(FAMILY == "kintexu" ? "GTH" : "GTY"), diff --git a/src/eth/example/Nexus_K3P_S/fpga/tb/fpga_core/test_fpga_core.py b/src/eth/example/Nexus_K3P_S/fpga/tb/fpga_core/test_fpga_core.py index 68f0c80..99ef168 100644 --- a/src/eth/example/Nexus_K3P_S/fpga/tb/fpga_core/test_fpga_core.py +++ b/src/eth/example/Nexus_K3P_S/fpga/tb/fpga_core/test_fpga_core.py @@ -47,11 +47,38 @@ class TB: self.sfp_sinks = [] for ch in dut.sfp_mac_inst.ch: - cocotb.start_soon(Clock(ch.ch_inst.gt_inst.tx_clk, 2.56, units="ns").start()) - cocotb.start_soon(Clock(ch.ch_inst.gt_inst.rx_clk, 2.56, units="ns").start()) + gt_inst = ch.ch_inst.gt.gt_inst - self.sfp_sources.append(BaseRSerdesSource(ch.ch_inst.serdes_rx_data, ch.ch_inst.serdes_rx_hdr, ch.ch_inst.gt_inst.rx_clk, slip=ch.ch_inst.serdes_rx_bitslip, reverse=True)) - self.sfp_sinks.append(BaseRSerdesSink(ch.ch_inst.serdes_tx_data, ch.ch_inst.serdes_tx_hdr, ch.ch_inst.gt_inst.tx_clk, reverse=True)) + if ch.ch_inst.CFG_LOW_LATENCY.value: + clk = 2.482 + gbx_cfg = (66, [64, 65]) + else: + clk = 2.56 + gbx_cfg = None + + cocotb.start_soon(Clock(gt_inst.tx_clk, clk, units="ns").start()) + cocotb.start_soon(Clock(gt_inst.rx_clk, clk, units="ns").start()) + + self.sfp_sources.append(BaseRSerdesSource( + data=gt_inst.serdes_rx_data, + data_valid=gt_inst.serdes_rx_data_valid, + hdr=gt_inst.serdes_rx_hdr, + hdr_valid=gt_inst.serdes_rx_hdr_valid, + clock=gt_inst.rx_clk, + slip=gt_inst.serdes_rx_bitslip, + reverse=True, + gbx_cfg=gbx_cfg + )) + self.sfp_sinks.append(BaseRSerdesSink( + data=gt_inst.serdes_tx_data, + data_valid=gt_inst.serdes_tx_data_valid, + hdr=gt_inst.serdes_tx_hdr, + hdr_valid=gt_inst.serdes_tx_hdr_valid, + gbx_start=gt_inst.serdes_tx_gbx_start, + clock=gt_inst.tx_clk, + reverse=True, + gbx_cfg=gbx_cfg + )) dut.sfp_npres.setimmediatevalue(0) dut.sfp_los.setimmediatevalue(0) diff --git a/src/eth/example/VCU108/fpga/rtl/fpga_core.sv b/src/eth/example/VCU108/fpga/rtl/fpga_core.sv index eecc0a6..c69dc64 100644 --- a/src/eth/example/VCU108/fpga/rtl/fpga_core.sv +++ b/src/eth/example/VCU108/fpga/rtl/fpga_core.sv @@ -348,6 +348,9 @@ taxi_eth_mac_25g_us #( .CNT(4), + // GT config + .CFG_LOW_LATENCY(1), + // GT type .GT_TYPE("GTY"), diff --git a/src/eth/example/VCU108/fpga/tb/fpga_core/test_fpga_core.py b/src/eth/example/VCU108/fpga/tb/fpga_core/test_fpga_core.py index 5dd219e..59a8b5e 100644 --- a/src/eth/example/VCU108/fpga/tb/fpga_core/test_fpga_core.py +++ b/src/eth/example/VCU108/fpga/tb/fpga_core/test_fpga_core.py @@ -58,11 +58,38 @@ class TB: self.qsfp_sinks = [] for ch in dut.qsfp_mac_inst.ch: - cocotb.start_soon(Clock(ch.ch_inst.gt_inst.tx_clk, 2.56, units="ns").start()) - cocotb.start_soon(Clock(ch.ch_inst.gt_inst.rx_clk, 2.56, units="ns").start()) + gt_inst = ch.ch_inst.gt.gt_inst - self.qsfp_sources.append(BaseRSerdesSource(ch.ch_inst.serdes_rx_data, ch.ch_inst.serdes_rx_hdr, ch.ch_inst.gt_inst.rx_clk, slip=ch.ch_inst.serdes_rx_bitslip, reverse=True)) - self.qsfp_sinks.append(BaseRSerdesSink(ch.ch_inst.serdes_tx_data, ch.ch_inst.serdes_tx_hdr, ch.ch_inst.gt_inst.tx_clk, reverse=True)) + if ch.ch_inst.CFG_LOW_LATENCY.value: + clk = 2.482 + gbx_cfg = (66, [64, 65]) + else: + clk = 2.56 + gbx_cfg = None + + cocotb.start_soon(Clock(gt_inst.tx_clk, clk, units="ns").start()) + cocotb.start_soon(Clock(gt_inst.rx_clk, clk, units="ns").start()) + + self.qsfp_sources.append(BaseRSerdesSource( + data=gt_inst.serdes_rx_data, + data_valid=gt_inst.serdes_rx_data_valid, + hdr=gt_inst.serdes_rx_hdr, + hdr_valid=gt_inst.serdes_rx_hdr_valid, + clock=gt_inst.rx_clk, + slip=gt_inst.serdes_rx_bitslip, + reverse=True, + gbx_cfg=gbx_cfg + )) + self.qsfp_sinks.append(BaseRSerdesSink( + data=gt_inst.serdes_tx_data, + data_valid=gt_inst.serdes_tx_data_valid, + hdr=gt_inst.serdes_tx_hdr, + hdr_valid=gt_inst.serdes_tx_hdr_valid, + gbx_start=gt_inst.serdes_tx_gbx_start, + clock=gt_inst.tx_clk, + reverse=True, + gbx_cfg=gbx_cfg + )) dut.phy_gmii_clk_en.setimmediatevalue(1) diff --git a/src/eth/example/VCU118/fpga/rtl/fpga_core.sv b/src/eth/example/VCU118/fpga/rtl/fpga_core.sv index ac521fd..b300c04 100644 --- a/src/eth/example/VCU118/fpga/rtl/fpga_core.sv +++ b/src/eth/example/VCU118/fpga/rtl/fpga_core.sv @@ -544,6 +544,9 @@ for (genvar n = 0; n < 2; n = n + 1) begin : gty_quad .CNT(4), + // GT config + .CFG_LOW_LATENCY(1), + // GT type .GT_TYPE("GTY"), diff --git a/src/eth/example/VCU118/fpga/tb/fpga_core/test_fpga_core.py b/src/eth/example/VCU118/fpga/tb/fpga_core/test_fpga_core.py index 8db5d1d..f2275c9 100644 --- a/src/eth/example/VCU118/fpga/tb/fpga_core/test_fpga_core.py +++ b/src/eth/example/VCU118/fpga/tb/fpga_core/test_fpga_core.py @@ -59,11 +59,38 @@ class TB: for inst in dut.gty_quad: for ch in inst.mac_inst.ch: - cocotb.start_soon(Clock(ch.ch_inst.gt_inst.tx_clk, 2.56, units="ns").start()) - cocotb.start_soon(Clock(ch.ch_inst.gt_inst.rx_clk, 2.56, units="ns").start()) + gt_inst = ch.ch_inst.gt.gt_inst - self.qsfp_sources.append(BaseRSerdesSource(ch.ch_inst.serdes_rx_data, ch.ch_inst.serdes_rx_hdr, ch.ch_inst.gt_inst.rx_clk, slip=ch.ch_inst.serdes_rx_bitslip, reverse=True)) - self.qsfp_sinks.append(BaseRSerdesSink(ch.ch_inst.serdes_tx_data, ch.ch_inst.serdes_tx_hdr, ch.ch_inst.gt_inst.tx_clk, reverse=True)) + if ch.ch_inst.CFG_LOW_LATENCY.value: + clk = 2.482 + gbx_cfg = (66, [64, 65]) + else: + clk = 2.56 + gbx_cfg = None + + cocotb.start_soon(Clock(gt_inst.tx_clk, clk, units="ns").start()) + cocotb.start_soon(Clock(gt_inst.rx_clk, clk, units="ns").start()) + + self.qsfp_sources.append(BaseRSerdesSource( + data=gt_inst.serdes_rx_data, + data_valid=gt_inst.serdes_rx_data_valid, + hdr=gt_inst.serdes_rx_hdr, + hdr_valid=gt_inst.serdes_rx_hdr_valid, + clock=gt_inst.rx_clk, + slip=gt_inst.serdes_rx_bitslip, + reverse=True, + gbx_cfg=gbx_cfg + )) + self.qsfp_sinks.append(BaseRSerdesSink( + data=gt_inst.serdes_tx_data, + data_valid=gt_inst.serdes_tx_data_valid, + hdr=gt_inst.serdes_tx_hdr, + hdr_valid=gt_inst.serdes_tx_hdr_valid, + gbx_start=gt_inst.serdes_tx_gbx_start, + clock=gt_inst.tx_clk, + reverse=True, + gbx_cfg=gbx_cfg + )) dut.phy_gmii_clk_en.setimmediatevalue(1) diff --git a/src/eth/example/XUPP3R/fpga/rtl/fpga_core.sv b/src/eth/example/XUPP3R/fpga/rtl/fpga_core.sv index 2d629fc..468fc24 100644 --- a/src/eth/example/XUPP3R/fpga/rtl/fpga_core.sv +++ b/src/eth/example/XUPP3R/fpga/rtl/fpga_core.sv @@ -355,6 +355,9 @@ for (genvar n = 0; n < GTY_QUAD_CNT; n = n + 1) begin : gty_quad .CNT(4), + // GT config + .CFG_LOW_LATENCY(1), + // GT type .GT_TYPE("GTY"), diff --git a/src/eth/example/XUPP3R/fpga/tb/fpga_core/test_fpga_core.py b/src/eth/example/XUPP3R/fpga/tb/fpga_core/test_fpga_core.py index 290d223..2ce4006 100644 --- a/src/eth/example/XUPP3R/fpga/tb/fpga_core/test_fpga_core.py +++ b/src/eth/example/XUPP3R/fpga/tb/fpga_core/test_fpga_core.py @@ -55,11 +55,38 @@ class TB: for inst in dut.gty_quad: for ch in inst.mac_inst.ch: - cocotb.start_soon(Clock(ch.ch_inst.gt_inst.tx_clk, 2.56, units="ns").start()) - cocotb.start_soon(Clock(ch.ch_inst.gt_inst.rx_clk, 2.56, units="ns").start()) + gt_inst = ch.ch_inst.gt.gt_inst - self.qsfp_sources.append(BaseRSerdesSource(ch.ch_inst.serdes_rx_data, ch.ch_inst.serdes_rx_hdr, ch.ch_inst.gt_inst.rx_clk, slip=ch.ch_inst.serdes_rx_bitslip, reverse=True)) - self.qsfp_sinks.append(BaseRSerdesSink(ch.ch_inst.serdes_tx_data, ch.ch_inst.serdes_tx_hdr, ch.ch_inst.gt_inst.tx_clk, reverse=True)) + if ch.ch_inst.CFG_LOW_LATENCY.value: + clk = 2.482 + gbx_cfg = (66, [64, 65]) + else: + clk = 2.56 + gbx_cfg = None + + cocotb.start_soon(Clock(gt_inst.tx_clk, clk, units="ns").start()) + cocotb.start_soon(Clock(gt_inst.rx_clk, clk, units="ns").start()) + + self.qsfp_sources.append(BaseRSerdesSource( + data=gt_inst.serdes_rx_data, + data_valid=gt_inst.serdes_rx_data_valid, + hdr=gt_inst.serdes_rx_hdr, + hdr_valid=gt_inst.serdes_rx_hdr_valid, + clock=gt_inst.rx_clk, + slip=gt_inst.serdes_rx_bitslip, + reverse=True, + gbx_cfg=gbx_cfg + )) + self.qsfp_sinks.append(BaseRSerdesSink( + data=gt_inst.serdes_tx_data, + data_valid=gt_inst.serdes_tx_data_valid, + hdr=gt_inst.serdes_tx_hdr, + hdr_valid=gt_inst.serdes_tx_hdr_valid, + gbx_start=gt_inst.serdes_tx_gbx_start, + clock=gt_inst.tx_clk, + reverse=True, + gbx_cfg=gbx_cfg + )) async def init(self): diff --git a/src/eth/example/ZCU102/fpga/rtl/fpga_core.sv b/src/eth/example/ZCU102/fpga/rtl/fpga_core.sv index 8567061..4eab118 100644 --- a/src/eth/example/ZCU102/fpga/rtl/fpga_core.sv +++ b/src/eth/example/ZCU102/fpga/rtl/fpga_core.sv @@ -622,6 +622,9 @@ end else begin : sfp_mac .CNT(4), + // GT config + .CFG_LOW_LATENCY(1), + // GT type .GT_TYPE("GTH"), diff --git a/src/eth/example/ZCU102/fpga/tb/fpga_core/test_fpga_core.py b/src/eth/example/ZCU102/fpga/tb/fpga_core/test_fpga_core.py index d32f138..23e590f 100644 --- a/src/eth/example/ZCU102/fpga/tb/fpga_core/test_fpga_core.py +++ b/src/eth/example/ZCU102/fpga/tb/fpga_core/test_fpga_core.py @@ -77,11 +77,38 @@ class TB: cocotb.start_soon(Clock(dut.sfp_mgt_refclk_0_p, 6.4, units="ns").start()) for ch in dut.sfp_mac.sfp_mac_inst.ch: - cocotb.start_soon(Clock(ch.ch_inst.gt_inst.tx_clk, 6.4, units="ns").start()) - cocotb.start_soon(Clock(ch.ch_inst.gt_inst.rx_clk, 6.4, units="ns").start()) + gt_inst = ch.ch_inst.gt.gt_inst - self.sfp_sources.append(BaseRSerdesSource(ch.ch_inst.serdes_rx_data, ch.ch_inst.serdes_rx_hdr, ch.ch_inst.gt_inst.rx_clk, slip=ch.ch_inst.serdes_rx_bitslip, reverse=True)) - self.sfp_sinks.append(BaseRSerdesSink(ch.ch_inst.serdes_tx_data, ch.ch_inst.serdes_tx_hdr, ch.ch_inst.gt_inst.tx_clk, reverse=True)) + if ch.ch_inst.CFG_LOW_LATENCY.value: + clk = 6.206 + gbx_cfg = (33, [32]) + else: + clk = 6.4 + gbx_cfg = None + + cocotb.start_soon(Clock(gt_inst.tx_clk, clk, units="ns").start()) + cocotb.start_soon(Clock(gt_inst.rx_clk, clk, units="ns").start()) + + self.sfp_sources.append(BaseRSerdesSource( + data=gt_inst.serdes_rx_data, + data_valid=gt_inst.serdes_rx_data_valid, + hdr=gt_inst.serdes_rx_hdr, + hdr_valid=gt_inst.serdes_rx_hdr_valid, + clock=gt_inst.rx_clk, + slip=gt_inst.serdes_rx_bitslip, + reverse=True, + gbx_cfg=gbx_cfg + )) + self.sfp_sinks.append(BaseRSerdesSink( + data=gt_inst.serdes_tx_data, + data_valid=gt_inst.serdes_tx_data_valid, + hdr=gt_inst.serdes_tx_hdr, + hdr_valid=gt_inst.serdes_tx_hdr_valid, + gbx_start=gt_inst.serdes_tx_gbx_start, + clock=gt_inst.tx_clk, + reverse=True, + gbx_cfg=gbx_cfg + )) self.uart_source = UartSource(dut.uart_rxd, baud=2000000, bits=8, stop_bits=1) self.uart_sink = UartSink(dut.uart_txd, baud=2000000, bits=8, stop_bits=1) diff --git a/src/eth/example/ZCU106/fpga/rtl/fpga_core.sv b/src/eth/example/ZCU106/fpga/rtl/fpga_core.sv index 231568f..3dec0fb 100644 --- a/src/eth/example/ZCU106/fpga/rtl/fpga_core.sv +++ b/src/eth/example/ZCU106/fpga/rtl/fpga_core.sv @@ -432,6 +432,9 @@ end else begin : sfp_mac .CNT(2), + // GT config + .CFG_LOW_LATENCY(1), + // GT type .GT_TYPE("GTH"), diff --git a/src/eth/example/ZCU106/fpga/tb/fpga_core/test_fpga_core.py b/src/eth/example/ZCU106/fpga/tb/fpga_core/test_fpga_core.py index b6fad36..12ff110 100644 --- a/src/eth/example/ZCU106/fpga/tb/fpga_core/test_fpga_core.py +++ b/src/eth/example/ZCU106/fpga/tb/fpga_core/test_fpga_core.py @@ -65,11 +65,38 @@ class TB: cocotb.start_soon(Clock(dut.sfp_mgt_refclk_0_p, 6.4, units="ns").start()) for ch in dut.sfp_mac.sfp_mac_inst.ch: - cocotb.start_soon(Clock(ch.ch_inst.gt_inst.tx_clk, 6.4, units="ns").start()) - cocotb.start_soon(Clock(ch.ch_inst.gt_inst.rx_clk, 6.4, units="ns").start()) + gt_inst = ch.ch_inst.gt.gt_inst - self.sfp_sources.append(BaseRSerdesSource(ch.ch_inst.serdes_rx_data, ch.ch_inst.serdes_rx_hdr, ch.ch_inst.gt_inst.rx_clk, slip=ch.ch_inst.serdes_rx_bitslip, reverse=True)) - self.sfp_sinks.append(BaseRSerdesSink(ch.ch_inst.serdes_tx_data, ch.ch_inst.serdes_tx_hdr, ch.ch_inst.gt_inst.tx_clk, reverse=True)) + if ch.ch_inst.CFG_LOW_LATENCY.value: + clk = 6.206 + gbx_cfg = (33, [32]) + else: + clk = 6.4 + gbx_cfg = None + + cocotb.start_soon(Clock(gt_inst.tx_clk, clk, units="ns").start()) + cocotb.start_soon(Clock(gt_inst.rx_clk, clk, units="ns").start()) + + self.sfp_sources.append(BaseRSerdesSource( + data=gt_inst.serdes_rx_data, + data_valid=gt_inst.serdes_rx_data_valid, + hdr=gt_inst.serdes_rx_hdr, + hdr_valid=gt_inst.serdes_rx_hdr_valid, + clock=gt_inst.rx_clk, + slip=gt_inst.serdes_rx_bitslip, + reverse=True, + gbx_cfg=gbx_cfg + )) + self.sfp_sinks.append(BaseRSerdesSink( + data=gt_inst.serdes_tx_data, + data_valid=gt_inst.serdes_tx_data_valid, + hdr=gt_inst.serdes_tx_hdr, + hdr_valid=gt_inst.serdes_tx_hdr_valid, + gbx_start=gt_inst.serdes_tx_gbx_start, + clock=gt_inst.tx_clk, + reverse=True, + gbx_cfg=gbx_cfg + )) self.uart_source = UartSource(dut.uart_rxd, baud=2000000, bits=8, stop_bits=1) self.uart_sink = UartSink(dut.uart_txd, baud=2000000, bits=8, stop_bits=1) diff --git a/src/eth/example/ZCU111/fpga/rtl/fpga_core.sv b/src/eth/example/ZCU111/fpga/rtl/fpga_core.sv index e7a155a..96584ac 100644 --- a/src/eth/example/ZCU111/fpga/rtl/fpga_core.sv +++ b/src/eth/example/ZCU111/fpga/rtl/fpga_core.sv @@ -236,6 +236,9 @@ taxi_eth_mac_25g_us #( .CNT(4), + // GT config + .CFG_LOW_LATENCY(1), + // GT type .GT_TYPE("GTY"), diff --git a/src/eth/example/ZCU111/fpga/tb/fpga_core/test_fpga_core.py b/src/eth/example/ZCU111/fpga/tb/fpga_core/test_fpga_core.py index 1adba08..8b6384d 100644 --- a/src/eth/example/ZCU111/fpga/tb/fpga_core/test_fpga_core.py +++ b/src/eth/example/ZCU111/fpga/tb/fpga_core/test_fpga_core.py @@ -49,11 +49,38 @@ class TB: cocotb.start_soon(Clock(dut.sfp_mgt_refclk_0_p, 6.4, units="ns").start()) for ch in dut.sfp_mac_inst.ch: - cocotb.start_soon(Clock(ch.ch_inst.gt_inst.tx_clk, 6.4, units="ns").start()) - cocotb.start_soon(Clock(ch.ch_inst.gt_inst.rx_clk, 6.4, units="ns").start()) + gt_inst = ch.ch_inst.gt.gt_inst - self.sfp_sources.append(BaseRSerdesSource(ch.ch_inst.serdes_rx_data, ch.ch_inst.serdes_rx_hdr, ch.ch_inst.gt_inst.rx_clk, slip=ch.ch_inst.serdes_rx_bitslip, reverse=True)) - self.sfp_sinks.append(BaseRSerdesSink(ch.ch_inst.serdes_tx_data, ch.ch_inst.serdes_tx_hdr, ch.ch_inst.gt_inst.tx_clk, reverse=True)) + if ch.ch_inst.CFG_LOW_LATENCY.value: + clk = 2.482 + gbx_cfg = (66, [64, 65]) + else: + clk = 2.56 + gbx_cfg = None + + cocotb.start_soon(Clock(gt_inst.tx_clk, clk, units="ns").start()) + cocotb.start_soon(Clock(gt_inst.rx_clk, clk, units="ns").start()) + + self.sfp_sources.append(BaseRSerdesSource( + data=gt_inst.serdes_rx_data, + data_valid=gt_inst.serdes_rx_data_valid, + hdr=gt_inst.serdes_rx_hdr, + hdr_valid=gt_inst.serdes_rx_hdr_valid, + clock=gt_inst.rx_clk, + slip=gt_inst.serdes_rx_bitslip, + reverse=True, + gbx_cfg=gbx_cfg + )) + self.sfp_sinks.append(BaseRSerdesSink( + data=gt_inst.serdes_tx_data, + data_valid=gt_inst.serdes_tx_data_valid, + hdr=gt_inst.serdes_tx_hdr, + hdr_valid=gt_inst.serdes_tx_hdr_valid, + gbx_start=gt_inst.serdes_tx_gbx_start, + clock=gt_inst.tx_clk, + reverse=True, + gbx_cfg=gbx_cfg + )) self.uart_source = UartSource(dut.uart_rxd, baud=3000000, bits=8, stop_bits=1) self.uart_sink = UartSink(dut.uart_txd, baud=3000000, bits=8, stop_bits=1) diff --git a/src/eth/example/fb2CG/fpga/rtl/fpga_core.sv b/src/eth/example/fb2CG/fpga/rtl/fpga_core.sv index 31b85a6..609285a 100644 --- a/src/eth/example/fb2CG/fpga/rtl/fpga_core.sv +++ b/src/eth/example/fb2CG/fpga/rtl/fpga_core.sv @@ -185,6 +185,9 @@ for (genvar n = 0; n < 2; n = n + 1) begin : gty_quad .CNT(CNT), + // GT config + .CFG_LOW_LATENCY(1), + // GT type .GT_TYPE("GTY"), diff --git a/src/eth/example/fb2CG/fpga/tb/fpga_core/test_fpga_core.py b/src/eth/example/fb2CG/fpga/tb/fpga_core/test_fpga_core.py index d92ee69..c01c49d 100644 --- a/src/eth/example/fb2CG/fpga/tb/fpga_core/test_fpga_core.py +++ b/src/eth/example/fb2CG/fpga/tb/fpga_core/test_fpga_core.py @@ -49,11 +49,38 @@ class TB: for inst in dut.gty_quad: for ch in inst.mac_inst.ch: - cocotb.start_soon(Clock(ch.ch_inst.gt_inst.tx_clk, 2.56, units="ns").start()) - cocotb.start_soon(Clock(ch.ch_inst.gt_inst.rx_clk, 2.56, units="ns").start()) + gt_inst = ch.ch_inst.gt.gt_inst - self.qsfp_sources.append(BaseRSerdesSource(ch.ch_inst.serdes_rx_data, ch.ch_inst.serdes_rx_hdr, ch.ch_inst.gt_inst.rx_clk, slip=ch.ch_inst.serdes_rx_bitslip, reverse=True)) - self.qsfp_sinks.append(BaseRSerdesSink(ch.ch_inst.serdes_tx_data, ch.ch_inst.serdes_tx_hdr, ch.ch_inst.gt_inst.tx_clk, reverse=True)) + if ch.ch_inst.CFG_LOW_LATENCY.value: + clk = 2.482 + gbx_cfg = (66, [64, 65]) + else: + clk = 2.56 + gbx_cfg = None + + cocotb.start_soon(Clock(gt_inst.tx_clk, clk, units="ns").start()) + cocotb.start_soon(Clock(gt_inst.rx_clk, clk, units="ns").start()) + + self.qsfp_sources.append(BaseRSerdesSource( + data=gt_inst.serdes_rx_data, + data_valid=gt_inst.serdes_rx_data_valid, + hdr=gt_inst.serdes_rx_hdr, + hdr_valid=gt_inst.serdes_rx_hdr_valid, + clock=gt_inst.rx_clk, + slip=gt_inst.serdes_rx_bitslip, + reverse=True, + gbx_cfg=gbx_cfg + )) + self.qsfp_sinks.append(BaseRSerdesSink( + data=gt_inst.serdes_tx_data, + data_valid=gt_inst.serdes_tx_data_valid, + hdr=gt_inst.serdes_tx_hdr, + hdr_valid=gt_inst.serdes_tx_hdr_valid, + gbx_start=gt_inst.serdes_tx_gbx_start, + clock=gt_inst.tx_clk, + reverse=True, + gbx_cfg=gbx_cfg + )) dut.qsfp_0_mod_prsnt_n.setimmediatevalue(0) dut.qsfp_0_intr_n.setimmediatevalue(0) diff --git a/src/eth/rtl/taxi_axis_baser_rx_64.sv b/src/eth/rtl/taxi_axis_baser_rx_64.sv index d178e2f..22aadab 100644 --- a/src/eth/rtl/taxi_axis_baser_rx_64.sv +++ b/src/eth/rtl/taxi_axis_baser_rx_64.sv @@ -19,6 +19,7 @@ module taxi_axis_baser_rx_64 # ( parameter DATA_W = 64, parameter HDR_W = 2, + parameter logic GBX_IF_EN = 1'b0, parameter logic PTP_TS_EN = 1'b0, parameter logic PTP_TS_FMT_TOD = 1'b1, parameter PTP_TS_W = PTP_TS_FMT_TOD ? 96 : 64 @@ -31,7 +32,9 @@ module taxi_axis_baser_rx_64 # * 10GBASE-R encoded input */ input wire logic [DATA_W-1:0] encoded_rx_data, + input wire logic encoded_rx_data_valid, input wire logic [HDR_W-1:0] encoded_rx_hdr, + input wire logic encoded_rx_hdr_valid, /* * Receive interface (AXI stream) @@ -344,122 +347,145 @@ always_comb begin stat_rx_err_bad_fcs_next = 1'b0; stat_rx_err_preamble_next = 1'b0; - // counter to measure frame length - if (&frame_len_reg[15:3] == 0) begin - if (input_type_d0[3]) begin - frame_len_next = frame_len_reg + 16'(input_type_d0[2:0]); + if (GBX_IF_EN && !encoded_rx_data_valid) begin + // data from gearbox not valid - hold state + state_next = state_reg; + end else begin + // counter to measure frame length + if (&frame_len_reg[15:3] == 0) begin + if (input_type_d0[3]) begin + frame_len_next = frame_len_reg + 16'(input_type_d0[2:0]); + end else begin + frame_len_next = frame_len_reg + 16'(KEEP_W); + end end else begin - frame_len_next = frame_len_reg + 16'(KEEP_W); + frame_len_next = '1; end - end else begin - frame_len_next = '1; - end - // counter for max frame length enforcement - if (frame_len_lim_reg[15:3] != 0) begin - frame_len_lim_next = frame_len_lim_reg - 16'(KEEP_W); - end else begin - frame_len_lim_next = '0; - end - - // address and ethertype checks - if (&hdr_ptr_reg == 0) begin - hdr_ptr_next = hdr_ptr_reg + 1; - end - - case (hdr_ptr_reg) - 2'd0: begin - is_mcast_next = input_data_d1[0]; - is_bcast_next = &input_data_d1[47:0]; + // counter for max frame length enforcement + if (frame_len_lim_reg[15:3] != 0) begin + frame_len_lim_next = frame_len_lim_reg - 16'(KEEP_W); + end else begin + frame_len_lim_next = '0; end - 2'd1: is_8021q_next = {input_data_d1[39:32], input_data_d1[47:40]} == 16'h8100; - default: begin - // do nothing + + // address and ethertype checks + if (&hdr_ptr_reg == 0) begin + hdr_ptr_next = hdr_ptr_reg + 1; end - endcase - case (state_reg) - STATE_IDLE: begin - // idle state - wait for packet - reset_crc = 1'b1; - - frame_len_next = 16'(KEEP_W); - frame_len_lim_next = cfg_rx_max_pkt_len; - hdr_ptr_next = 0; - - pre_ok_next = input_data_d1[63:8] == 56'hD5555555555555; - - if (input_start_d1 && cfg_rx_enable) begin - // start condition - reset_crc = 1'b0; - stat_rx_byte_next = 4'(KEEP_W); - state_next = STATE_PAYLOAD; - end else begin - state_next = STATE_IDLE; + case (hdr_ptr_reg) + 2'd0: begin + is_mcast_next = input_data_d1[0]; + is_bcast_next = &input_data_d1[47:0]; end - end - STATE_PAYLOAD: begin - // read payload - m_axis_rx_tdata_next = input_data_d1; - m_axis_rx_tkeep_next = 8'hff; - m_axis_rx_tvalid_next = 1'b1; - m_axis_rx_tlast_next = 1'b0; - m_axis_rx_tuser_next = 1'b0; - - if (input_type_d0[3]) begin - stat_rx_byte_next = 4'(input_type_d0[2:0]); - frame_oversize_next = frame_len_lim_reg < 16'(8+input_type_d0[2:0]); - end else begin - stat_rx_byte_next = 4'(KEEP_W); - frame_oversize_next = frame_len_lim_reg < 8; + 2'd1: is_8021q_next = {input_data_d1[39:32], input_data_d1[47:40]} == 16'h8100; + default: begin + // do nothing end + endcase - if (input_type_d0[3]) begin - // INPUT_TYPE_TERM_* + case (state_reg) + STATE_IDLE: begin + // idle state - wait for packet reset_crc = 1'b1; - end - if (PTP_TS_EN) begin - ptp_ts_out_next = (!PTP_TS_FMT_TOD || ptp_ts_borrow_reg) ? ptp_ts_reg : ptp_ts_adj_reg; - end + frame_len_next = 16'(KEEP_W); + frame_len_lim_next = cfg_rx_max_pkt_len; + hdr_ptr_next = 0; - if (input_type_d0 == INPUT_TYPE_DATA) begin - state_next = STATE_PAYLOAD; - end else if (input_type_d0[3]) begin - // INPUT_TYPE_TERM_* - if (input_type_d0 <= INPUT_TYPE_TERM_4) begin - // end this cycle - case (input_type_d0) - INPUT_TYPE_TERM_0: m_axis_rx_tkeep_next = 8'b00001111; - INPUT_TYPE_TERM_1: m_axis_rx_tkeep_next = 8'b00011111; - INPUT_TYPE_TERM_2: m_axis_rx_tkeep_next = 8'b00111111; - INPUT_TYPE_TERM_3: m_axis_rx_tkeep_next = 8'b01111111; - INPUT_TYPE_TERM_4: m_axis_rx_tkeep_next = 8'b11111111; - default: m_axis_rx_tkeep_next = 8'b11111111; - endcase - m_axis_rx_tlast_next = 1'b1; - if ((input_type_d0 == INPUT_TYPE_TERM_0 && crc_valid_save[7]) || - (input_type_d0 == INPUT_TYPE_TERM_1 && crc_valid[0]) || - (input_type_d0 == INPUT_TYPE_TERM_2 && crc_valid[1]) || - (input_type_d0 == INPUT_TYPE_TERM_3 && crc_valid[2]) || - (input_type_d0 == INPUT_TYPE_TERM_4 && crc_valid[3])) begin - // CRC valid - if (frame_oversize_next) begin - // too long - m_axis_rx_tuser_next = 1'b1; - stat_rx_pkt_bad_next = 1'b1; + pre_ok_next = input_data_d1[63:8] == 56'hD5555555555555; + + if (input_start_d1 && cfg_rx_enable) begin + // start condition + reset_crc = 1'b0; + stat_rx_byte_next = 4'(KEEP_W); + state_next = STATE_PAYLOAD; + end else begin + state_next = STATE_IDLE; + end + end + STATE_PAYLOAD: begin + // read payload + m_axis_rx_tdata_next = input_data_d1; + m_axis_rx_tkeep_next = 8'hff; + m_axis_rx_tvalid_next = 1'b1; + m_axis_rx_tlast_next = 1'b0; + m_axis_rx_tuser_next = 1'b0; + + if (input_type_d0[3]) begin + stat_rx_byte_next = 4'(input_type_d0[2:0]); + frame_oversize_next = frame_len_lim_reg < 16'(8+input_type_d0[2:0]); + end else begin + stat_rx_byte_next = 4'(KEEP_W); + frame_oversize_next = frame_len_lim_reg < 8; + end + + if (input_type_d0[3]) begin + // INPUT_TYPE_TERM_* + reset_crc = 1'b1; + end + + if (PTP_TS_EN) begin + ptp_ts_out_next = (!PTP_TS_FMT_TOD || ptp_ts_borrow_reg) ? ptp_ts_reg : ptp_ts_adj_reg; + end + + if (input_type_d0 == INPUT_TYPE_DATA) begin + state_next = STATE_PAYLOAD; + end else if (input_type_d0[3]) begin + // INPUT_TYPE_TERM_* + if (input_type_d0 <= INPUT_TYPE_TERM_4) begin + // end this cycle + case (input_type_d0) + INPUT_TYPE_TERM_0: m_axis_rx_tkeep_next = 8'b00001111; + INPUT_TYPE_TERM_1: m_axis_rx_tkeep_next = 8'b00011111; + INPUT_TYPE_TERM_2: m_axis_rx_tkeep_next = 8'b00111111; + INPUT_TYPE_TERM_3: m_axis_rx_tkeep_next = 8'b01111111; + INPUT_TYPE_TERM_4: m_axis_rx_tkeep_next = 8'b11111111; + default: m_axis_rx_tkeep_next = 8'b11111111; + endcase + m_axis_rx_tlast_next = 1'b1; + if ((input_type_d0 == INPUT_TYPE_TERM_0 && crc_valid_save[7]) || + (input_type_d0 == INPUT_TYPE_TERM_1 && crc_valid[0]) || + (input_type_d0 == INPUT_TYPE_TERM_2 && crc_valid[1]) || + (input_type_d0 == INPUT_TYPE_TERM_3 && crc_valid[2]) || + (input_type_d0 == INPUT_TYPE_TERM_4 && crc_valid[3])) begin + // CRC valid + if (frame_oversize_next) begin + // too long + m_axis_rx_tuser_next = 1'b1; + stat_rx_pkt_bad_next = 1'b1; + end else begin + // length OK + m_axis_rx_tuser_next = 1'b0; + stat_rx_pkt_good_next = 1'b1; + end end else begin - // length OK - m_axis_rx_tuser_next = 1'b0; - stat_rx_pkt_good_next = 1'b1; + m_axis_rx_tuser_next = 1'b1; + stat_rx_pkt_fragment_next = frame_len_next[15:6] == 0; + stat_rx_pkt_jabber_next = frame_oversize_next; + stat_rx_pkt_bad_next = 1'b1; + stat_rx_err_bad_fcs_next = 1'b1; end + + stat_rx_pkt_len_next = frame_len_next; + stat_rx_pkt_ucast_next = !is_mcast_reg; + stat_rx_pkt_mcast_next = is_mcast_reg && !is_bcast_reg; + stat_rx_pkt_bcast_next = is_bcast_reg; + stat_rx_pkt_vlan_next = is_8021q_reg; + stat_rx_err_oversize_next = frame_oversize_next; + stat_rx_err_preamble_next = !pre_ok_reg; + + state_next = STATE_IDLE; end else begin - m_axis_rx_tuser_next = 1'b1; - stat_rx_pkt_fragment_next = frame_len_next[15:6] == 0; - stat_rx_pkt_jabber_next = frame_oversize_next; - stat_rx_pkt_bad_next = 1'b1; - stat_rx_err_bad_fcs_next = 1'b1; + // need extra cycle + state_next = STATE_LAST; end + end else begin + // control or error characters in packet + m_axis_rx_tlast_next = 1'b1; + m_axis_rx_tuser_next = 1'b1; + stat_rx_pkt_bad_next = 1'b1; stat_rx_pkt_len_next = frame_len_next; stat_rx_pkt_ucast_next = !is_mcast_reg; @@ -468,85 +494,67 @@ always_comb begin stat_rx_pkt_vlan_next = is_8021q_reg; stat_rx_err_oversize_next = frame_oversize_next; stat_rx_err_preamble_next = !pre_ok_reg; + stat_rx_pkt_fragment_next = frame_len_next[15:6] == 0; + stat_rx_pkt_jabber_next = frame_oversize_next; + reset_crc = 1'b1; state_next = STATE_IDLE; - end else begin - // need extra cycle - state_next = STATE_LAST; end - end else begin - // control or error characters in packet + end + STATE_LAST: begin + // last cycle of packet + m_axis_rx_tdata_next = input_data_d1; + m_axis_rx_tkeep_next = 8'hff; + m_axis_rx_tvalid_next = 1'b1; m_axis_rx_tlast_next = 1'b1; - m_axis_rx_tuser_next = 1'b1; - stat_rx_pkt_bad_next = 1'b1; + m_axis_rx_tuser_next = 1'b0; - stat_rx_pkt_len_next = frame_len_next; + reset_crc = 1'b1; + + case (input_type_d1) + INPUT_TYPE_TERM_5: m_axis_rx_tkeep_next = 8'b00000001; + INPUT_TYPE_TERM_6: m_axis_rx_tkeep_next = 8'b00000011; + INPUT_TYPE_TERM_7: m_axis_rx_tkeep_next = 8'b00000111; + default: m_axis_rx_tkeep_next = 8'b00000111; + endcase + + if ((input_type_d1 == INPUT_TYPE_TERM_5 && crc_valid_save[4]) || + (input_type_d1 == INPUT_TYPE_TERM_6 && crc_valid_save[5]) || + (input_type_d1 == INPUT_TYPE_TERM_7 && crc_valid_save[6])) begin + // CRC valid + if (frame_oversize_reg) begin + // too long + m_axis_rx_tuser_next = 1'b1; + stat_rx_pkt_bad_next = 1'b1; + end else begin + // length OK + m_axis_rx_tuser_next = 1'b0; + stat_rx_pkt_good_next = 1'b1; + end + end else begin + m_axis_rx_tuser_next = 1'b1; + stat_rx_pkt_fragment_next = frame_len_reg[15:6] == 0; + stat_rx_pkt_jabber_next = frame_oversize_reg; + stat_rx_pkt_bad_next = 1'b1; + stat_rx_err_bad_fcs_next = 1'b1; + end + + stat_rx_pkt_len_next = frame_len_reg; stat_rx_pkt_ucast_next = !is_mcast_reg; stat_rx_pkt_mcast_next = is_mcast_reg && !is_bcast_reg; stat_rx_pkt_bcast_next = is_bcast_reg; stat_rx_pkt_vlan_next = is_8021q_reg; - stat_rx_err_oversize_next = frame_oversize_next; + stat_rx_err_oversize_next = frame_oversize_reg; stat_rx_err_preamble_next = !pre_ok_reg; - stat_rx_pkt_fragment_next = frame_len_next[15:6] == 0; - stat_rx_pkt_jabber_next = frame_oversize_next; - reset_crc = 1'b1; state_next = STATE_IDLE; end - end - STATE_LAST: begin - // last cycle of packet - m_axis_rx_tdata_next = input_data_d1; - m_axis_rx_tkeep_next = 8'hff; - m_axis_rx_tvalid_next = 1'b1; - m_axis_rx_tlast_next = 1'b1; - m_axis_rx_tuser_next = 1'b0; - - reset_crc = 1'b1; - - case (input_type_d1) - INPUT_TYPE_TERM_5: m_axis_rx_tkeep_next = 8'b00000001; - INPUT_TYPE_TERM_6: m_axis_rx_tkeep_next = 8'b00000011; - INPUT_TYPE_TERM_7: m_axis_rx_tkeep_next = 8'b00000111; - default: m_axis_rx_tkeep_next = 8'b00000111; - endcase - - if ((input_type_d1 == INPUT_TYPE_TERM_5 && crc_valid_save[4]) || - (input_type_d1 == INPUT_TYPE_TERM_6 && crc_valid_save[5]) || - (input_type_d1 == INPUT_TYPE_TERM_7 && crc_valid_save[6])) begin - // CRC valid - if (frame_oversize_reg) begin - // too long - m_axis_rx_tuser_next = 1'b1; - stat_rx_pkt_bad_next = 1'b1; - end else begin - // length OK - m_axis_rx_tuser_next = 1'b0; - stat_rx_pkt_good_next = 1'b1; - end - end else begin - m_axis_rx_tuser_next = 1'b1; - stat_rx_pkt_fragment_next = frame_len_reg[15:6] == 0; - stat_rx_pkt_jabber_next = frame_oversize_reg; - stat_rx_pkt_bad_next = 1'b1; - stat_rx_err_bad_fcs_next = 1'b1; + default: begin + // invalid state, return to idle + state_next = STATE_IDLE; end - - stat_rx_pkt_len_next = frame_len_reg; - stat_rx_pkt_ucast_next = !is_mcast_reg; - stat_rx_pkt_mcast_next = is_mcast_reg && !is_bcast_reg; - stat_rx_pkt_bcast_next = is_bcast_reg; - stat_rx_pkt_vlan_next = is_8021q_reg; - stat_rx_err_oversize_next = frame_oversize_reg; - stat_rx_err_preamble_next = !pre_ok_reg; - - state_next = STATE_IDLE; - end - default: begin - // invalid state, return to idle - state_next = STATE_IDLE; - end - endcase + endcase + end end always_ff @(posedge clk) begin @@ -587,245 +595,247 @@ always_ff @(posedge clk) begin stat_rx_err_framing_reg <= 1'b0; stat_rx_err_preamble_reg <= stat_rx_err_preamble_next; - delay_type_valid <= 1'b0; + if (!GBX_IF_EN || encoded_rx_data_valid) begin + delay_type_valid <= 1'b0; - swap_data <= encoded_rx_data_masked[63:32]; + swap_data <= encoded_rx_data_masked[63:32]; - input_start_swap <= 1'b0; - input_start_d0 <= input_start_swap; + input_start_swap <= 1'b0; + input_start_d0 <= input_start_swap; - if (PTP_TS_EN && PTP_TS_FMT_TOD) begin - // ns field rollover - ptp_ts_adj_reg[15:0] <= ptp_ts_reg[15:0]; - {ptp_ts_borrow_reg, ptp_ts_adj_reg[45:16]} <= $signed({1'b0, ptp_ts_reg[45:16]}) - $signed(31'd1000000000); - ptp_ts_adj_reg[47:46] <= 0; - ptp_ts_adj_reg[95:48] <= ptp_ts_reg[95:48] + 1; - end + if (PTP_TS_EN && PTP_TS_FMT_TOD) begin + // ns field rollover + ptp_ts_adj_reg[15:0] <= ptp_ts_reg[15:0]; + {ptp_ts_borrow_reg, ptp_ts_adj_reg[45:16]} <= $signed({1'b0, ptp_ts_reg[45:16]}) - $signed(31'd1000000000); + ptp_ts_adj_reg[47:46] <= 0; + ptp_ts_adj_reg[95:48] <= ptp_ts_reg[95:48] + 1; + end - // lane swapping and termination character detection - if (lanes_swapped) begin - if (delay_type_valid) begin - input_type_d0 <= delay_type; - end else if (encoded_rx_hdr[0] == SYNC_DATA[0]) begin - input_type_d0 <= INPUT_TYPE_DATA; + // lane swapping and termination character detection + if (lanes_swapped) begin + if (delay_type_valid) begin + input_type_d0 <= delay_type; + end else if (encoded_rx_hdr[0] == SYNC_DATA[0]) begin + input_type_d0 <= INPUT_TYPE_DATA; + end else begin + case (encoded_rx_data[7:4]) + BLOCK_TYPE_TERM_0[7:4]: input_type_d0 <= INPUT_TYPE_TERM_4; + BLOCK_TYPE_TERM_1[7:4]: input_type_d0 <= INPUT_TYPE_TERM_5; + BLOCK_TYPE_TERM_2[7:4]: input_type_d0 <= INPUT_TYPE_TERM_6; + BLOCK_TYPE_TERM_3[7:4]: input_type_d0 <= INPUT_TYPE_TERM_7; + BLOCK_TYPE_TERM_4[7:4]: begin + delay_type_valid <= 1'b1; + input_type_d0 <= INPUT_TYPE_DATA; + end + BLOCK_TYPE_TERM_5[7:4]: begin + delay_type_valid <= 1'b1; + input_type_d0 <= INPUT_TYPE_DATA; + end + BLOCK_TYPE_TERM_6[7:4]: begin + delay_type_valid <= 1'b1; + input_type_d0 <= INPUT_TYPE_DATA; + end + BLOCK_TYPE_TERM_7[7:4]: begin + delay_type_valid <= 1'b1; + input_type_d0 <= INPUT_TYPE_DATA; + end + BLOCK_TYPE_CTRL[7:4]: input_type_d0 <= INPUT_TYPE_IDLE; + BLOCK_TYPE_OS_4[7:4]: input_type_d0 <= INPUT_TYPE_IDLE; + BLOCK_TYPE_OS_04[7:4]: input_type_d0 <= INPUT_TYPE_IDLE; + BLOCK_TYPE_OS_0[7:4]: input_type_d0 <= INPUT_TYPE_IDLE; + default: begin + input_type_d0 <= INPUT_TYPE_ERROR; + end + endcase + end + if (delay_type_valid) begin + // mask off trailing data + input_data_d0 <= {32'd0, swap_data}; + end else begin + input_data_d0 <= {encoded_rx_data_masked[31:0], swap_data}; + end end else begin + if (encoded_rx_hdr[0] == SYNC_DATA[0]) begin + input_type_d0 <= INPUT_TYPE_DATA; + end else begin + case (encoded_rx_data[7:4]) + BLOCK_TYPE_CTRL[7:4]: input_type_d0 <= INPUT_TYPE_IDLE; + BLOCK_TYPE_OS_4[7:4]: input_type_d0 <= INPUT_TYPE_IDLE; + BLOCK_TYPE_OS_04[7:4]: input_type_d0 <= INPUT_TYPE_IDLE; + BLOCK_TYPE_OS_0[7:4]: input_type_d0 <= INPUT_TYPE_IDLE; + BLOCK_TYPE_TERM_0[7:4]: input_type_d0 <= INPUT_TYPE_TERM_0; + BLOCK_TYPE_TERM_1[7:4]: input_type_d0 <= INPUT_TYPE_TERM_1; + BLOCK_TYPE_TERM_2[7:4]: input_type_d0 <= INPUT_TYPE_TERM_2; + BLOCK_TYPE_TERM_3[7:4]: input_type_d0 <= INPUT_TYPE_TERM_3; + BLOCK_TYPE_TERM_4[7:4]: input_type_d0 <= INPUT_TYPE_TERM_4; + BLOCK_TYPE_TERM_5[7:4]: input_type_d0 <= INPUT_TYPE_TERM_5; + BLOCK_TYPE_TERM_6[7:4]: input_type_d0 <= INPUT_TYPE_TERM_6; + BLOCK_TYPE_TERM_7[7:4]: input_type_d0 <= INPUT_TYPE_TERM_7; + default: begin + input_type_d0 <= INPUT_TYPE_ERROR; + end + endcase + end + input_data_d0 <= encoded_rx_data_masked; + end + + // start control character detection + if (encoded_rx_hdr == SYNC_CTRL && encoded_rx_data[7:0] == BLOCK_TYPE_START_0) begin + lanes_swapped <= 1'b0; + input_start_d0 <= 1'b1; + input_data_d0 <= encoded_rx_data_masked; + end else if (encoded_rx_hdr == SYNC_CTRL && (encoded_rx_data[7:0] == BLOCK_TYPE_START_4 || encoded_rx_data[7:0] == BLOCK_TYPE_OS_START)) begin + lanes_swapped <= 1'b1; + input_start_swap <= 1'b1; + end + + if (encoded_rx_hdr == SYNC_DATA) begin + delay_type <= INPUT_TYPE_DATA; + end else if (encoded_rx_hdr == SYNC_CTRL) begin case (encoded_rx_data[7:4]) - BLOCK_TYPE_TERM_0[7:4]: input_type_d0 <= INPUT_TYPE_TERM_4; - BLOCK_TYPE_TERM_1[7:4]: input_type_d0 <= INPUT_TYPE_TERM_5; - BLOCK_TYPE_TERM_2[7:4]: input_type_d0 <= INPUT_TYPE_TERM_6; - BLOCK_TYPE_TERM_3[7:4]: input_type_d0 <= INPUT_TYPE_TERM_7; + BLOCK_TYPE_START_4[7:4]: delay_type <= INPUT_TYPE_START_0; + BLOCK_TYPE_OS_START[7:4]: delay_type <= INPUT_TYPE_START_0; + BLOCK_TYPE_TERM_0[7:4]: delay_type <= INPUT_TYPE_TERM_4; + BLOCK_TYPE_TERM_1[7:4]: delay_type <= INPUT_TYPE_TERM_5; + BLOCK_TYPE_TERM_2[7:4]: delay_type <= INPUT_TYPE_TERM_6; + BLOCK_TYPE_TERM_3[7:4]: delay_type <= INPUT_TYPE_TERM_7; + BLOCK_TYPE_TERM_4[7:4]: delay_type <= INPUT_TYPE_TERM_0; + BLOCK_TYPE_TERM_5[7:4]: delay_type <= INPUT_TYPE_TERM_1; + BLOCK_TYPE_TERM_6[7:4]: delay_type <= INPUT_TYPE_TERM_2; + BLOCK_TYPE_TERM_7[7:4]: delay_type <= INPUT_TYPE_TERM_3; + default: delay_type <= INPUT_TYPE_ERROR; + endcase + end else begin + delay_type <= INPUT_TYPE_ERROR; + end + + // check for framing errors + stat_rx_err_framing_reg <= 1'b0; + if (encoded_rx_hdr == SYNC_DATA) begin + // data - must be in a frame + stat_rx_err_framing_reg <= !frame_reg; + end else if (encoded_rx_hdr == SYNC_CTRL) begin + // control - control only allowed between frames + frame_reg <= 1'b0; + case (encoded_rx_data[7:4]) + BLOCK_TYPE_CTRL[7:4]: begin + stat_rx_err_framing_reg <= frame_reg; + end + BLOCK_TYPE_OS_4[7:4]: begin + stat_rx_err_framing_reg <= frame_reg; + end + BLOCK_TYPE_START_4[7:4]: begin + frame_reg <= 1'b1; + stat_rx_err_framing_reg <= frame_reg; + end + BLOCK_TYPE_OS_START[7:4]: begin + frame_reg <= 1'b1; + stat_rx_err_framing_reg <= frame_reg; + end + BLOCK_TYPE_OS_04[7:4]: begin + stat_rx_err_framing_reg <= frame_reg; + end + BLOCK_TYPE_START_0[7:4]: begin + frame_reg <= 1'b1; + stat_rx_err_framing_reg <= frame_reg; + end + BLOCK_TYPE_OS_0[7:4]: begin + stat_rx_err_framing_reg <= frame_reg; + end + BLOCK_TYPE_TERM_0[7:4]: begin + stat_rx_err_framing_reg <= !frame_reg; + end + BLOCK_TYPE_TERM_1[7:4]: begin + stat_rx_err_framing_reg <= !frame_reg; + end + BLOCK_TYPE_TERM_2[7:4]: begin + stat_rx_err_framing_reg <= !frame_reg; + end + BLOCK_TYPE_TERM_3[7:4]: begin + stat_rx_err_framing_reg <= !frame_reg; + end BLOCK_TYPE_TERM_4[7:4]: begin - delay_type_valid <= 1'b1; - input_type_d0 <= INPUT_TYPE_DATA; + stat_rx_err_framing_reg <= !frame_reg; end BLOCK_TYPE_TERM_5[7:4]: begin - delay_type_valid <= 1'b1; - input_type_d0 <= INPUT_TYPE_DATA; + stat_rx_err_framing_reg <= !frame_reg; end BLOCK_TYPE_TERM_6[7:4]: begin - delay_type_valid <= 1'b1; - input_type_d0 <= INPUT_TYPE_DATA; + stat_rx_err_framing_reg <= !frame_reg; end BLOCK_TYPE_TERM_7[7:4]: begin - delay_type_valid <= 1'b1; - input_type_d0 <= INPUT_TYPE_DATA; + stat_rx_err_framing_reg <= !frame_reg; end - BLOCK_TYPE_CTRL[7:4]: input_type_d0 <= INPUT_TYPE_IDLE; - BLOCK_TYPE_OS_4[7:4]: input_type_d0 <= INPUT_TYPE_IDLE; - BLOCK_TYPE_OS_04[7:4]: input_type_d0 <= INPUT_TYPE_IDLE; - BLOCK_TYPE_OS_0[7:4]: input_type_d0 <= INPUT_TYPE_IDLE; default: begin - input_type_d0 <= INPUT_TYPE_ERROR; + // invalid block type + frame_reg <= 1'b0; end endcase - end - if (delay_type_valid) begin - // mask off trailing data - input_data_d0 <= {32'd0, swap_data}; end else begin - input_data_d0 <= {encoded_rx_data_masked[31:0], swap_data}; + // invalid header + frame_reg <= 1'b0; end - end else begin - if (encoded_rx_hdr[0] == SYNC_DATA[0]) begin - input_type_d0 <= INPUT_TYPE_DATA; - end else begin - case (encoded_rx_data[7:4]) - BLOCK_TYPE_CTRL[7:4]: input_type_d0 <= INPUT_TYPE_IDLE; - BLOCK_TYPE_OS_4[7:4]: input_type_d0 <= INPUT_TYPE_IDLE; - BLOCK_TYPE_OS_04[7:4]: input_type_d0 <= INPUT_TYPE_IDLE; - BLOCK_TYPE_OS_0[7:4]: input_type_d0 <= INPUT_TYPE_IDLE; - BLOCK_TYPE_TERM_0[7:4]: input_type_d0 <= INPUT_TYPE_TERM_0; - BLOCK_TYPE_TERM_1[7:4]: input_type_d0 <= INPUT_TYPE_TERM_1; - BLOCK_TYPE_TERM_2[7:4]: input_type_d0 <= INPUT_TYPE_TERM_2; - BLOCK_TYPE_TERM_3[7:4]: input_type_d0 <= INPUT_TYPE_TERM_3; - BLOCK_TYPE_TERM_4[7:4]: input_type_d0 <= INPUT_TYPE_TERM_4; - BLOCK_TYPE_TERM_5[7:4]: input_type_d0 <= INPUT_TYPE_TERM_5; - BLOCK_TYPE_TERM_6[7:4]: input_type_d0 <= INPUT_TYPE_TERM_6; - BLOCK_TYPE_TERM_7[7:4]: input_type_d0 <= INPUT_TYPE_TERM_7; + + // check all block type bits to detect bad encodings + if (encoded_rx_hdr == SYNC_DATA) begin + // data - nothing encoded + end else if (encoded_rx_hdr == SYNC_CTRL) begin + // control - check for bad block types + case (encoded_rx_data[7:0]) + BLOCK_TYPE_CTRL: begin end + BLOCK_TYPE_OS_4: begin end + BLOCK_TYPE_START_4: begin end + BLOCK_TYPE_OS_START: begin end + BLOCK_TYPE_OS_04: begin end + BLOCK_TYPE_START_0: begin end + BLOCK_TYPE_OS_0: begin end + BLOCK_TYPE_TERM_0: begin end + BLOCK_TYPE_TERM_1: begin end + BLOCK_TYPE_TERM_2: begin end + BLOCK_TYPE_TERM_3: begin end + BLOCK_TYPE_TERM_4: begin end + BLOCK_TYPE_TERM_5: begin end + BLOCK_TYPE_TERM_6: begin end + BLOCK_TYPE_TERM_7: begin end default: begin - input_type_d0 <= INPUT_TYPE_ERROR; + // invalid block type + stat_rx_err_bad_block_reg <= 1'b1; end endcase - end - input_data_d0 <= encoded_rx_data_masked; - end - - // start control character detection - if (encoded_rx_hdr == SYNC_CTRL && encoded_rx_data[7:0] == BLOCK_TYPE_START_0) begin - lanes_swapped <= 1'b0; - input_start_d0 <= 1'b1; - input_data_d0 <= encoded_rx_data_masked; - end else if (encoded_rx_hdr == SYNC_CTRL && (encoded_rx_data[7:0] == BLOCK_TYPE_START_4 || encoded_rx_data[7:0] == BLOCK_TYPE_OS_START)) begin - lanes_swapped <= 1'b1; - input_start_swap <= 1'b1; - end - - if (encoded_rx_hdr == SYNC_DATA) begin - delay_type <= INPUT_TYPE_DATA; - end else if (encoded_rx_hdr == SYNC_CTRL) begin - case (encoded_rx_data[7:4]) - BLOCK_TYPE_START_4[7:4]: delay_type <= INPUT_TYPE_START_0; - BLOCK_TYPE_OS_START[7:4]: delay_type <= INPUT_TYPE_START_0; - BLOCK_TYPE_TERM_0[7:4]: delay_type <= INPUT_TYPE_TERM_4; - BLOCK_TYPE_TERM_1[7:4]: delay_type <= INPUT_TYPE_TERM_5; - BLOCK_TYPE_TERM_2[7:4]: delay_type <= INPUT_TYPE_TERM_6; - BLOCK_TYPE_TERM_3[7:4]: delay_type <= INPUT_TYPE_TERM_7; - BLOCK_TYPE_TERM_4[7:4]: delay_type <= INPUT_TYPE_TERM_0; - BLOCK_TYPE_TERM_5[7:4]: delay_type <= INPUT_TYPE_TERM_1; - BLOCK_TYPE_TERM_6[7:4]: delay_type <= INPUT_TYPE_TERM_2; - BLOCK_TYPE_TERM_7[7:4]: delay_type <= INPUT_TYPE_TERM_3; - default: delay_type <= INPUT_TYPE_ERROR; - endcase - end else begin - delay_type <= INPUT_TYPE_ERROR; - end - - // check for framing errors - stat_rx_err_framing_reg <= 1'b0; - if (encoded_rx_hdr == SYNC_DATA) begin - // data - must be in a frame - stat_rx_err_framing_reg <= !frame_reg; - end else if (encoded_rx_hdr == SYNC_CTRL) begin - // control - control only allowed between frames - frame_reg <= 1'b0; - case (encoded_rx_data[7:4]) - BLOCK_TYPE_CTRL[7:4]: begin - stat_rx_err_framing_reg <= frame_reg; - end - BLOCK_TYPE_OS_4[7:4]: begin - stat_rx_err_framing_reg <= frame_reg; - end - BLOCK_TYPE_START_4[7:4]: begin - frame_reg <= 1'b1; - stat_rx_err_framing_reg <= frame_reg; - end - BLOCK_TYPE_OS_START[7:4]: begin - frame_reg <= 1'b1; - stat_rx_err_framing_reg <= frame_reg; - end - BLOCK_TYPE_OS_04[7:4]: begin - stat_rx_err_framing_reg <= frame_reg; - end - BLOCK_TYPE_START_0[7:4]: begin - frame_reg <= 1'b1; - stat_rx_err_framing_reg <= frame_reg; - end - BLOCK_TYPE_OS_0[7:4]: begin - stat_rx_err_framing_reg <= frame_reg; - end - BLOCK_TYPE_TERM_0[7:4]: begin - stat_rx_err_framing_reg <= !frame_reg; - end - BLOCK_TYPE_TERM_1[7:4]: begin - stat_rx_err_framing_reg <= !frame_reg; - end - BLOCK_TYPE_TERM_2[7:4]: begin - stat_rx_err_framing_reg <= !frame_reg; - end - BLOCK_TYPE_TERM_3[7:4]: begin - stat_rx_err_framing_reg <= !frame_reg; - end - BLOCK_TYPE_TERM_4[7:4]: begin - stat_rx_err_framing_reg <= !frame_reg; - end - BLOCK_TYPE_TERM_5[7:4]: begin - stat_rx_err_framing_reg <= !frame_reg; - end - BLOCK_TYPE_TERM_6[7:4]: begin - stat_rx_err_framing_reg <= !frame_reg; - end - BLOCK_TYPE_TERM_7[7:4]: begin - stat_rx_err_framing_reg <= !frame_reg; - end - default: begin - // invalid block type - frame_reg <= 1'b0; - end - endcase - end else begin - // invalid header - frame_reg <= 1'b0; - end - - // check all block type bits to detect bad encodings - if (encoded_rx_hdr == SYNC_DATA) begin - // data - nothing encoded - end else if (encoded_rx_hdr == SYNC_CTRL) begin - // control - check for bad block types - case (encoded_rx_data[7:0]) - BLOCK_TYPE_CTRL: begin end - BLOCK_TYPE_OS_4: begin end - BLOCK_TYPE_START_4: begin end - BLOCK_TYPE_OS_START: begin end - BLOCK_TYPE_OS_04: begin end - BLOCK_TYPE_START_0: begin end - BLOCK_TYPE_OS_0: begin end - BLOCK_TYPE_TERM_0: begin end - BLOCK_TYPE_TERM_1: begin end - BLOCK_TYPE_TERM_2: begin end - BLOCK_TYPE_TERM_3: begin end - BLOCK_TYPE_TERM_4: begin end - BLOCK_TYPE_TERM_5: begin end - BLOCK_TYPE_TERM_6: begin end - BLOCK_TYPE_TERM_7: begin end - default: begin - // invalid block type - stat_rx_err_bad_block_reg <= 1'b1; - end - endcase - end else begin - // invalid header - stat_rx_err_bad_block_reg <= 1'b1; - end - - // capture timestamps - if (input_start_swap) begin - start_packet_reg <= 2'b10; - if (PTP_TS_FMT_TOD) begin - ptp_ts_reg[45:0] <= ptp_ts[45:0] + 46'(ts_inc_reg >> 1); - ptp_ts_reg[95:48] <= ptp_ts[95:48]; end else begin - ptp_ts_reg <= ptp_ts + PTP_TS_W'(ts_inc_reg >> 1); + // invalid header + stat_rx_err_bad_block_reg <= 1'b1; end + + // capture timestamps + if (input_start_swap) begin + start_packet_reg <= 2'b10; + if (PTP_TS_FMT_TOD) begin + ptp_ts_reg[45:0] <= ptp_ts[45:0] + 46'(ts_inc_reg >> 1); + ptp_ts_reg[95:48] <= ptp_ts[95:48]; + end else begin + ptp_ts_reg <= ptp_ts + PTP_TS_W'(ts_inc_reg >> 1); + end + end + + if (input_start_d0 && !lanes_swapped) begin + start_packet_reg <= 2'b01; + ptp_ts_reg <= ptp_ts; + end + + input_type_d1 <= input_type_d0; + input_start_d1 <= input_start_d0; + input_data_d1 <= input_data_d0; + + if (reset_crc) begin + crc_state <= '1; + end else begin + crc_state <= crc_next; + end + + crc_valid_save <= crc_valid; end - if (input_start_d0 && !lanes_swapped) begin - start_packet_reg <= 2'b01; - ptp_ts_reg <= ptp_ts; - end - - input_type_d1 <= input_type_d0; - input_start_d1 <= input_start_d0; - input_data_d1 <= input_data_d0; - - if (reset_crc) begin - crc_state <= '1; - end else begin - crc_state <= crc_next; - end - - crc_valid_save <= crc_valid; - last_ts_reg <= (4+16)'(ptp_ts); ts_inc_reg <= (4+16)'(ptp_ts) - last_ts_reg; diff --git a/src/eth/rtl/taxi_axis_baser_tx_64.sv b/src/eth/rtl/taxi_axis_baser_tx_64.sv index d20bc3d..4e13bf8 100644 --- a/src/eth/rtl/taxi_axis_baser_tx_64.sv +++ b/src/eth/rtl/taxi_axis_baser_tx_64.sv @@ -19,6 +19,8 @@ module taxi_axis_baser_tx_64 # ( parameter DATA_W = 64, parameter HDR_W = 2, + parameter logic GBX_IF_EN = 1'b0, + parameter GBX_CNT = 1, parameter logic PADDING_EN = 1'b1, parameter logic DIC_EN = 1'b1, parameter MIN_FRAME_LEN = 64, @@ -41,7 +43,12 @@ module taxi_axis_baser_tx_64 # * 10GBASE-R encoded interface */ output wire logic [DATA_W-1:0] encoded_tx_data, + output wire logic encoded_tx_data_valid, output wire logic [HDR_W-1:0] encoded_tx_hdr, + output wire logic encoded_tx_hdr_valid, + input wire logic [GBX_CNT-1:0] tx_gbx_req_start = '0, + input wire logic tx_gbx_req_stall = '0, + output wire logic [GBX_CNT-1:0] tx_gbx_start, /* * PTP @@ -213,7 +220,10 @@ logic [31:0] crc_state_reg[7:0]; wire [31:0] crc_state_next[7:0]; logic [DATA_W-1:0] encoded_tx_data_reg = {{8{CTRL_IDLE}}, BLOCK_TYPE_CTRL}; +logic encoded_tx_data_valid_reg = 1'b0; logic [HDR_W-1:0] encoded_tx_hdr_reg = SYNC_CTRL; +logic encoded_tx_hdr_valid_reg = 1'b0; +logic [GBX_CNT-1:0] tx_gbx_start_reg = '0; logic [DATA_W-1:0] output_data_reg = '0, output_data_next; logic [3:0] output_type_reg = OUTPUT_TYPE_IDLE, output_type_next; @@ -235,10 +245,13 @@ logic stat_tx_err_underflow_reg = 1'b0, stat_tx_err_underflow_next; logic [4+16-1:0] last_ts_reg = '0; logic [4+16-1:0] ts_inc_reg = '0; -assign s_axis_tx.tready = s_axis_tx_tready_reg; +assign s_axis_tx.tready = s_axis_tx_tready_reg && (!GBX_IF_EN || !tx_gbx_req_stall); assign encoded_tx_data = encoded_tx_data_reg; +assign encoded_tx_data_valid = GBX_IF_EN ? encoded_tx_data_valid_reg : 1'b1; assign encoded_tx_hdr = encoded_tx_hdr_reg; +assign encoded_tx_hdr_valid = GBX_IF_EN ? encoded_tx_hdr_valid_reg : 1'b1; +assign tx_gbx_start = GBX_IF_EN ? tx_gbx_start_reg : '0; assign m_axis_tx_cpl.tdata = PTP_TS_EN ? ((!PTP_TS_FMT_TOD || m_axis_tx_cpl_ts_borrow_reg) ? m_axis_tx_cpl_ts_reg : m_axis_tx_cpl_ts_adj_reg) : '0; assign m_axis_tx_cpl.tkeep = 1'b1; @@ -413,113 +426,126 @@ always_comb begin frame_next = !s_axis_tx.tlast; end - // counter for min frame length enforcement - if (frame_min_count_reg > MIN_LEN_W'(KEEP_W)) begin - frame_min_count_next = MIN_LEN_W'(frame_min_count_reg - KEEP_W); + if (GBX_IF_EN && tx_gbx_req_stall) begin + // gearbox stall - hold state + state_next = state_reg; + frame_start_next = frame_start_reg; + s_axis_tx_tready_next = s_axis_tx_tready_reg; end else begin - frame_min_count_next = 0; - end - - // counter to measure frame length - if (&frame_len_reg[15:3] == 0) begin - frame_len_next = frame_len_reg + 16'(KEEP_W); - end else begin - frame_len_next = '1; - end - - // counter for max frame length enforcement - if (frame_len_lim_reg[15:3] != 0) begin - frame_len_lim_next = frame_len_lim_reg - 16'(KEEP_W); - end else begin - frame_len_lim_next = '0; - end - - // address and ethertype checks - if (&hdr_ptr_reg == 0) begin - hdr_ptr_next = hdr_ptr_reg + 1; - end - - case (hdr_ptr_reg) - 2'd0: begin - is_mcast_next = s_tdata_reg[0]; - is_bcast_next = &s_tdata_reg[47:0]; + // counter for min frame length enforcement + if (frame_min_count_reg > MIN_LEN_W'(KEEP_W)) begin + frame_min_count_next = MIN_LEN_W'(frame_min_count_reg - KEEP_W); + end else begin + frame_min_count_next = 0; end - 2'd1: is_8021q_next = {s_tdata_reg[39:32], s_tdata_reg[47:40]} == 16'h8100; - default: begin - // do nothing + + // counter to measure frame length + if (&frame_len_reg[15:3] == 0) begin + frame_len_next = frame_len_reg + 16'(KEEP_W); + end else begin + frame_len_next = '1; end - endcase - if (ifg_cnt_reg[7:3] != 0) begin - ifg_cnt_next = ifg_cnt_reg - 8'(KEEP_W); - end else begin - ifg_cnt_next = '0; - end + // counter for max frame length enforcement + if (frame_len_lim_reg[15:3] != 0) begin + frame_len_lim_next = frame_len_lim_reg - 16'(KEEP_W); + end else begin + frame_len_lim_next = '0; + end - case (state_reg) - STATE_IDLE: begin - // idle state - wait for data - frame_error_next = 1'b0; - frame_min_count_next = MIN_LEN_W'(MIN_FRAME_LEN-4-KEEP_W); - hdr_ptr_next = 0; - frame_len_next = 0; - frame_len_lim_next = cfg_tx_max_pkt_len; - reset_crc = 1'b1; - s_axis_tx_tready_next = 1'b1; + // address and ethertype checks + if (&hdr_ptr_reg == 0) begin + hdr_ptr_next = hdr_ptr_reg + 1; + end - output_data_next = s_tdata_reg; - output_type_next = OUTPUT_TYPE_IDLE; + case (hdr_ptr_reg) + 2'd0: begin + is_mcast_next = s_tdata_reg[0]; + is_bcast_next = &s_tdata_reg[47:0]; + end + 2'd1: is_8021q_next = {s_tdata_reg[39:32], s_tdata_reg[47:40]} == 16'h8100; + default: begin + // do nothing + end + endcase - s_tdata_next = s_axis_tx_tdata_masked; - s_empty_next = keep2empty(s_axis_tx.tkeep); + if (ifg_cnt_reg[7:3] != 0) begin + ifg_cnt_next = ifg_cnt_reg - 8'(KEEP_W); + end else begin + ifg_cnt_next = '0; + end - if (s_axis_tx.tvalid && cfg_tx_enable) begin - // Preamble and SFD - output_data_next = {ETH_SFD, {7{ETH_PRE}}}; - output_type_next = OUTPUT_TYPE_START_0; - frame_start_next = 1'b1; + case (state_reg) + STATE_IDLE: begin + // idle state - wait for data + frame_error_next = 1'b0; + frame_min_count_next = MIN_LEN_W'(MIN_FRAME_LEN-4-KEEP_W); + hdr_ptr_next = 0; + frame_len_next = 0; + frame_len_lim_next = cfg_tx_max_pkt_len; + reset_crc = 1'b1; s_axis_tx_tready_next = 1'b1; - state_next = STATE_PAYLOAD; - end else begin - swap_lanes_next = 1'b0; - ifg_count_next = 8'd0; - deficit_idle_count_next = 2'd0; - state_next = STATE_IDLE; + + output_data_next = s_tdata_reg; + output_type_next = OUTPUT_TYPE_IDLE; + + s_tdata_next = s_axis_tx_tdata_masked; + s_empty_next = keep2empty(s_axis_tx.tkeep); + + if (s_axis_tx.tvalid && cfg_tx_enable) begin + // Preamble and SFD + output_data_next = {ETH_SFD, {7{ETH_PRE}}}; + output_type_next = OUTPUT_TYPE_START_0; + frame_start_next = 1'b1; + s_axis_tx_tready_next = 1'b1; + state_next = STATE_PAYLOAD; + end else begin + swap_lanes_next = 1'b0; + ifg_count_next = 8'd0; + deficit_idle_count_next = 2'd0; + state_next = STATE_IDLE; + end end - end - STATE_PAYLOAD: begin - // transfer payload - update_crc = 1'b1; - s_axis_tx_tready_next = 1'b1; + STATE_PAYLOAD: begin + // transfer payload + update_crc = 1'b1; + s_axis_tx_tready_next = 1'b1; - output_data_next = s_tdata_reg; - output_type_next = OUTPUT_TYPE_DATA; + output_data_next = s_tdata_reg; + output_type_next = OUTPUT_TYPE_DATA; - s_tdata_next = s_axis_tx_tdata_masked; - s_empty_next = keep2empty(s_axis_tx.tkeep); + s_tdata_next = s_axis_tx_tdata_masked; + s_empty_next = keep2empty(s_axis_tx.tkeep); - stat_tx_byte_next = 4'(KEEP_W); + stat_tx_byte_next = 4'(KEEP_W); - if (s_axis_tx.tvalid && s_axis_tx.tlast) begin - frame_oversize_next = frame_len_lim_reg < 16'(8+8+4-keep2empty(s_axis_tx.tkeep)); - end else begin - frame_oversize_next = frame_len_lim_reg < 8+8; - end + if (s_axis_tx.tvalid && s_axis_tx.tlast) begin + frame_oversize_next = frame_len_lim_reg < 16'(8+8+4-keep2empty(s_axis_tx.tkeep)); + end else begin + frame_oversize_next = frame_len_lim_reg < 8+8; + end - if (!s_axis_tx.tvalid || s_axis_tx.tlast || frame_oversize_next) begin - s_axis_tx_tready_next = frame_next; // drop frame - frame_error_next = !s_axis_tx.tvalid || s_axis_tx.tuser[0] || frame_oversize_next; - stat_tx_err_user_next = s_axis_tx.tuser[0]; - stat_tx_err_underflow_next = !s_axis_tx.tvalid; + if (!s_axis_tx.tvalid || s_axis_tx.tlast || frame_oversize_next) begin + s_axis_tx_tready_next = frame_next; // drop frame + frame_error_next = !s_axis_tx.tvalid || s_axis_tx.tuser[0] || frame_oversize_next; + stat_tx_err_user_next = s_axis_tx.tuser[0]; + stat_tx_err_underflow_next = !s_axis_tx.tvalid; - if (PADDING_EN && frame_min_count_reg != 0) begin - if (frame_min_count_reg > MIN_LEN_W'(KEEP_W)) begin - s_empty_next = 0; - state_next = STATE_PAD; - end else begin - if (keep2empty(s_axis_tx.tkeep) > 3'(KEEP_W-frame_min_count_reg)) begin - s_empty_next = 3'(KEEP_W-frame_min_count_reg); + if (PADDING_EN && frame_min_count_reg != 0) begin + if (frame_min_count_reg > MIN_LEN_W'(KEEP_W)) begin + s_empty_next = 0; + state_next = STATE_PAD; + end else begin + if (keep2empty(s_axis_tx.tkeep) > 3'(KEEP_W-frame_min_count_reg)) begin + s_empty_next = 3'(KEEP_W-frame_min_count_reg); + end + if (frame_error_next) begin + state_next = STATE_ERR; + end else begin + state_next = STATE_FCS_1; + end end + end else begin if (frame_error_next) begin state_next = STATE_ERR; end else begin @@ -527,57 +553,74 @@ always_comb begin end end end else begin - if (frame_error_next) begin + state_next = STATE_PAYLOAD; + end + end + STATE_PAD: begin + // pad frame to MIN_FRAME_LEN + s_axis_tx_tready_next = frame_next; // drop frame + + output_data_next = s_tdata_reg; + output_type_next = OUTPUT_TYPE_DATA; + + s_tdata_next = 64'd0; + s_empty_next = 0; + + stat_tx_byte_next = 4'(KEEP_W); + + update_crc = 1'b1; + + if (frame_min_count_reg > MIN_LEN_W'(KEEP_W)) begin + state_next = STATE_PAD; + end else begin + s_empty_next = 3'(KEEP_W-frame_min_count_reg); + if (frame_error_reg) begin state_next = STATE_ERR; end else begin state_next = STATE_FCS_1; end end - end else begin - state_next = STATE_PAYLOAD; end - end - STATE_PAD: begin - // pad frame to MIN_FRAME_LEN - s_axis_tx_tready_next = frame_next; // drop frame + STATE_FCS_1: begin + // last cycle + s_axis_tx_tready_next = frame_next; // drop frame - output_data_next = s_tdata_reg; - output_type_next = OUTPUT_TYPE_DATA; + output_data_next = fcs_output_data_0; + output_type_next = fcs_output_type_0; - s_tdata_next = 64'd0; - s_empty_next = 0; + update_crc = 1'b1; - stat_tx_byte_next = 4'(KEEP_W); - - update_crc = 1'b1; - - if (frame_min_count_reg > MIN_LEN_W'(KEEP_W)) begin - state_next = STATE_PAD; - end else begin - s_empty_next = 3'(KEEP_W-frame_min_count_reg); - if (frame_error_reg) begin - state_next = STATE_ERR; + ifg_count_next = (cfg_tx_ifg > 8'd12 ? cfg_tx_ifg : 8'd12) - ifg_offset + (swap_lanes_reg ? 8'd4 : 8'd0) + 8'(deficit_idle_count_reg); + if (s_empty_reg <= 4) begin + stat_tx_byte_next = 4'(KEEP_W); + state_next = STATE_FCS_2; end else begin - state_next = STATE_FCS_1; + stat_tx_byte_next = 12-s_empty_reg; + frame_len_next = frame_len_reg + 16'(12-s_empty_reg); + stat_tx_pkt_len_next = frame_len_next; + stat_tx_pkt_good_next = !frame_error_reg; + stat_tx_pkt_bad_next = frame_error_reg; + stat_tx_pkt_ucast_next = !is_mcast_reg; + stat_tx_pkt_mcast_next = is_mcast_reg && !is_bcast_reg; + stat_tx_pkt_bcast_next = is_bcast_reg; + stat_tx_pkt_vlan_next = is_8021q_reg; + stat_tx_err_oversize_next = frame_oversize_reg; + + state_next = STATE_IFG; end end - end - STATE_FCS_1: begin - // last cycle - s_axis_tx_tready_next = frame_next; // drop frame + STATE_FCS_2: begin + // last cycle + s_axis_tx_tready_next = frame_next; // drop frame - output_data_next = fcs_output_data_0; - output_type_next = fcs_output_type_0; + output_data_next = fcs_output_data_1; + output_type_next = fcs_output_type_1; - update_crc = 1'b1; + stat_tx_byte_next = 4-s_empty_reg; + frame_len_next = frame_len_reg + 16'(4-s_empty_reg); + + reset_crc = 1'b1; - ifg_count_next = (cfg_tx_ifg > 8'd12 ? cfg_tx_ifg : 8'd12) - ifg_offset + (swap_lanes_reg ? 8'd4 : 8'd0) + 8'(deficit_idle_count_reg); - if (s_empty_reg <= 4) begin - stat_tx_byte_next = 4'(KEEP_W); - state_next = STATE_FCS_2; - end else begin - stat_tx_byte_next = 12-s_empty_reg; - frame_len_next = frame_len_reg + 16'(12-s_empty_reg); stat_tx_pkt_len_next = frame_len_next; stat_tx_pkt_good_next = !frame_error_reg; stat_tx_pkt_bad_next = frame_error_reg; @@ -587,120 +630,97 @@ always_comb begin stat_tx_pkt_vlan_next = is_8021q_reg; stat_tx_err_oversize_next = frame_oversize_reg; + if (DIC_EN) begin + if (ifg_count_next > 8'd7) begin + state_next = STATE_IFG; + end else begin + if (ifg_count_next >= 8'd4) begin + deficit_idle_count_next = 2'(ifg_count_next - 8'd4); + swap_lanes_next = 1'b1; + end else begin + deficit_idle_count_next = 2'(ifg_count_next); + ifg_count_next = 8'd0; + swap_lanes_next = 1'b0; + end + s_axis_tx_tready_next = 1'b1; + state_next = STATE_IDLE; + end + end else begin + if (ifg_count_next > 8'd4) begin + state_next = STATE_IFG; + end else begin + s_axis_tx_tready_next = 1'b1; + swap_lanes_next = ifg_count_next != 0; + state_next = STATE_IDLE; + end + end + end + STATE_ERR: begin + // terminate packet with error + s_axis_tx_tready_next = frame_next; // drop frame + + output_data_next = s_tdata_reg; + output_type_next = OUTPUT_TYPE_ERROR; + + ifg_count_next = cfg_tx_ifg > 8'd12 ? cfg_tx_ifg : 8'd12; + + stat_tx_pkt_len_next = frame_len_reg; + stat_tx_pkt_good_next = !frame_error_reg; + stat_tx_pkt_bad_next = frame_error_reg; + stat_tx_pkt_ucast_next = !is_mcast_reg; + stat_tx_pkt_mcast_next = is_mcast_reg && !is_bcast_reg; + stat_tx_pkt_bcast_next = is_bcast_reg; + stat_tx_pkt_vlan_next = is_8021q_reg; + stat_tx_err_oversize_next = frame_oversize_reg; + state_next = STATE_IFG; end - end - STATE_FCS_2: begin - // last cycle - s_axis_tx_tready_next = frame_next; // drop frame + STATE_IFG: begin + // send IFG + s_axis_tx_tready_next = frame_next; // drop frame - output_data_next = fcs_output_data_1; - output_type_next = fcs_output_type_1; + output_data_next = s_tdata_reg; + output_type_next = OUTPUT_TYPE_IDLE; - stat_tx_byte_next = 4-s_empty_reg; - frame_len_next = frame_len_reg + 16'(4-s_empty_reg); - - reset_crc = 1'b1; - - stat_tx_pkt_len_next = frame_len_next; - stat_tx_pkt_good_next = !frame_error_reg; - stat_tx_pkt_bad_next = frame_error_reg; - stat_tx_pkt_ucast_next = !is_mcast_reg; - stat_tx_pkt_mcast_next = is_mcast_reg && !is_bcast_reg; - stat_tx_pkt_bcast_next = is_bcast_reg; - stat_tx_pkt_vlan_next = is_8021q_reg; - stat_tx_err_oversize_next = frame_oversize_reg; - - if (DIC_EN) begin - if (ifg_count_next > 8'd7) begin - state_next = STATE_IFG; + if (ifg_count_reg > 8'd8) begin + ifg_count_next = ifg_count_reg - 8'd8; end else begin - if (ifg_count_next >= 8'd4) begin - deficit_idle_count_next = 2'(ifg_count_next - 8'd4); - swap_lanes_next = 1'b1; + ifg_count_next = 8'd0; + end + + reset_crc = 1'b1; + + if (DIC_EN) begin + if (ifg_count_next > 8'd7 || frame_reg) begin + state_next = STATE_IFG; end else begin - deficit_idle_count_next = 2'(ifg_count_next); - ifg_count_next = 8'd0; - swap_lanes_next = 1'b0; + if (ifg_count_next >= 8'd4) begin + deficit_idle_count_next = 2'(ifg_count_next - 8'd4); + swap_lanes_next = 1'b1; + end else begin + deficit_idle_count_next = 2'(ifg_count_next); + ifg_count_next = 8'd0; + swap_lanes_next = 1'b0; + end + s_axis_tx_tready_next = 1'b1; + state_next = STATE_IDLE; end - s_axis_tx_tready_next = 1'b1; - state_next = STATE_IDLE; - end - end else begin - if (ifg_count_next > 8'd4) begin - state_next = STATE_IFG; end else begin - s_axis_tx_tready_next = 1'b1; - swap_lanes_next = ifg_count_next != 0; - state_next = STATE_IDLE; - end - end - end - STATE_ERR: begin - // terminate packet with error - s_axis_tx_tready_next = frame_next; // drop frame - - output_data_next = s_tdata_reg; - output_type_next = OUTPUT_TYPE_ERROR; - - ifg_count_next = cfg_tx_ifg > 8'd12 ? cfg_tx_ifg : 8'd12; - - stat_tx_pkt_len_next = frame_len_reg; - stat_tx_pkt_good_next = !frame_error_reg; - stat_tx_pkt_bad_next = frame_error_reg; - stat_tx_pkt_ucast_next = !is_mcast_reg; - stat_tx_pkt_mcast_next = is_mcast_reg && !is_bcast_reg; - stat_tx_pkt_bcast_next = is_bcast_reg; - stat_tx_pkt_vlan_next = is_8021q_reg; - stat_tx_err_oversize_next = frame_oversize_reg; - - state_next = STATE_IFG; - end - STATE_IFG: begin - // send IFG - s_axis_tx_tready_next = frame_next; // drop frame - - output_data_next = s_tdata_reg; - output_type_next = OUTPUT_TYPE_IDLE; - - if (ifg_count_reg > 8'd8) begin - ifg_count_next = ifg_count_reg - 8'd8; - end else begin - ifg_count_next = 8'd0; - end - - reset_crc = 1'b1; - - if (DIC_EN) begin - if (ifg_count_next > 8'd7 || frame_reg) begin - state_next = STATE_IFG; - end else begin - if (ifg_count_next >= 8'd4) begin - deficit_idle_count_next = 2'(ifg_count_next - 8'd4); - swap_lanes_next = 1'b1; + if (ifg_count_next > 8'd4 || frame_reg) begin + state_next = STATE_IFG; end else begin - deficit_idle_count_next = 2'(ifg_count_next); - ifg_count_next = 8'd0; - swap_lanes_next = 1'b0; + s_axis_tx_tready_next = 1'b1; + swap_lanes_next = ifg_count_next != 0; + state_next = STATE_IDLE; end - s_axis_tx_tready_next = 1'b1; - state_next = STATE_IDLE; - end - end else begin - if (ifg_count_next > 8'd4 || frame_reg) begin - state_next = STATE_IFG; - end else begin - s_axis_tx_tready_next = 1'b1; - swap_lanes_next = ifg_count_next != 0; - state_next = STATE_IDLE; end end - end - default: begin - // invalid state, return to idle - state_next = STATE_IDLE; - end - endcase + default: begin + // invalid state, return to idle + state_next = STATE_IDLE; + end + endcase + end end always_ff @(posedge clk) begin @@ -746,33 +766,6 @@ always_ff @(posedge clk) begin stat_tx_err_user_reg <= stat_tx_err_user_next; stat_tx_err_underflow_reg <= stat_tx_err_underflow_next; - delay_type_valid <= 1'b0; - delay_type <= output_type_next ^ 4'd4; - - swap_data <= output_data_next[63:32]; - - if (swap_lanes_reg) begin - output_data_reg <= {output_data_next[31:0], swap_data}; - if (delay_type_valid) begin - output_type_reg <= delay_type; - end else if (output_type_next == OUTPUT_TYPE_START_0) begin - output_type_reg <= OUTPUT_TYPE_START_4; - end else if (output_type_next[3]) begin - // OUTPUT_TYPE_TERM_* - if (output_type_next[2]) begin - delay_type_valid <= 1'b1; - output_type_reg <= OUTPUT_TYPE_DATA; - end else begin - output_type_reg <= output_type_next ^ 4'd4; - end - end else begin - output_type_reg <= output_type_next; - end - end else begin - output_data_reg <= output_data_next; - output_type_reg <= output_type_next; - end - if (PTP_TS_EN && PTP_TS_FMT_TOD) begin m_axis_tx_cpl_valid_reg <= m_axis_tx_cpl_valid_int_reg; m_axis_tx_cpl_ts_adj_reg[15:0] <= m_axis_tx_cpl_ts_reg[15:0]; @@ -781,113 +774,151 @@ always_ff @(posedge clk) begin m_axis_tx_cpl_ts_adj_reg[95:48] <= m_axis_tx_cpl_ts_reg[95:48] + 1; end - if (frame_start_reg) begin + if (GBX_IF_EN && tx_gbx_req_stall) begin + // gearbox stall + encoded_tx_data_valid_reg <= 1'b0; + encoded_tx_hdr_valid_reg <= 1'b0; + end else begin + delay_type_valid <= 1'b0; + delay_type <= output_type_next ^ 4'd4; + + swap_data <= output_data_next[63:32]; + if (swap_lanes_reg) begin - if (PTP_TS_EN) begin - if (PTP_TS_FMT_TOD) begin - m_axis_tx_cpl_ts_reg[45:0] <= ptp_ts[45:0] + 46'(ts_inc_reg >> 1); - m_axis_tx_cpl_ts_reg[95:48] <= ptp_ts[95:48]; + output_data_reg <= {output_data_next[31:0], swap_data}; + if (delay_type_valid) begin + output_type_reg <= delay_type; + end else if (output_type_next == OUTPUT_TYPE_START_0) begin + output_type_reg <= OUTPUT_TYPE_START_4; + end else if (output_type_next[3]) begin + // OUTPUT_TYPE_TERM_* + if (output_type_next[2]) begin + delay_type_valid <= 1'b1; + output_type_reg <= OUTPUT_TYPE_DATA; end else begin - m_axis_tx_cpl_ts_reg <= ptp_ts + PTP_TS_W'(ts_inc_reg >> 1); + output_type_reg <= output_type_next ^ 4'd4; + end + end else begin + output_type_reg <= output_type_next; + end + end else begin + output_data_reg <= output_data_next; + output_type_reg <= output_type_next; + end + + if (frame_start_reg) begin + if (swap_lanes_reg) begin + if (PTP_TS_EN) begin + if (PTP_TS_FMT_TOD) begin + m_axis_tx_cpl_ts_reg[45:0] <= ptp_ts[45:0] + 46'(ts_inc_reg >> 1); + m_axis_tx_cpl_ts_reg[95:48] <= ptp_ts[95:48]; + end else begin + m_axis_tx_cpl_ts_reg <= ptp_ts + PTP_TS_W'(ts_inc_reg >> 1); + end + end + start_packet_reg <= 2'b10; + end else begin + if (PTP_TS_EN) begin + m_axis_tx_cpl_ts_reg <= ptp_ts; + end + start_packet_reg <= 2'b01; + end + m_axis_tx_cpl_tag_reg <= s_axis_tx.tid; + if (TX_CPL_CTRL_IN_TUSER) begin + if (PTP_TS_FMT_TOD) begin + m_axis_tx_cpl_valid_int_reg <= (s_axis_tx.tuser >> 1) == 0; + end else begin + m_axis_tx_cpl_valid_reg <= (s_axis_tx.tuser >> 1) == 0; + end + end else begin + if (PTP_TS_FMT_TOD) begin + m_axis_tx_cpl_valid_int_reg <= 1'b1; + end else begin + m_axis_tx_cpl_valid_reg <= 1'b1; end end - start_packet_reg <= 2'b10; - end else begin - if (PTP_TS_EN) begin - m_axis_tx_cpl_ts_reg <= ptp_ts; - end - start_packet_reg <= 2'b01; end - m_axis_tx_cpl_tag_reg <= s_axis_tx.tid; - if (TX_CPL_CTRL_IN_TUSER) begin - if (PTP_TS_FMT_TOD) begin - m_axis_tx_cpl_valid_int_reg <= (s_axis_tx.tuser >> 1) == 0; - end else begin - m_axis_tx_cpl_valid_reg <= (s_axis_tx.tuser >> 1) == 0; + + case (output_type_reg) + OUTPUT_TYPE_IDLE: begin + encoded_tx_data_reg <= {{8{CTRL_IDLE}}, BLOCK_TYPE_CTRL}; + encoded_tx_hdr_reg <= SYNC_CTRL; end - end else begin - if (PTP_TS_FMT_TOD) begin - m_axis_tx_cpl_valid_int_reg <= 1'b1; - end else begin - m_axis_tx_cpl_valid_reg <= 1'b1; + OUTPUT_TYPE_ERROR: begin + encoded_tx_data_reg <= {{8{CTRL_ERROR}}, BLOCK_TYPE_CTRL}; + encoded_tx_hdr_reg <= SYNC_CTRL; end + OUTPUT_TYPE_START_0: begin + encoded_tx_data_reg <= {output_data_reg[63:8], BLOCK_TYPE_START_0}; + encoded_tx_hdr_reg <= SYNC_CTRL; + end + OUTPUT_TYPE_START_4: begin + encoded_tx_data_reg <= {output_data_reg[63:40], 4'd0, {4{CTRL_IDLE}}, BLOCK_TYPE_START_4}; + encoded_tx_hdr_reg <= SYNC_CTRL; + end + OUTPUT_TYPE_DATA: begin + encoded_tx_data_reg <= output_data_reg; + encoded_tx_hdr_reg <= SYNC_DATA; + end + OUTPUT_TYPE_TERM_0: begin + encoded_tx_data_reg <= {{7{CTRL_IDLE}}, 7'd0, BLOCK_TYPE_TERM_0}; + encoded_tx_hdr_reg <= SYNC_CTRL; + end + OUTPUT_TYPE_TERM_1: begin + encoded_tx_data_reg <= {{6{CTRL_IDLE}}, 6'd0, output_data_reg[7:0], BLOCK_TYPE_TERM_1}; + encoded_tx_hdr_reg <= SYNC_CTRL; + end + OUTPUT_TYPE_TERM_2: begin + encoded_tx_data_reg <= {{5{CTRL_IDLE}}, 5'd0, output_data_reg[15:0], BLOCK_TYPE_TERM_2}; + encoded_tx_hdr_reg <= SYNC_CTRL; + end + OUTPUT_TYPE_TERM_3: begin + encoded_tx_data_reg <= {{4{CTRL_IDLE}}, 4'd0, output_data_reg[23:0], BLOCK_TYPE_TERM_3}; + encoded_tx_hdr_reg <= SYNC_CTRL; + end + OUTPUT_TYPE_TERM_4: begin + encoded_tx_data_reg <= {{3{CTRL_IDLE}}, 3'd0, output_data_reg[31:0], BLOCK_TYPE_TERM_4}; + encoded_tx_hdr_reg <= SYNC_CTRL; + end + OUTPUT_TYPE_TERM_5: begin + encoded_tx_data_reg <= {{2{CTRL_IDLE}}, 2'd0, output_data_reg[39:0], BLOCK_TYPE_TERM_5}; + encoded_tx_hdr_reg <= SYNC_CTRL; + end + OUTPUT_TYPE_TERM_6: begin + encoded_tx_data_reg <= {{1{CTRL_IDLE}}, 1'd0, output_data_reg[47:0], BLOCK_TYPE_TERM_6}; + encoded_tx_hdr_reg <= SYNC_CTRL; + end + OUTPUT_TYPE_TERM_7: begin + encoded_tx_data_reg <= {output_data_reg[55:0], BLOCK_TYPE_TERM_7}; + encoded_tx_hdr_reg <= SYNC_CTRL; + end + default: begin + encoded_tx_data_reg <= {{8{CTRL_ERROR}}, BLOCK_TYPE_CTRL}; + encoded_tx_hdr_reg <= SYNC_CTRL; + end + endcase + + encoded_tx_data_valid_reg <= 1'b1; + encoded_tx_hdr_valid_reg <= 1'b1; + + crc_state_reg[0] <= crc_state_next[0]; + crc_state_reg[1] <= crc_state_next[1]; + crc_state_reg[2] <= crc_state_next[2]; + crc_state_reg[3] <= crc_state_next[3]; + crc_state_reg[4] <= crc_state_next[4]; + crc_state_reg[5] <= crc_state_next[5]; + crc_state_reg[6] <= crc_state_next[6]; + + if (update_crc) begin + crc_state_reg[7] <= crc_state_next[7]; + end + + if (reset_crc) begin + crc_state_reg[7] <= '1; end end - case (output_type_reg) - OUTPUT_TYPE_IDLE: begin - encoded_tx_data_reg <= {{8{CTRL_IDLE}}, BLOCK_TYPE_CTRL}; - encoded_tx_hdr_reg <= SYNC_CTRL; - end - OUTPUT_TYPE_ERROR: begin - encoded_tx_data_reg <= {{8{CTRL_ERROR}}, BLOCK_TYPE_CTRL}; - encoded_tx_hdr_reg <= SYNC_CTRL; - end - OUTPUT_TYPE_START_0: begin - encoded_tx_data_reg <= {output_data_reg[63:8], BLOCK_TYPE_START_0}; - encoded_tx_hdr_reg <= SYNC_CTRL; - end - OUTPUT_TYPE_START_4: begin - encoded_tx_data_reg <= {output_data_reg[63:40], 4'd0, {4{CTRL_IDLE}}, BLOCK_TYPE_START_4}; - encoded_tx_hdr_reg <= SYNC_CTRL; - end - OUTPUT_TYPE_DATA: begin - encoded_tx_data_reg <= output_data_reg; - encoded_tx_hdr_reg <= SYNC_DATA; - end - OUTPUT_TYPE_TERM_0: begin - encoded_tx_data_reg <= {{7{CTRL_IDLE}}, 7'd0, BLOCK_TYPE_TERM_0}; - encoded_tx_hdr_reg <= SYNC_CTRL; - end - OUTPUT_TYPE_TERM_1: begin - encoded_tx_data_reg <= {{6{CTRL_IDLE}}, 6'd0, output_data_reg[7:0], BLOCK_TYPE_TERM_1}; - encoded_tx_hdr_reg <= SYNC_CTRL; - end - OUTPUT_TYPE_TERM_2: begin - encoded_tx_data_reg <= {{5{CTRL_IDLE}}, 5'd0, output_data_reg[15:0], BLOCK_TYPE_TERM_2}; - encoded_tx_hdr_reg <= SYNC_CTRL; - end - OUTPUT_TYPE_TERM_3: begin - encoded_tx_data_reg <= {{4{CTRL_IDLE}}, 4'd0, output_data_reg[23:0], BLOCK_TYPE_TERM_3}; - encoded_tx_hdr_reg <= SYNC_CTRL; - end - OUTPUT_TYPE_TERM_4: begin - encoded_tx_data_reg <= {{3{CTRL_IDLE}}, 3'd0, output_data_reg[31:0], BLOCK_TYPE_TERM_4}; - encoded_tx_hdr_reg <= SYNC_CTRL; - end - OUTPUT_TYPE_TERM_5: begin - encoded_tx_data_reg <= {{2{CTRL_IDLE}}, 2'd0, output_data_reg[39:0], BLOCK_TYPE_TERM_5}; - encoded_tx_hdr_reg <= SYNC_CTRL; - end - OUTPUT_TYPE_TERM_6: begin - encoded_tx_data_reg <= {{1{CTRL_IDLE}}, 1'd0, output_data_reg[47:0], BLOCK_TYPE_TERM_6}; - encoded_tx_hdr_reg <= SYNC_CTRL; - end - OUTPUT_TYPE_TERM_7: begin - encoded_tx_data_reg <= {output_data_reg[55:0], BLOCK_TYPE_TERM_7}; - encoded_tx_hdr_reg <= SYNC_CTRL; - end - default: begin - encoded_tx_data_reg <= {{8{CTRL_ERROR}}, BLOCK_TYPE_CTRL}; - encoded_tx_hdr_reg <= SYNC_CTRL; - end - endcase - - crc_state_reg[0] <= crc_state_next[0]; - crc_state_reg[1] <= crc_state_next[1]; - crc_state_reg[2] <= crc_state_next[2]; - crc_state_reg[3] <= crc_state_next[3]; - crc_state_reg[4] <= crc_state_next[4]; - crc_state_reg[5] <= crc_state_next[5]; - crc_state_reg[6] <= crc_state_next[6]; - - if (update_crc) begin - crc_state_reg[7] <= crc_state_next[7]; - end - - if (reset_crc) begin - crc_state_reg[7] <= '1; - end + tx_gbx_start_reg <= tx_gbx_req_start; last_ts_reg <= (4+16)'(ptp_ts); ts_inc_reg <= (4+16)'(ptp_ts) - last_ts_reg; @@ -909,7 +940,10 @@ always_ff @(posedge clk) begin m_axis_tx_cpl_valid_int_reg <= 1'b0; encoded_tx_data_reg <= {{8{CTRL_IDLE}}, BLOCK_TYPE_CTRL}; + encoded_tx_data_valid_reg <= 1'b0; encoded_tx_hdr_reg <= SYNC_CTRL; + encoded_tx_hdr_valid_reg <= 1'b0; + tx_gbx_start_reg <= '0; output_data_reg <= '0; output_type_reg <= OUTPUT_TYPE_IDLE; diff --git a/src/eth/rtl/taxi_eth_mac_phy_10g.sv b/src/eth/rtl/taxi_eth_mac_phy_10g.sv index 9890136..90062d0 100644 --- a/src/eth/rtl/taxi_eth_mac_phy_10g.sv +++ b/src/eth/rtl/taxi_eth_mac_phy_10g.sv @@ -19,6 +19,8 @@ module taxi_eth_mac_phy_10g # ( parameter DATA_W = 64, parameter HDR_W = (DATA_W/32), + parameter logic TX_GBX_IF_EN = 1'b0, + parameter logic RX_GBX_IF_EN = TX_GBX_IF_EN, parameter logic PADDING_EN = 1'b1, parameter logic DIC_EN = 1'b1, parameter MIN_FRAME_LEN = 64, @@ -64,9 +66,16 @@ module taxi_eth_mac_phy_10g # * SERDES interface */ output wire logic [DATA_W-1:0] serdes_tx_data, + output wire logic serdes_tx_data_valid, output wire logic [HDR_W-1:0] serdes_tx_hdr, + output wire logic serdes_tx_hdr_valid, + input wire logic serdes_tx_gbx_req_start = 1'b0, + input wire logic serdes_tx_gbx_req_stall = 1'b0, + output wire logic serdes_tx_gbx_start, input wire logic [DATA_W-1:0] serdes_rx_data, + input wire logic serdes_rx_data_valid = 1'b1, input wire logic [HDR_W-1:0] serdes_rx_hdr, + input wire logic serdes_rx_hdr_valid = 1'b1, output wire logic serdes_rx_bitslip, output wire logic serdes_rx_reset_req, @@ -220,6 +229,7 @@ taxi_axis_if #(.DATA_W(DATA_W), .USER_EN(1), .USER_W(RX_USER_W)) axis_rx_int(); taxi_eth_mac_phy_10g_rx #( .DATA_W(DATA_W), .HDR_W(HDR_W), + .GBX_IF_EN(RX_GBX_IF_EN), .PTP_TS_EN(PTP_TS_EN), .PTP_TS_FMT_TOD(PTP_TS_FMT_TOD), .PTP_TS_W(PTP_TS_W), @@ -244,7 +254,9 @@ eth_mac_phy_10g_rx_inst ( * SERDES interface */ .serdes_rx_data(serdes_rx_data), + .serdes_rx_data_valid(serdes_rx_data_valid), .serdes_rx_hdr(serdes_rx_hdr), + .serdes_rx_hdr_valid(serdes_rx_hdr_valid), .serdes_rx_bitslip(serdes_rx_bitslip), .serdes_rx_reset_req(serdes_rx_reset_req), @@ -288,6 +300,7 @@ eth_mac_phy_10g_rx_inst ( taxi_eth_mac_phy_10g_tx #( .DATA_W(DATA_W), .HDR_W(HDR_W), + .GBX_IF_EN(TX_GBX_IF_EN), .PADDING_EN(PADDING_EN), .DIC_EN(DIC_EN), .MIN_FRAME_LEN(MIN_FRAME_LEN), @@ -314,7 +327,12 @@ eth_mac_phy_10g_tx_inst ( * SERDES interface */ .serdes_tx_data(serdes_tx_data), + .serdes_tx_data_valid(serdes_tx_data_valid), .serdes_tx_hdr(serdes_tx_hdr), + .serdes_tx_hdr_valid(serdes_tx_hdr_valid), + .serdes_tx_gbx_req_start(serdes_tx_gbx_req_start), + .serdes_tx_gbx_req_stall(serdes_tx_gbx_req_stall), + .serdes_tx_gbx_start(serdes_tx_gbx_start), /* * PTP @@ -635,7 +653,7 @@ if (MAC_CTRL_EN) begin : mac_ctrl .cfg_tx_pfc_quanta(cfg_tx_pfc_quanta), .cfg_tx_pfc_refresh(cfg_tx_pfc_refresh), .cfg_quanta_step(10'((DATA_W*256)/512)), - .cfg_quanta_clk_en(1'b1), + .cfg_quanta_clk_en(!RX_GBX_IF_EN || serdes_tx_data_valid), /* * Status @@ -690,7 +708,7 @@ if (MAC_CTRL_EN) begin : mac_ctrl .cfg_rx_pfc_opcode(cfg_rx_pfc_opcode), .cfg_rx_pfc_en(cfg_rx_pfc_en), .cfg_quanta_step(10'((DATA_W*256)/512)), - .cfg_quanta_clk_en(1'b1), + .cfg_quanta_clk_en(!RX_GBX_IF_EN || serdes_rx_data_valid), /* * Status diff --git a/src/eth/rtl/taxi_eth_mac_phy_10g_fifo.sv b/src/eth/rtl/taxi_eth_mac_phy_10g_fifo.sv index 3096da3..2623150 100644 --- a/src/eth/rtl/taxi_eth_mac_phy_10g_fifo.sv +++ b/src/eth/rtl/taxi_eth_mac_phy_10g_fifo.sv @@ -19,6 +19,8 @@ module taxi_eth_mac_phy_10g_fifo # ( parameter DATA_W = 64, parameter HDR_W = (DATA_W/32), + parameter logic TX_GBX_IF_EN = 1'b0, + parameter logic RX_GBX_IF_EN = TX_GBX_IF_EN, parameter logic PADDING_EN = 1'b1, parameter logic DIC_EN = 1'b1, parameter MIN_FRAME_LEN = 64, @@ -78,9 +80,16 @@ module taxi_eth_mac_phy_10g_fifo # * SERDES interface */ output wire logic [DATA_W-1:0] serdes_tx_data, + output wire logic serdes_tx_data_valid, output wire logic [HDR_W-1:0] serdes_tx_hdr, + output wire logic serdes_tx_hdr_valid, + input wire logic serdes_tx_gbx_req_start = 1'b0, + input wire logic serdes_tx_gbx_req_stall = 1'b0, + output wire logic serdes_tx_gbx_start, input wire logic [DATA_W-1:0] serdes_rx_data, + input wire logic serdes_rx_data_valid = 1'b1, input wire logic [HDR_W-1:0] serdes_rx_hdr, + input wire logic serdes_rx_hdr_valid = 1'b1, output wire logic serdes_rx_bitslip, output wire logic serdes_rx_reset_req, @@ -275,6 +284,8 @@ wire stat_rx_fifo_drop; taxi_eth_mac_phy_10g #( .DATA_W(DATA_W), .HDR_W(HDR_W), + .TX_GBX_IF_EN(TX_GBX_IF_EN), + .RX_GBX_IF_EN(RX_GBX_IF_EN), .PADDING_EN(PADDING_EN), .DIC_EN(DIC_EN), .MIN_FRAME_LEN(MIN_FRAME_LEN), @@ -318,9 +329,16 @@ eth_mac_phy_10g_inst ( * Serdes interface */ .serdes_tx_data(serdes_tx_data), + .serdes_tx_data_valid(serdes_tx_data_valid), .serdes_tx_hdr(serdes_tx_hdr), + .serdes_tx_hdr_valid(serdes_tx_hdr_valid), + .serdes_tx_gbx_req_start(serdes_tx_gbx_req_start), + .serdes_tx_gbx_req_stall(serdes_tx_gbx_req_stall), + .serdes_tx_gbx_start(serdes_tx_gbx_start), .serdes_rx_data(serdes_rx_data), + .serdes_rx_data_valid(serdes_rx_data_valid), .serdes_rx_hdr(serdes_rx_hdr), + .serdes_rx_hdr_valid(serdes_rx_hdr_valid), .serdes_rx_bitslip(serdes_rx_bitslip), .serdes_rx_reset_req(serdes_rx_reset_req), diff --git a/src/eth/rtl/taxi_eth_mac_phy_10g_rx.sv b/src/eth/rtl/taxi_eth_mac_phy_10g_rx.sv index 7d96e2d..954f721 100644 --- a/src/eth/rtl/taxi_eth_mac_phy_10g_rx.sv +++ b/src/eth/rtl/taxi_eth_mac_phy_10g_rx.sv @@ -19,6 +19,7 @@ module taxi_eth_mac_phy_10g_rx # ( parameter DATA_W = 64, parameter HDR_W = (DATA_W/32), + parameter logic GBX_IF_EN = 1'b0, parameter logic PTP_TS_EN = 1'b0, parameter logic PTP_TS_FMT_TOD = 1'b1, parameter PTP_TS_W = PTP_TS_FMT_TOD ? 96 : 64, @@ -43,7 +44,9 @@ module taxi_eth_mac_phy_10g_rx # * SERDES interface */ input wire logic [DATA_W-1:0] serdes_rx_data, + input wire logic serdes_rx_data_valid = 1'b1, input wire logic [HDR_W-1:0] serdes_rx_hdr, + input wire logic serdes_rx_hdr_valid = 1'b1, output wire logic serdes_rx_bitslip, output wire logic serdes_rx_reset_req, @@ -85,11 +88,14 @@ module taxi_eth_mac_phy_10g_rx # ); wire [DATA_W-1:0] encoded_rx_data; +wire encoded_rx_data_valid; wire [HDR_W-1:0] encoded_rx_hdr; +wire encoded_rx_hdr_valid; taxi_eth_phy_10g_rx_if #( .DATA_W(DATA_W), .HDR_W(HDR_W), + .GBX_IF_EN(GBX_IF_EN), .BIT_REVERSE(BIT_REVERSE), .SCRAMBLER_DISABLE(SCRAMBLER_DISABLE), .PRBS31_EN(PRBS31_EN), @@ -106,13 +112,17 @@ eth_phy_10g_rx_if_inst ( * 10GBASE-R encoded interface */ .encoded_rx_data(encoded_rx_data), + .encoded_rx_data_valid(encoded_rx_data_valid), .encoded_rx_hdr(encoded_rx_hdr), + .encoded_rx_hdr_valid(encoded_rx_hdr_valid), /* * SERDES interface */ .serdes_rx_data(serdes_rx_data), + .serdes_rx_data_valid(serdes_rx_data_valid), .serdes_rx_hdr(serdes_rx_hdr), + .serdes_rx_hdr_valid(serdes_rx_hdr_valid), .serdes_rx_bitslip(serdes_rx_bitslip), .serdes_rx_reset_req(serdes_rx_reset_req), @@ -135,6 +145,7 @@ eth_phy_10g_rx_if_inst ( taxi_axis_baser_rx_64 #( .DATA_W(DATA_W), .HDR_W(HDR_W), + .GBX_IF_EN(GBX_IF_EN), .PTP_TS_EN(PTP_TS_EN), .PTP_TS_FMT_TOD(PTP_TS_FMT_TOD), .PTP_TS_W(PTP_TS_W) @@ -147,7 +158,9 @@ axis_baser_rx_inst ( * 10GBASE-R encoded input */ .encoded_rx_data(encoded_rx_data), + .encoded_rx_data_valid(encoded_rx_data_valid), .encoded_rx_hdr(encoded_rx_hdr), + .encoded_rx_hdr_valid(encoded_rx_hdr_valid), /* * Receive interface (AXI stream) diff --git a/src/eth/rtl/taxi_eth_mac_phy_10g_tx.sv b/src/eth/rtl/taxi_eth_mac_phy_10g_tx.sv index c205f72..9e77a47 100644 --- a/src/eth/rtl/taxi_eth_mac_phy_10g_tx.sv +++ b/src/eth/rtl/taxi_eth_mac_phy_10g_tx.sv @@ -19,6 +19,7 @@ module taxi_eth_mac_phy_10g_tx # ( parameter DATA_W = 64, parameter HDR_W = (DATA_W/32), + parameter logic GBX_IF_EN = 1'b0, parameter logic PADDING_EN = 1'b1, parameter logic DIC_EN = 1'b1, parameter MIN_FRAME_LEN = 64, @@ -45,7 +46,12 @@ module taxi_eth_mac_phy_10g_tx # * SERDES interface */ output wire logic [DATA_W-1:0] serdes_tx_data, + output wire logic serdes_tx_data_valid, output wire logic [HDR_W-1:0] serdes_tx_hdr, + output wire logic serdes_tx_hdr_valid, + input wire logic serdes_tx_gbx_req_start = 1'b0, + input wire logic serdes_tx_gbx_req_stall = 1'b0, + output wire logic serdes_tx_gbx_start, /* * PTP @@ -78,11 +84,19 @@ module taxi_eth_mac_phy_10g_tx # ); wire [DATA_W-1:0] encoded_tx_data; +wire encoded_tx_data_valid; wire [HDR_W-1:0] encoded_tx_hdr; +wire encoded_tx_hdr_valid; + +wire tx_gbx_req_start; +wire tx_gbx_req_stall; +wire tx_gbx_start; taxi_axis_baser_tx_64 #( .DATA_W(DATA_W), .HDR_W(HDR_W), + .GBX_IF_EN(GBX_IF_EN), + .GBX_CNT(1), .PADDING_EN(PADDING_EN), .DIC_EN(DIC_EN), .MIN_FRAME_LEN(MIN_FRAME_LEN), @@ -105,7 +119,12 @@ axis_baser_tx_inst ( * 10GBASE-R encoded interface */ .encoded_tx_data(encoded_tx_data), + .encoded_tx_data_valid(encoded_tx_data_valid), .encoded_tx_hdr(encoded_tx_hdr), + .encoded_tx_hdr_valid(encoded_tx_hdr_valid), + .tx_gbx_req_start(tx_gbx_req_start), + .tx_gbx_req_stall(tx_gbx_req_stall), + .tx_gbx_start(tx_gbx_start), /* * PTP @@ -139,6 +158,7 @@ axis_baser_tx_inst ( taxi_eth_phy_10g_tx_if #( .DATA_W(DATA_W), .HDR_W(HDR_W), + .GBX_IF_EN(GBX_IF_EN), .BIT_REVERSE(BIT_REVERSE), .SCRAMBLER_DISABLE(SCRAMBLER_DISABLE), .PRBS31_EN(PRBS31_EN), @@ -152,13 +172,23 @@ eth_phy_10g_tx_if_inst ( * 10GBASE-R encoded interface */ .encoded_tx_data(encoded_tx_data), + .encoded_tx_data_valid(encoded_tx_data_valid), .encoded_tx_hdr(encoded_tx_hdr), + .encoded_tx_hdr_valid(encoded_tx_hdr_valid), + .tx_gbx_req_start(tx_gbx_req_start), + .tx_gbx_req_stall(tx_gbx_req_stall), + .tx_gbx_start(tx_gbx_start), /* * SERDES interface */ .serdes_tx_data(serdes_tx_data), + .serdes_tx_data_valid(serdes_tx_data_valid), .serdes_tx_hdr(serdes_tx_hdr), + .serdes_tx_hdr_valid(serdes_tx_hdr_valid), + .serdes_tx_gbx_req_start(serdes_tx_gbx_req_start), + .serdes_tx_gbx_req_stall(serdes_tx_gbx_req_stall), + .serdes_tx_gbx_start(serdes_tx_gbx_start), /* * Configuration diff --git a/src/eth/rtl/taxi_eth_phy_10g.sv b/src/eth/rtl/taxi_eth_phy_10g.sv index 270094b..da9b67b 100644 --- a/src/eth/rtl/taxi_eth_phy_10g.sv +++ b/src/eth/rtl/taxi_eth_phy_10g.sv @@ -20,6 +20,8 @@ module taxi_eth_phy_10g # parameter DATA_W = 64, parameter CTRL_W = (DATA_W/8), parameter HDR_W = 2, + parameter logic TX_GBX_IF_EN = 1'b0, + parameter logic RX_GBX_IF_EN = TX_GBX_IF_EN, parameter logic BIT_REVERSE = 1'b0, parameter logic SCRAMBLER_DISABLE = 1'b0, parameter logic PRBS31_EN = 1'b0, @@ -40,16 +42,28 @@ module taxi_eth_phy_10g # */ input wire logic [DATA_W-1:0] xgmii_txd, input wire logic [CTRL_W-1:0] xgmii_txc, + input wire logic xgmii_tx_valid = 1'b1, output wire logic [DATA_W-1:0] xgmii_rxd, output wire logic [CTRL_W-1:0] xgmii_rxc, + output wire logic xgmii_rx_valid = 1'b1, + output wire logic tx_gbx_req_start, + output wire logic tx_gbx_req_stall, + input wire logic tx_gbx_start = 1'b0, /* * SERDES interface */ output wire logic [DATA_W-1:0] serdes_tx_data, + output wire logic serdes_tx_data_valid, output wire logic [HDR_W-1:0] serdes_tx_hdr, + output wire logic serdes_tx_hdr_valid, + input wire logic serdes_tx_gbx_req_start = 1'b0, + input wire logic serdes_tx_gbx_req_stall = 1'b0, + output wire logic serdes_tx_gbx_start, input wire logic [DATA_W-1:0] serdes_rx_data, + input wire logic serdes_rx_data_valid = 1'b1, input wire logic [HDR_W-1:0] serdes_rx_hdr, + input wire logic serdes_rx_hdr_valid = 1'b1, output wire logic serdes_rx_bitslip, output wire logic serdes_rx_reset_req, @@ -75,6 +89,7 @@ taxi_eth_phy_10g_rx #( .DATA_W(DATA_W), .CTRL_W(CTRL_W), .HDR_W(HDR_W), + .GBX_IF_EN(RX_GBX_IF_EN), .BIT_REVERSE(BIT_REVERSE), .SCRAMBLER_DISABLE(SCRAMBLER_DISABLE), .PRBS31_EN(PRBS31_EN), @@ -92,12 +107,15 @@ eth_phy_10g_rx_inst ( */ .xgmii_rxd(xgmii_rxd), .xgmii_rxc(xgmii_rxc), + .xgmii_rx_valid(xgmii_rx_valid), /* * SERDES interface */ .serdes_rx_data(serdes_rx_data), + .serdes_rx_data_valid(serdes_rx_data_valid), .serdes_rx_hdr(serdes_rx_hdr), + .serdes_rx_hdr_valid(serdes_rx_hdr_valid), .serdes_rx_bitslip(serdes_rx_bitslip), .serdes_rx_reset_req(serdes_rx_reset_req), @@ -121,6 +139,7 @@ taxi_eth_phy_10g_tx #( .DATA_W(DATA_W), .CTRL_W(CTRL_W), .HDR_W(HDR_W), + .GBX_IF_EN(TX_GBX_IF_EN), .BIT_REVERSE(BIT_REVERSE), .SCRAMBLER_DISABLE(SCRAMBLER_DISABLE), .PRBS31_EN(PRBS31_EN), @@ -135,12 +154,21 @@ eth_phy_10g_tx_inst ( */ .xgmii_txd(xgmii_txd), .xgmii_txc(xgmii_txc), + .xgmii_tx_valid(xgmii_tx_valid), + .tx_gbx_req_start(tx_gbx_req_start), + .tx_gbx_req_stall(tx_gbx_req_stall), + .tx_gbx_start(tx_gbx_start), /* * SERDES interface */ .serdes_tx_data(serdes_tx_data), + .serdes_tx_data_valid(serdes_tx_data_valid), .serdes_tx_hdr(serdes_tx_hdr), + .serdes_tx_hdr_valid(serdes_tx_hdr_valid), + .serdes_tx_gbx_req_start(serdes_tx_gbx_req_start), + .serdes_tx_gbx_req_stall(serdes_tx_gbx_req_stall), + .serdes_tx_gbx_start(serdes_tx_gbx_start), /* * Status diff --git a/src/eth/rtl/taxi_eth_phy_10g_rx.sv b/src/eth/rtl/taxi_eth_phy_10g_rx.sv index ed38a3e..5146c02 100644 --- a/src/eth/rtl/taxi_eth_phy_10g_rx.sv +++ b/src/eth/rtl/taxi_eth_phy_10g_rx.sv @@ -20,6 +20,7 @@ module taxi_eth_phy_10g_rx # parameter DATA_W = 64, parameter CTRL_W = (DATA_W/8), parameter HDR_W = 2, + parameter logic GBX_IF_EN = 1'b0, parameter logic BIT_REVERSE = 1'b0, parameter logic SCRAMBLER_DISABLE = 1'b0, parameter logic PRBS31_EN = 1'b0, @@ -37,12 +38,15 @@ module taxi_eth_phy_10g_rx # */ output wire logic [DATA_W-1:0] xgmii_rxd, output wire logic [CTRL_W-1:0] xgmii_rxc, + output wire logic xgmii_rx_valid, /* * SERDES interface */ input wire logic [DATA_W-1:0] serdes_rx_data, + input wire logic serdes_rx_data_valid = 1'b1, input wire logic [HDR_W-1:0] serdes_rx_hdr, + input wire logic serdes_rx_hdr_valid = 1'b1, output wire logic serdes_rx_bitslip, output wire logic serdes_rx_reset_req, @@ -73,11 +77,14 @@ if (HDR_W != 2) $fatal(0, "Error: HDR_W must be 2"); wire [DATA_W-1:0] encoded_rx_data; -wire [HDR_W-1:0] encoded_rx_hdr; +wire encoded_rx_data_valid; +wire [HDR_W-1:0] encoded_rx_hdr; +wire encoded_rx_hdr_valid; taxi_eth_phy_10g_rx_if #( .DATA_W(DATA_W), .HDR_W(HDR_W), + .GBX_IF_EN(GBX_IF_EN), .BIT_REVERSE(BIT_REVERSE), .SCRAMBLER_DISABLE(SCRAMBLER_DISABLE), .PRBS31_EN(PRBS31_EN), @@ -94,13 +101,17 @@ eth_phy_10g_rx_if_inst ( * 10GBASE-R encoded interface */ .encoded_rx_data(encoded_rx_data), + .encoded_rx_data_valid(encoded_rx_data_valid), .encoded_rx_hdr(encoded_rx_hdr), + .encoded_rx_hdr_valid(encoded_rx_hdr_valid), /* * SERDES interface */ .serdes_rx_data(serdes_rx_data), + .serdes_rx_data_valid(serdes_rx_data_valid), .serdes_rx_hdr(serdes_rx_hdr), + .serdes_rx_hdr_valid(serdes_rx_hdr_valid), .serdes_rx_bitslip(serdes_rx_bitslip), .serdes_rx_reset_req(serdes_rx_reset_req), @@ -123,7 +134,8 @@ eth_phy_10g_rx_if_inst ( taxi_xgmii_baser_dec_64 #( .DATA_W(DATA_W), .CTRL_W(CTRL_W), - .HDR_W(HDR_W) + .HDR_W(HDR_W), + .GBX_IF_EN(GBX_IF_EN) ) xgmii_baser_dec_inst ( .clk(clk), @@ -133,13 +145,16 @@ xgmii_baser_dec_inst ( * 10GBASE-R encoded input */ .encoded_rx_data(encoded_rx_data), + .encoded_rx_data_valid(encoded_rx_data_valid), .encoded_rx_hdr(encoded_rx_hdr), + .encoded_rx_hdr_valid(encoded_rx_hdr_valid), /* * XGMII interface */ .xgmii_rxd(xgmii_rxd), .xgmii_rxc(xgmii_rxc), + .xgmii_rx_valid(xgmii_rx_valid), /* * Status diff --git a/src/eth/rtl/taxi_eth_phy_10g_rx_ber_mon.sv b/src/eth/rtl/taxi_eth_phy_10g_rx_ber_mon.sv index a4f5806..9641cc6 100644 --- a/src/eth/rtl/taxi_eth_phy_10g_rx_ber_mon.sv +++ b/src/eth/rtl/taxi_eth_phy_10g_rx_ber_mon.sv @@ -18,6 +18,7 @@ Authors: module taxi_eth_phy_10g_rx_ber_mon # ( parameter HDR_W = 2, + parameter logic GBX_IF_EN = 1'b0, parameter COUNT_125US = 125000/6.4 ) ( @@ -28,6 +29,7 @@ module taxi_eth_phy_10g_rx_ber_mon # * SERDES interface */ input wire logic [HDR_W-1:0] serdes_rx_hdr, + input wire logic serdes_rx_hdr_valid, /* * Status @@ -63,7 +65,9 @@ always_comb begin rx_high_ber_next = rx_high_ber_reg; - if (serdes_rx_hdr == SYNC_CTRL || serdes_rx_hdr == SYNC_DATA) begin + if (GBX_IF_EN && !serdes_rx_hdr_valid) begin + // wait for header + end else if (serdes_rx_hdr == SYNC_CTRL || serdes_rx_hdr == SYNC_DATA) begin // valid header if (ber_count_reg != 4'd15) begin if (time_count_reg == 0) begin diff --git a/src/eth/rtl/taxi_eth_phy_10g_rx_frame_sync.sv b/src/eth/rtl/taxi_eth_phy_10g_rx_frame_sync.sv index 3711b60..df802d1 100644 --- a/src/eth/rtl/taxi_eth_phy_10g_rx_frame_sync.sv +++ b/src/eth/rtl/taxi_eth_phy_10g_rx_frame_sync.sv @@ -18,6 +18,7 @@ Authors: module taxi_eth_phy_10g_rx_frame_sync # ( parameter HDR_W = 2, + parameter logic GBX_IF_EN = 1'b0, parameter BITSLIP_HIGH_CYCLES = 1, parameter BITSLIP_LOW_CYCLES = 7 ) @@ -29,6 +30,7 @@ module taxi_eth_phy_10g_rx_frame_sync # * SERDES interface */ input wire logic [HDR_W-1:0] serdes_rx_hdr, + input wire logic serdes_rx_hdr_valid, output wire logic serdes_rx_bitslip, /* @@ -73,6 +75,8 @@ always_comb begin end else if (serdes_rx_bitslip_reg) begin serdes_rx_bitslip_next = 1'b0; bitslip_count_next = BITSLIP_COUNT_W'(BITSLIP_LOW_CYCLES); + end else if (GBX_IF_EN && !serdes_rx_hdr_valid) begin + // wait for header end else if (serdes_rx_hdr == SYNC_CTRL || serdes_rx_hdr == SYNC_DATA) begin // valid header sh_count_next = sh_count_reg + 1; diff --git a/src/eth/rtl/taxi_eth_phy_10g_rx_if.sv b/src/eth/rtl/taxi_eth_phy_10g_rx_if.sv index 092f15a..009c67b 100644 --- a/src/eth/rtl/taxi_eth_phy_10g_rx_if.sv +++ b/src/eth/rtl/taxi_eth_phy_10g_rx_if.sv @@ -19,6 +19,7 @@ module taxi_eth_phy_10g_rx_if # ( parameter DATA_W = 64, parameter HDR_W = 2, + parameter logic GBX_IF_EN = 1'b0, parameter logic BIT_REVERSE = 1'b0, parameter logic SCRAMBLER_DISABLE = 1'b0, parameter logic PRBS31_EN = 1'b0, @@ -35,13 +36,17 @@ module taxi_eth_phy_10g_rx_if # * 10GBASE-R encoded interface */ output wire logic [DATA_W-1:0] encoded_rx_data, + output wire logic encoded_rx_data_valid, output wire logic [HDR_W-1:0] encoded_rx_hdr, + output wire logic encoded_rx_hdr_valid, /* * SERDES interface */ input wire logic [DATA_W-1:0] serdes_rx_data, + input wire logic serdes_rx_data_valid, input wire logic [HDR_W-1:0] serdes_rx_hdr, + input wire logic serdes_rx_hdr_valid, output wire logic serdes_rx_bitslip, output wire logic serdes_rx_reset_req, @@ -69,7 +74,9 @@ if (HDR_W != 2) $fatal(0, "Error: HDR_W must be 2"); wire [DATA_W-1:0] serdes_rx_data_rev, serdes_rx_data_int; -wire [HDR_W-1:0] serdes_rx_hdr_rev, serdes_rx_hdr_int; +wire serdes_rx_data_valid_int; +wire [HDR_W-1:0] serdes_rx_hdr_rev, serdes_rx_hdr_int; +wire serdes_rx_hdr_valid_int; if (BIT_REVERSE) begin for (genvar n = 0; n < DATA_W; n = n + 1) begin @@ -88,36 +95,50 @@ if (SERDES_PIPELINE > 0) begin (* srl_style = "register" *) logic [DATA_W-1:0] serdes_rx_data_pipe_reg[SERDES_PIPELINE-1:0]; (* srl_style = "register" *) - logic [HDR_W-1:0] serdes_rx_hdr_pipe_reg[SERDES_PIPELINE-1:0]; + logic serdes_rx_data_valid_pipe_reg[SERDES_PIPELINE-1:0]; + (* srl_style = "register" *) + logic [HDR_W-1:0] serdes_rx_hdr_pipe_reg[SERDES_PIPELINE-1:0]; + (* srl_style = "register" *) + logic serdes_rx_hdr_valid_pipe_reg[SERDES_PIPELINE-1:0]; for (genvar n = 0; n < SERDES_PIPELINE; n = n + 1) begin initial begin serdes_rx_data_pipe_reg[n] = '0; + serdes_rx_data_valid_pipe_reg[n] = '0; serdes_rx_hdr_pipe_reg[n] = '0; + serdes_rx_hdr_valid_pipe_reg[n] = '0; end always @(posedge clk) begin serdes_rx_data_pipe_reg[n] <= n == 0 ? serdes_rx_data_rev : serdes_rx_data_pipe_reg[n-1]; + serdes_rx_data_valid_pipe_reg[n] <= n == 0 ? serdes_rx_data_valid : serdes_rx_data_valid_pipe_reg[n-1]; serdes_rx_hdr_pipe_reg[n] <= n == 0 ? serdes_rx_hdr_rev : serdes_rx_hdr_pipe_reg[n-1]; + serdes_rx_hdr_valid_pipe_reg[n] <= n == 0 ? serdes_rx_hdr_valid : serdes_rx_hdr_valid_pipe_reg[n-1]; end end assign serdes_rx_data_int = serdes_rx_data_pipe_reg[SERDES_PIPELINE-1]; + assign serdes_rx_data_valid_int = serdes_rx_data_valid_pipe_reg[SERDES_PIPELINE-1]; assign serdes_rx_hdr_int = serdes_rx_hdr_pipe_reg[SERDES_PIPELINE-1]; + assign serdes_rx_hdr_valid_int = serdes_rx_hdr_valid_pipe_reg[SERDES_PIPELINE-1]; end else begin assign serdes_rx_data_int = serdes_rx_data_rev; + assign serdes_rx_data_valid_int = serdes_rx_data_valid; assign serdes_rx_hdr_int = serdes_rx_hdr_rev; + assign serdes_rx_hdr_valid_int = serdes_rx_hdr_valid; end wire [DATA_W-1:0] descrambled_rx_data; logic [DATA_W-1:0] encoded_rx_data_reg = '0; +logic encoded_rx_data_valid_reg = 1'b0; logic [HDR_W-1:0] encoded_rx_hdr_reg = '0; +logic encoded_rx_hdr_valid_reg = 1'b0; -logic [57:0] scrambler_state_reg = {58{1'b1}}; +logic [57:0] scrambler_state_reg = '1; wire [57:0] scrambler_state; -logic [30:0] prbs31_state_reg = 31'h7fffffff; +logic [30:0] prbs31_state_reg = '1; wire [30:0] prbs31_state; wire [DATA_W+HDR_W-1:0] prbs31_data; logic [DATA_W+HDR_W-1:0] prbs31_data_reg = '0; @@ -143,6 +164,12 @@ descrambler_inst ( .state_out(scrambler_state) ); +always_ff @(posedge clk) begin + if (!GBX_IF_EN || serdes_rx_data_valid_int) begin + scrambler_state_reg <= scrambler_state; + end +end + taxi_lfsr #( .LFSR_W(31), .LFSR_POLY(31'h10000001), @@ -171,13 +198,13 @@ always_comb begin end always_ff @(posedge clk) begin - scrambler_state_reg <= scrambler_state; - encoded_rx_data_reg <= SCRAMBLER_DISABLE ? serdes_rx_data_int : descrambled_rx_data; + encoded_rx_data_valid_reg <= serdes_rx_data_valid_int; encoded_rx_hdr_reg <= serdes_rx_hdr_int; + encoded_rx_hdr_valid_reg <= serdes_rx_hdr_valid_int; if (PRBS31_EN) begin - if (cfg_rx_prbs31_enable) begin + if (cfg_rx_prbs31_enable && (!GBX_IF_EN || serdes_rx_data_valid_int)) begin prbs31_state_reg <= prbs31_state; prbs31_data_reg <= prbs31_data; end else begin @@ -193,7 +220,9 @@ always_ff @(posedge clk) begin end assign encoded_rx_data = encoded_rx_data_reg; +assign encoded_rx_data_valid = GBX_IF_EN ? encoded_rx_data_valid_reg : 1'b1; assign encoded_rx_hdr = encoded_rx_hdr_reg; +assign encoded_rx_hdr_valid = GBX_IF_EN ? encoded_rx_hdr_valid_reg : 1'b1; assign rx_error_count = rx_error_count_reg; @@ -204,6 +233,7 @@ assign serdes_rx_reset_req = serdes_rx_reset_req_int && !(PRBS31_EN && cfg_rx_pr taxi_eth_phy_10g_rx_frame_sync #( .HDR_W(HDR_W), + .GBX_IF_EN(GBX_IF_EN), .BITSLIP_HIGH_CYCLES(BITSLIP_HIGH_CYCLES), .BITSLIP_LOW_CYCLES(BITSLIP_LOW_CYCLES) ) @@ -211,6 +241,7 @@ eth_phy_10g_rx_frame_sync_inst ( .clk(clk), .rst(rst), .serdes_rx_hdr(serdes_rx_hdr_int), + .serdes_rx_hdr_valid(serdes_rx_hdr_valid_int), .serdes_rx_bitslip(serdes_rx_bitslip_int), .rx_block_lock(rx_block_lock) ); @@ -223,17 +254,20 @@ eth_phy_10g_rx_ber_mon_inst ( .clk(clk), .rst(rst), .serdes_rx_hdr(serdes_rx_hdr_int), + .serdes_rx_hdr_valid(serdes_rx_hdr_valid_int), .rx_high_ber(rx_high_ber) ); taxi_eth_phy_10g_rx_watchdog #( .HDR_W(HDR_W), + .GBX_IF_EN(GBX_IF_EN), .COUNT_125US(COUNT_125US) ) eth_phy_10g_rx_watchdog_inst ( .clk(clk), .rst(rst), .serdes_rx_hdr(serdes_rx_hdr_int), + .serdes_rx_hdr_valid(serdes_rx_hdr_valid_int), .serdes_rx_reset_req(serdes_rx_reset_req_int), .rx_bad_block(rx_bad_block), .rx_sequence_error(rx_sequence_error), diff --git a/src/eth/rtl/taxi_eth_phy_10g_rx_watchdog.sv b/src/eth/rtl/taxi_eth_phy_10g_rx_watchdog.sv index 130389a..dc3ede8 100644 --- a/src/eth/rtl/taxi_eth_phy_10g_rx_watchdog.sv +++ b/src/eth/rtl/taxi_eth_phy_10g_rx_watchdog.sv @@ -18,6 +18,7 @@ Authors: module taxi_eth_phy_10g_rx_watchdog # ( parameter HDR_W = 2, + parameter logic GBX_IF_EN = 1'b0, parameter COUNT_125US = 125000/6.4 ) ( @@ -28,6 +29,7 @@ module taxi_eth_phy_10g_rx_watchdog # * SERDES interface */ input wire logic [HDR_W-1:0] serdes_rx_hdr, + input wire logic serdes_rx_hdr_valid, output wire logic serdes_rx_reset_req, /* @@ -82,7 +84,7 @@ always_comb begin rx_status_next = rx_status_reg; if (rx_block_lock) begin - if (serdes_rx_hdr == SYNC_CTRL) begin + if (serdes_rx_hdr == SYNC_CTRL && (!GBX_IF_EN || serdes_rx_hdr_valid)) begin saw_ctrl_sh_next = 1'b1; end if ((rx_bad_block || rx_sequence_error) && !(&block_error_count_reg)) begin diff --git a/src/eth/rtl/taxi_eth_phy_10g_tx.sv b/src/eth/rtl/taxi_eth_phy_10g_tx.sv index e076556..be6d05c 100644 --- a/src/eth/rtl/taxi_eth_phy_10g_tx.sv +++ b/src/eth/rtl/taxi_eth_phy_10g_tx.sv @@ -20,6 +20,7 @@ module taxi_eth_phy_10g_tx # parameter DATA_W = 64, parameter CTRL_W = (DATA_W/8), parameter HDR_W = 2, + parameter logic GBX_IF_EN = 1'b0, parameter logic BIT_REVERSE = 1'b0, parameter logic SCRAMBLER_DISABLE = 1'b0, parameter logic PRBS31_EN = 1'b0, @@ -34,12 +35,21 @@ module taxi_eth_phy_10g_tx # */ input wire logic [DATA_W-1:0] xgmii_txd, input wire logic [CTRL_W-1:0] xgmii_txc, + input wire logic xgmii_tx_valid = 1'b1, + output wire logic tx_gbx_req_start, + output wire logic tx_gbx_req_stall, + input wire logic tx_gbx_start = 1'b0, /* * SERDES interface */ output wire logic [DATA_W-1:0] serdes_tx_data, + output wire logic serdes_tx_data_valid, output wire logic [HDR_W-1:0] serdes_tx_hdr, + output wire logic serdes_tx_hdr_valid, + input wire logic serdes_tx_gbx_req_start = 1'b0, + input wire logic serdes_tx_gbx_req_stall = 1'b0, + output wire logic serdes_tx_gbx_start, /* * Status @@ -63,12 +73,18 @@ if (HDR_W != 2) $fatal(0, "Error: HDR_W must be 2"); wire [DATA_W-1:0] encoded_tx_data; +wire encoded_tx_data_valid; wire [HDR_W-1:0] encoded_tx_hdr; +wire encoded_tx_hdr_valid; + +wire tx_gbx_start_int; taxi_xgmii_baser_enc_64 #( .DATA_W(DATA_W), .CTRL_W(CTRL_W), - .HDR_W(HDR_W) + .HDR_W(HDR_W), + .GBX_IF_EN(GBX_IF_EN), + .GBX_CNT(1) ) xgmii_baser_enc_inst ( .clk(clk), @@ -79,12 +95,17 @@ xgmii_baser_enc_inst ( */ .xgmii_txd(xgmii_txd), .xgmii_txc(xgmii_txc), + .xgmii_tx_valid(xgmii_tx_valid), + .tx_gbx_start_in(tx_gbx_start), /* * 10GBASE-R encoded interface */ .encoded_tx_data(encoded_tx_data), + .encoded_tx_data_valid(encoded_tx_data_valid), .encoded_tx_hdr(encoded_tx_hdr), + .encoded_tx_hdr_valid(encoded_tx_hdr_valid), + .tx_gbx_start_out(tx_gbx_start_int), /* * Status @@ -95,6 +116,7 @@ xgmii_baser_enc_inst ( taxi_eth_phy_10g_tx_if #( .DATA_W(DATA_W), .HDR_W(HDR_W), + .GBX_IF_EN(GBX_IF_EN), .BIT_REVERSE(BIT_REVERSE), .SCRAMBLER_DISABLE(SCRAMBLER_DISABLE), .PRBS31_EN(PRBS31_EN), @@ -108,13 +130,23 @@ eth_phy_10g_tx_if_inst ( * 10GBASE-R encoded interface */ .encoded_tx_data(encoded_tx_data), + .encoded_tx_data_valid(encoded_tx_data_valid), .encoded_tx_hdr(encoded_tx_hdr), + .encoded_tx_hdr_valid(encoded_tx_hdr_valid), + .tx_gbx_req_start(tx_gbx_req_start), + .tx_gbx_req_stall(tx_gbx_req_stall), + .tx_gbx_start(tx_gbx_start_int), /* * SERDES interface */ .serdes_tx_data(serdes_tx_data), + .serdes_tx_data_valid(serdes_tx_data_valid), .serdes_tx_hdr(serdes_tx_hdr), + .serdes_tx_hdr_valid(serdes_tx_hdr_valid), + .serdes_tx_gbx_req_start(serdes_tx_gbx_req_start), + .serdes_tx_gbx_req_stall(serdes_tx_gbx_req_stall), + .serdes_tx_gbx_start(serdes_tx_gbx_start), /* * Configuration diff --git a/src/eth/rtl/taxi_eth_phy_10g_tx_if.sv b/src/eth/rtl/taxi_eth_phy_10g_tx_if.sv index f149537..4fb1290 100644 --- a/src/eth/rtl/taxi_eth_phy_10g_tx_if.sv +++ b/src/eth/rtl/taxi_eth_phy_10g_tx_if.sv @@ -19,6 +19,7 @@ module taxi_eth_phy_10g_tx_if # ( parameter DATA_W = 64, parameter HDR_W = 2, + parameter logic GBX_IF_EN = 1'b0, parameter logic BIT_REVERSE = 1'b0, parameter logic SCRAMBLER_DISABLE = 1'b0, parameter logic PRBS31_EN = 1'b0, @@ -32,13 +33,22 @@ module taxi_eth_phy_10g_tx_if # * 10GBASE-R encoded interface */ input wire logic [DATA_W-1:0] encoded_tx_data, + input wire logic encoded_tx_data_valid = 1'b1, input wire logic [HDR_W-1:0] encoded_tx_hdr, - + input wire logic encoded_tx_hdr_valid = 1'b1, + output wire logic tx_gbx_req_start, + output wire logic tx_gbx_req_stall, + input wire logic tx_gbx_start = 1'b0, /* * SERDES interface */ output wire logic [DATA_W-1:0] serdes_tx_data, + output wire logic serdes_tx_data_valid, output wire logic [HDR_W-1:0] serdes_tx_hdr, + output wire logic serdes_tx_hdr_valid, + input wire logic serdes_tx_gbx_req_start = 1'b0, + input wire logic serdes_tx_gbx_req_stall = 1'b0, + output wire logic serdes_tx_gbx_start, /* * Configuration @@ -53,19 +63,25 @@ if (DATA_W != 64) if (HDR_W != 2) $fatal(0, "Error: HDR_W must be 2"); +assign tx_gbx_req_start = GBX_IF_EN ? serdes_tx_gbx_req_start : '0; +assign tx_gbx_req_stall = GBX_IF_EN ? serdes_tx_gbx_req_stall : '0; + logic [57:0] scrambler_state_reg = '1; wire [57:0] scrambler_state; wire [DATA_W-1:0] scrambled_data; -logic [30:0] prbs31_state_reg = 31'h7fffffff; +logic [30:0] prbs31_state_reg = '1; wire [30:0] prbs31_state; wire [DATA_W+HDR_W-1:0] prbs31_data; logic [DATA_W-1:0] serdes_tx_data_reg = '0; +logic serdes_tx_data_valid_reg = 1'b0; logic [HDR_W-1:0] serdes_tx_hdr_reg = '0; +logic serdes_tx_hdr_valid_reg = 1'b0; +logic serdes_tx_gbx_start_reg = 1'b0; wire [DATA_W-1:0] serdes_tx_data_int; -wire [HDR_W-1:0] serdes_tx_hdr_int; +wire [HDR_W-1:0] serdes_tx_hdr_int; if (BIT_REVERSE) begin for (genvar n = 0; n < DATA_W; n = n + 1) begin @@ -84,25 +100,43 @@ if (SERDES_PIPELINE > 0) begin (* srl_style = "register" *) reg [DATA_W-1:0] serdes_tx_data_pipe_reg[SERDES_PIPELINE-1:0]; (* srl_style = "register" *) - reg [HDR_W-1:0] serdes_tx_hdr_pipe_reg[SERDES_PIPELINE-1:0]; + reg serdes_tx_data_valid_pipe_reg[SERDES_PIPELINE-1:0]; + (* srl_style = "register" *) + reg [HDR_W-1:0] serdes_tx_hdr_pipe_reg[SERDES_PIPELINE-1:0]; + (* srl_style = "register" *) + reg serdes_tx_hdr_valid_pipe_reg[SERDES_PIPELINE-1:0]; + (* srl_style = "register" *) + reg serdes_tx_gbx_start_pipe_reg[SERDES_PIPELINE-1:0]; for (genvar n = 0; n < SERDES_PIPELINE; n = n + 1) begin initial begin serdes_tx_data_pipe_reg[n] = '0; + serdes_tx_data_valid_pipe_reg[n] = '0; serdes_tx_hdr_pipe_reg[n] = '0; + serdes_tx_hdr_valid_pipe_reg[n] = '0; + serdes_tx_gbx_start_pipe_reg[n] = '0; end always @(posedge clk) begin serdes_tx_data_pipe_reg[n] <= n == 0 ? serdes_tx_data_int : serdes_tx_data_pipe_reg[n-1]; + serdes_tx_data_valid_pipe_reg[n] <= n == 0 ? serdes_tx_data_valid_reg : serdes_tx_data_valid_pipe_reg[n-1]; serdes_tx_hdr_pipe_reg[n] <= n == 0 ? serdes_tx_hdr_int : serdes_tx_hdr_pipe_reg[n-1]; + serdes_tx_hdr_valid_pipe_reg[n] <= n == 0 ? serdes_tx_hdr_valid_reg : serdes_tx_hdr_valid_pipe_reg[n-1]; + serdes_tx_gbx_start_pipe_reg[n] <= n == 0 ? serdes_tx_gbx_start_reg : serdes_tx_gbx_start_pipe_reg[n-1]; end end assign serdes_tx_data = serdes_tx_data_pipe_reg[SERDES_PIPELINE-1]; + assign serdes_tx_data_valid = GBX_IF_EN ? serdes_tx_data_valid_pipe_reg[SERDES_PIPELINE-1] : 1'b1; assign serdes_tx_hdr = serdes_tx_hdr_pipe_reg[SERDES_PIPELINE-1]; + assign serdes_tx_hdr_valid = GBX_IF_EN ? serdes_tx_hdr_valid_pipe_reg[SERDES_PIPELINE-1] : 1'b1; + assign serdes_tx_gbx_start = GBX_IF_EN ? serdes_tx_gbx_start_pipe_reg[SERDES_PIPELINE-1] : 1'b0; end else begin assign serdes_tx_data = serdes_tx_data_int; + assign serdes_tx_data_valid = GBX_IF_EN ? serdes_tx_data_valid_reg : 1'b1; assign serdes_tx_hdr = serdes_tx_hdr_int; + assign serdes_tx_hdr_valid = GBX_IF_EN ? serdes_tx_hdr_valid_reg : 1'b1; + assign serdes_tx_gbx_start = GBX_IF_EN ? serdes_tx_gbx_start_reg : 1'b0; end taxi_lfsr #( @@ -120,6 +154,12 @@ scrambler_inst ( .state_out(scrambler_state) ); +always_ff @(posedge clk) begin + if (!GBX_IF_EN || encoded_tx_data_valid) begin + scrambler_state_reg <= scrambler_state; + end +end + taxi_lfsr #( .LFSR_W(31), .LFSR_POLY(31'h10000001), @@ -136,10 +176,10 @@ prbs31_gen_inst ( ); always_ff @(posedge clk) begin - scrambler_state_reg <= scrambler_state; - if (PRBS31_EN && cfg_tx_prbs31_enable) begin - prbs31_state_reg <= prbs31_state; + if (!GBX_IF_EN || encoded_tx_data_valid) begin + prbs31_state_reg <= prbs31_state; + end serdes_tx_data_reg <= ~prbs31_data[DATA_W+HDR_W-1:HDR_W]; serdes_tx_hdr_reg <= ~prbs31_data[HDR_W-1:0]; @@ -147,6 +187,10 @@ always_ff @(posedge clk) begin serdes_tx_data_reg <= SCRAMBLER_DISABLE ? encoded_tx_data : scrambled_data; serdes_tx_hdr_reg <= encoded_tx_hdr; end + + serdes_tx_data_valid_reg <= encoded_tx_data_valid; + serdes_tx_hdr_valid_reg <= encoded_tx_hdr_valid; + serdes_tx_gbx_start_reg <= tx_gbx_start; end endmodule diff --git a/src/eth/rtl/taxi_xgmii_baser_dec_64.sv b/src/eth/rtl/taxi_xgmii_baser_dec_64.sv index d7f78f7..9d7bd04 100644 --- a/src/eth/rtl/taxi_xgmii_baser_dec_64.sv +++ b/src/eth/rtl/taxi_xgmii_baser_dec_64.sv @@ -19,7 +19,8 @@ module taxi_xgmii_baser_dec_64 # ( parameter DATA_W = 64, parameter CTRL_W = (DATA_W/8), - parameter HDR_W = 2 + parameter HDR_W = 2, + parameter logic GBX_IF_EN = 1'b0 ) ( input wire logic clk, @@ -29,13 +30,16 @@ module taxi_xgmii_baser_dec_64 # * 10GBASE-R encoded input */ input wire logic [DATA_W-1:0] encoded_rx_data, + input wire logic encoded_rx_data_valid = 1'b1, input wire logic [HDR_W-1:0] encoded_rx_hdr, + input wire logic encoded_rx_hdr_valid = 1'b1, /* * XGMII interface */ output wire logic [DATA_W-1:0] xgmii_rxd, output wire logic [CTRL_W-1:0] xgmii_rxc, + output wire logic xgmii_rx_valid, /* * Status @@ -110,6 +114,7 @@ logic [CTRL_W-1:0] decode_err; logic [DATA_W-1:0] xgmii_rxd_reg = '0, xgmii_rxd_next; logic [CTRL_W-1:0] xgmii_rxc_reg = '0, xgmii_rxc_next; +logic xgmii_rx_valid_reg = 1'b0, xgmii_rx_valid_next; logic rx_bad_block_reg = 1'b0, rx_bad_block_next; logic rx_sequence_error_reg = 1'b0, rx_sequence_error_next; @@ -117,6 +122,7 @@ logic frame_reg = 1'b0, frame_next; assign xgmii_rxd = xgmii_rxd_reg; assign xgmii_rxc = xgmii_rxc_reg; +assign xgmii_rx_valid = xgmii_rx_valid_reg; assign rx_bad_block = rx_bad_block_reg; assign rx_sequence_error = rx_sequence_error_reg; @@ -124,6 +130,7 @@ assign rx_sequence_error = rx_sequence_error_reg; always_comb begin xgmii_rxd_next = {8{XGMII_ERROR}}; xgmii_rxc_next = 8'hff; + xgmii_rx_valid_next = 1'b0; rx_bad_block_next = 1'b0; rx_sequence_error_next = 1'b0; frame_next = frame_reg; @@ -173,12 +180,16 @@ always_comb begin endcase end - // use only four bits of block type for reduced fanin - if (encoded_rx_hdr[0] == 0) begin + if (GBX_IF_EN && !encoded_rx_data_valid) begin + // wait for data + end else if (encoded_rx_hdr[0] == 0) begin + // data block xgmii_rxd_next = encoded_rx_data; xgmii_rxc_next = 8'h00; rx_bad_block_next = 1'b0; end else begin + // control block + // use only four bits of block type for reduced fanin case (encoded_rx_data[7:4]) BLOCK_TYPE_CTRL[7:4]: begin // C7 C6 C5 C4 C3 C2 C1 C0 BT @@ -340,7 +351,9 @@ always_comb begin end // check all block type bits to detect bad encodings - if (encoded_rx_hdr == SYNC_DATA) begin + if (GBX_IF_EN && !encoded_rx_hdr_valid) begin + // wait for header + end else if (encoded_rx_hdr == SYNC_DATA) begin // data - nothing encoded end else if (encoded_rx_hdr == SYNC_CTRL) begin // control - check for bad block types @@ -378,12 +391,14 @@ end always_ff @(posedge clk) begin xgmii_rxd_reg <= xgmii_rxd_next; xgmii_rxc_reg <= xgmii_rxc_next; + xgmii_rx_valid_reg <= xgmii_rx_valid_next; rx_bad_block_reg <= rx_bad_block_next; rx_sequence_error_reg <= rx_sequence_error_next; frame_reg <= frame_next; if (rst) begin + xgmii_rx_valid_reg <= 1'b0; frame_reg <= 1'b0; end end diff --git a/src/eth/rtl/taxi_xgmii_baser_enc_64.sv b/src/eth/rtl/taxi_xgmii_baser_enc_64.sv index 41de01e..f91f6c9 100644 --- a/src/eth/rtl/taxi_xgmii_baser_enc_64.sv +++ b/src/eth/rtl/taxi_xgmii_baser_enc_64.sv @@ -19,28 +19,35 @@ module taxi_xgmii_baser_enc_64 # ( parameter DATA_W = 64, parameter CTRL_W = (DATA_W/8), - parameter HDR_W = 2 + parameter HDR_W = 2, + parameter logic GBX_IF_EN = 1'b0, + parameter GBX_CNT = 1 ) ( - input wire logic clk, - input wire logic rst, + input wire logic clk, + input wire logic rst, /* * XGMII interface */ - input wire logic [DATA_W-1:0] xgmii_txd, - input wire logic [CTRL_W-1:0] xgmii_txc, + input wire logic [DATA_W-1:0] xgmii_txd, + input wire logic [CTRL_W-1:0] xgmii_txc, + input wire logic xgmii_tx_valid = 1'b1, + input wire logic [GBX_CNT-1:0] tx_gbx_start_in = '0, /* * 10GBASE-R encoded interface */ - output wire logic [DATA_W-1:0] encoded_tx_data, - output wire logic [HDR_W-1:0] encoded_tx_hdr, + output wire logic [DATA_W-1:0] encoded_tx_data, + output wire logic encoded_tx_data_valid, + output wire logic [HDR_W-1:0] encoded_tx_hdr, + output wire logic encoded_tx_hdr_valid, + output wire logic [GBX_CNT-1:0] tx_gbx_start_out, /* * Status */ - output wire logic tx_bad_block + output wire logic tx_bad_block ); // check configuration @@ -108,12 +115,18 @@ logic [DATA_W*7/8-1:0] encoded_ctrl; logic [CTRL_W-1:0] encode_err; logic [DATA_W-1:0] encoded_tx_data_reg = '0, encoded_tx_data_next; +logic encoded_tx_data_valid_reg = 1'b0, encoded_tx_data_valid_next; logic [HDR_W-1:0] encoded_tx_hdr_reg = '0, encoded_tx_hdr_next; +logic encoded_tx_hdr_valid_reg = 1'b0, encoded_tx_hdr_valid_next; +logic [GBX_CNT-1:0] tx_gbx_start_reg = '0, tx_gbx_start_next; logic tx_bad_block_reg = 1'b0, tx_bad_block_next; assign encoded_tx_data = encoded_tx_data_reg; +assign encoded_tx_data_valid = GBX_IF_EN ? encoded_tx_data_valid_reg : 1'b1; assign encoded_tx_hdr = encoded_tx_hdr_reg; +assign encoded_tx_hdr_valid = GBX_IF_EN ? encoded_tx_hdr_valid_reg : 1'b1; +assign tx_gbx_start_out = GBX_IF_EN ? tx_gbx_start_reg : '0; assign tx_bad_block = tx_bad_block_reg; @@ -244,11 +257,22 @@ always_comb begin end encoded_tx_hdr_next = SYNC_CTRL; end + + if (GBX_IF_EN && !xgmii_tx_valid) begin + tx_bad_block_next = 1'b0; + end + + encoded_tx_data_valid_next = xgmii_tx_valid; + encoded_tx_hdr_valid_next = xgmii_tx_valid; + tx_gbx_start_next = tx_gbx_start_in; end always_ff @(posedge clk) begin encoded_tx_data_reg <= encoded_tx_data_next; + encoded_tx_data_valid_reg <= encoded_tx_data_valid_next; encoded_tx_hdr_reg <= encoded_tx_hdr_next; + encoded_tx_hdr_valid_reg <= encoded_tx_hdr_valid_next; + tx_gbx_start_reg <= tx_gbx_start_next; tx_bad_block_reg <= tx_bad_block_next; end diff --git a/src/eth/rtl/us/taxi_eth_mac_25g_us.f b/src/eth/rtl/us/taxi_eth_mac_25g_us.f index 1188ba7..c33b881 100644 --- a/src/eth/rtl/us/taxi_eth_mac_25g_us.f +++ b/src/eth/rtl/us/taxi_eth_mac_25g_us.f @@ -1,4 +1,5 @@ taxi_eth_mac_25g_us.sv taxi_eth_mac_25g_us_ch.sv taxi_eth_phy_25g_us_gt.f +taxi_eth_phy_25g_us_gt_ll.f ../taxi_eth_mac_phy_10g.f diff --git a/src/eth/rtl/us/taxi_eth_mac_25g_us.sv b/src/eth/rtl/us/taxi_eth_mac_25g_us.sv index 36ffefb..2ed277b 100644 --- a/src/eth/rtl/us/taxi_eth_mac_25g_us.sv +++ b/src/eth/rtl/us/taxi_eth_mac_25g_us.sv @@ -23,6 +23,9 @@ module taxi_eth_mac_25g_us # parameter CNT = 4, + // GT config + parameter logic CFG_LOW_LATENCY = 0, + // GT type parameter string GT_TYPE = "GTY", @@ -333,6 +336,9 @@ for (genvar n = 0; n < CNT; n = n + 1) begin : ch .HAS_COMMON(HAS_COMMON), + // GT config + .CFG_LOW_LATENCY(CFG_LOW_LATENCY), + // GT type .GT_TYPE(GT_TYPE), diff --git a/src/eth/rtl/us/taxi_eth_mac_25g_us_ch.sv b/src/eth/rtl/us/taxi_eth_mac_25g_us_ch.sv index b9dc322..b514b07 100644 --- a/src/eth/rtl/us/taxi_eth_mac_25g_us_ch.sv +++ b/src/eth/rtl/us/taxi_eth_mac_25g_us_ch.sv @@ -23,6 +23,9 @@ module taxi_eth_mac_25g_us_ch # parameter logic HAS_COMMON = 1'b1, + // GT config + parameter logic CFG_LOW_LATENCY = 0, + // GT type parameter string GT_TYPE = "GTY", @@ -278,130 +281,244 @@ localparam HDR_W = 2; wire rx_reset_req; -wire [5:0] gt_txheader; -wire [63:0] gt_txdata; -wire gt_rxgearboxslip; -wire [5:0] gt_rxheader; -wire [1:0] gt_rxheadervalid; -wire [63:0] gt_rxdata; -wire [1:0] gt_rxdatavalid; +wire [DATA_W-1:0] serdes_tx_data; +wire serdes_tx_data_valid; +wire [HDR_W-1:0] serdes_tx_hdr; +wire serdes_tx_hdr_valid; +wire serdes_tx_gbx_req_start; +wire serdes_tx_gbx_req_stall; +wire serdes_tx_gbx_start; +wire [DATA_W-1:0] serdes_rx_data; +wire serdes_rx_data_valid; +wire [HDR_W-1:0] serdes_rx_hdr; +wire serdes_rx_hdr_valid; +wire serdes_rx_bitslip; -taxi_eth_phy_25g_us_gt #( - .SIM(SIM), - .VENDOR(VENDOR), - .FAMILY(FAMILY), +if (CFG_LOW_LATENCY) begin : gt - .HAS_COMMON(HAS_COMMON), + taxi_eth_phy_25g_us_gt_ll #( + .SIM(SIM), + .VENDOR(VENDOR), + .FAMILY(FAMILY), - // GT type - .GT_TYPE(GT_TYPE), + .HAS_COMMON(HAS_COMMON), - // PLL parameters - .QPLL0_PD(QPLL0_PD), - .QPLL1_PD(QPLL1_PD), - .QPLL0_EXT_CTRL(QPLL0_EXT_CTRL), - .QPLL1_EXT_CTRL(QPLL1_EXT_CTRL), + // GT type + .GT_TYPE(GT_TYPE), - // GT parameters - .GT_TX_PD(GT_TX_PD), - .GT_TX_QPLL_SEL(GT_TX_QPLL_SEL), - .GT_TX_POLARITY(GT_TX_POLARITY), - .GT_TX_ELECIDLE(GT_TX_ELECIDLE), - .GT_TX_INHIBIT(GT_TX_INHIBIT), - .GT_TX_DIFFCTRL(GT_TX_DIFFCTRL), - .GT_TX_MAINCURSOR(GT_TX_MAINCURSOR), - .GT_TX_POSTCURSOR(GT_TX_POSTCURSOR), - .GT_TX_PRECURSOR(GT_TX_PRECURSOR), - .GT_RX_PD(GT_RX_PD), - .GT_RX_QPLL_SEL(GT_RX_QPLL_SEL), - .GT_RX_LPM_EN(GT_RX_LPM_EN), - .GT_RX_POLARITY(GT_RX_POLARITY) -) -gt_inst ( - .xcvr_ctrl_clk(xcvr_ctrl_clk), - .xcvr_ctrl_rst(xcvr_ctrl_rst), + // PLL parameters + .QPLL0_PD(QPLL0_PD), + .QPLL1_PD(QPLL1_PD), + .QPLL0_EXT_CTRL(QPLL0_EXT_CTRL), + .QPLL1_EXT_CTRL(QPLL1_EXT_CTRL), - /* - * Common - */ - .xcvr_gtpowergood_out(xcvr_gtpowergood_out), + // GT parameters + .GT_TX_PD(GT_TX_PD), + .GT_TX_QPLL_SEL(GT_TX_QPLL_SEL), + .GT_TX_POLARITY(GT_TX_POLARITY), + .GT_TX_ELECIDLE(GT_TX_ELECIDLE), + .GT_TX_INHIBIT(GT_TX_INHIBIT), + .GT_TX_DIFFCTRL(GT_TX_DIFFCTRL), + .GT_TX_MAINCURSOR(GT_TX_MAINCURSOR), + .GT_TX_POSTCURSOR(GT_TX_POSTCURSOR), + .GT_TX_PRECURSOR(GT_TX_PRECURSOR), + .GT_RX_PD(GT_RX_PD), + .GT_RX_QPLL_SEL(GT_RX_QPLL_SEL), + .GT_RX_LPM_EN(GT_RX_LPM_EN), + .GT_RX_POLARITY(GT_RX_POLARITY), - /* - * PLL out - */ - .xcvr_gtrefclk00_in(xcvr_gtrefclk00_in), - .xcvr_qpll0pd_in(xcvr_qpll0pd_in), - .xcvr_qpll0reset_in(xcvr_qpll0reset_in), - .xcvr_qpll0pcierate_in(xcvr_qpll0pcierate_in), - .xcvr_qpll0lock_out(xcvr_qpll0lock_out), - .xcvr_qpll0clk_out(xcvr_qpll0clk_out), - .xcvr_qpll0refclk_out(xcvr_qpll0refclk_out), - .xcvr_gtrefclk01_in(xcvr_gtrefclk01_in), - .xcvr_qpll1pd_in(xcvr_qpll1pd_in), - .xcvr_qpll1reset_in(xcvr_qpll1reset_in), - .xcvr_qpll1pcierate_in(xcvr_qpll1pcierate_in), - .xcvr_qpll1lock_out(xcvr_qpll1lock_out), - .xcvr_qpll1clk_out(xcvr_qpll1clk_out), - .xcvr_qpll1refclk_out(xcvr_qpll1refclk_out), + // MAC/PHY parameters + .DATA_W(DATA_W), + .HDR_W(HDR_W) + ) + gt_inst ( + .xcvr_ctrl_clk(xcvr_ctrl_clk), + .xcvr_ctrl_rst(xcvr_ctrl_rst), - /* - * PLL in - */ - .xcvr_qpll0lock_in(xcvr_qpll0lock_in), - .xcvr_qpll0clk_in(xcvr_qpll0clk_in), - .xcvr_qpll0refclk_in(xcvr_qpll0refclk_in), - .xcvr_qpll1lock_in(xcvr_qpll1lock_in), - .xcvr_qpll1clk_in(xcvr_qpll1clk_in), - .xcvr_qpll1refclk_in(xcvr_qpll1refclk_in), + /* + * Common + */ + .xcvr_gtpowergood_out(xcvr_gtpowergood_out), - /* - * Serial data - */ - .xcvr_txp(xcvr_txp), - .xcvr_txn(xcvr_txn), - .xcvr_rxp(xcvr_rxp), - .xcvr_rxn(xcvr_rxn), + /* + * PLL out + */ + .xcvr_gtrefclk00_in(xcvr_gtrefclk00_in), + .xcvr_qpll0pd_in(xcvr_qpll0pd_in), + .xcvr_qpll0reset_in(xcvr_qpll0reset_in), + .xcvr_qpll0pcierate_in(xcvr_qpll0pcierate_in), + .xcvr_qpll0lock_out(xcvr_qpll0lock_out), + .xcvr_qpll0clk_out(xcvr_qpll0clk_out), + .xcvr_qpll0refclk_out(xcvr_qpll0refclk_out), + .xcvr_gtrefclk01_in(xcvr_gtrefclk01_in), + .xcvr_qpll1pd_in(xcvr_qpll1pd_in), + .xcvr_qpll1reset_in(xcvr_qpll1reset_in), + .xcvr_qpll1pcierate_in(xcvr_qpll1pcierate_in), + .xcvr_qpll1lock_out(xcvr_qpll1lock_out), + .xcvr_qpll1clk_out(xcvr_qpll1clk_out), + .xcvr_qpll1refclk_out(xcvr_qpll1refclk_out), - /* - * GT user clocks - */ - .rx_clk(rx_clk), - .rx_rst_in(rx_rst_in || rx_reset_req), - .rx_rst_out(rx_rst_out), - .tx_clk(tx_clk), - .tx_rst_in(tx_rst_in), - .tx_rst_out(tx_rst_out), + /* + * PLL in + */ + .xcvr_qpll0lock_in(xcvr_qpll0lock_in), + .xcvr_qpll0clk_in(xcvr_qpll0clk_in), + .xcvr_qpll0refclk_in(xcvr_qpll0refclk_in), + .xcvr_qpll1lock_in(xcvr_qpll1lock_in), + .xcvr_qpll1clk_in(xcvr_qpll1clk_in), + .xcvr_qpll1refclk_in(xcvr_qpll1refclk_in), - /* - * Serdes interface - */ - .gt_txheader(gt_txheader), - .gt_txdata(gt_txdata), - .gt_rxgearboxslip(gt_rxgearboxslip), - .gt_rxheader(gt_rxheader), - .gt_rxheadervalid(gt_rxheadervalid), - .gt_rxdata(gt_rxdata), - .gt_rxdatavalid(gt_rxdatavalid) -); + /* + * Serial data + */ + .xcvr_txp(xcvr_txp), + .xcvr_txn(xcvr_txn), + .xcvr_rxp(xcvr_rxp), + .xcvr_rxn(xcvr_rxn), -wire [DATA_W-1:0] serdes_tx_data; -wire [HDR_W-1:0] serdes_tx_hdr; -wire [DATA_W-1:0] serdes_rx_data; -wire [HDR_W-1:0] serdes_rx_hdr; -wire serdes_rx_bitslip; + /* + * GT user clocks + */ + .rx_clk(rx_clk), + .rx_rst_in(rx_rst_in || rx_reset_req), + .rx_rst_out(rx_rst_out), + .tx_clk(tx_clk), + .tx_rst_in(tx_rst_in), + .tx_rst_out(tx_rst_out), -assign gt_txdata = serdes_tx_data; -assign gt_txheader = {4'd0, serdes_tx_hdr}; -assign gt_rxgearboxslip = serdes_rx_bitslip; + /* + * Serdes interface + */ + .serdes_tx_data(serdes_tx_data), + .serdes_tx_data_valid(serdes_tx_data_valid), + .serdes_tx_hdr(serdes_tx_hdr), + .serdes_tx_hdr_valid(serdes_tx_hdr_valid), + .serdes_tx_gbx_req_start(serdes_tx_gbx_req_start), + .serdes_tx_gbx_req_stall(serdes_tx_gbx_req_stall), + .serdes_tx_gbx_start(serdes_tx_gbx_start), + .serdes_rx_data(serdes_rx_data), + .serdes_rx_data_valid(serdes_rx_data_valid), + .serdes_rx_hdr(serdes_rx_hdr), + .serdes_rx_hdr_valid(serdes_rx_hdr_valid), + .serdes_rx_bitslip(serdes_rx_bitslip) + ); + +end else begin : gt + + taxi_eth_phy_25g_us_gt #( + .SIM(SIM), + .VENDOR(VENDOR), + .FAMILY(FAMILY), + + .HAS_COMMON(HAS_COMMON), + + // GT type + .GT_TYPE(GT_TYPE), + + // PLL parameters + .QPLL0_PD(QPLL0_PD), + .QPLL1_PD(QPLL1_PD), + .QPLL0_EXT_CTRL(QPLL0_EXT_CTRL), + .QPLL1_EXT_CTRL(QPLL1_EXT_CTRL), + + // GT parameters + .GT_TX_PD(GT_TX_PD), + .GT_TX_QPLL_SEL(GT_TX_QPLL_SEL), + .GT_TX_POLARITY(GT_TX_POLARITY), + .GT_TX_ELECIDLE(GT_TX_ELECIDLE), + .GT_TX_INHIBIT(GT_TX_INHIBIT), + .GT_TX_DIFFCTRL(GT_TX_DIFFCTRL), + .GT_TX_MAINCURSOR(GT_TX_MAINCURSOR), + .GT_TX_POSTCURSOR(GT_TX_POSTCURSOR), + .GT_TX_PRECURSOR(GT_TX_PRECURSOR), + .GT_RX_PD(GT_RX_PD), + .GT_RX_QPLL_SEL(GT_RX_QPLL_SEL), + .GT_RX_LPM_EN(GT_RX_LPM_EN), + .GT_RX_POLARITY(GT_RX_POLARITY), + + // MAC/PHY parameters + .DATA_W(DATA_W), + .HDR_W(HDR_W) + ) + gt_inst ( + .xcvr_ctrl_clk(xcvr_ctrl_clk), + .xcvr_ctrl_rst(xcvr_ctrl_rst), + + /* + * Common + */ + .xcvr_gtpowergood_out(xcvr_gtpowergood_out), + + /* + * PLL out + */ + .xcvr_gtrefclk00_in(xcvr_gtrefclk00_in), + .xcvr_qpll0pd_in(xcvr_qpll0pd_in), + .xcvr_qpll0reset_in(xcvr_qpll0reset_in), + .xcvr_qpll0pcierate_in(xcvr_qpll0pcierate_in), + .xcvr_qpll0lock_out(xcvr_qpll0lock_out), + .xcvr_qpll0clk_out(xcvr_qpll0clk_out), + .xcvr_qpll0refclk_out(xcvr_qpll0refclk_out), + .xcvr_gtrefclk01_in(xcvr_gtrefclk01_in), + .xcvr_qpll1pd_in(xcvr_qpll1pd_in), + .xcvr_qpll1reset_in(xcvr_qpll1reset_in), + .xcvr_qpll1pcierate_in(xcvr_qpll1pcierate_in), + .xcvr_qpll1lock_out(xcvr_qpll1lock_out), + .xcvr_qpll1clk_out(xcvr_qpll1clk_out), + .xcvr_qpll1refclk_out(xcvr_qpll1refclk_out), + + /* + * PLL in + */ + .xcvr_qpll0lock_in(xcvr_qpll0lock_in), + .xcvr_qpll0clk_in(xcvr_qpll0clk_in), + .xcvr_qpll0refclk_in(xcvr_qpll0refclk_in), + .xcvr_qpll1lock_in(xcvr_qpll1lock_in), + .xcvr_qpll1clk_in(xcvr_qpll1clk_in), + .xcvr_qpll1refclk_in(xcvr_qpll1refclk_in), + + /* + * Serial data + */ + .xcvr_txp(xcvr_txp), + .xcvr_txn(xcvr_txn), + .xcvr_rxp(xcvr_rxp), + .xcvr_rxn(xcvr_rxn), + + /* + * GT user clocks + */ + .rx_clk(rx_clk), + .rx_rst_in(rx_rst_in || rx_reset_req), + .rx_rst_out(rx_rst_out), + .tx_clk(tx_clk), + .tx_rst_in(tx_rst_in), + .tx_rst_out(tx_rst_out), + + /* + * Serdes interface + */ + .serdes_tx_data(serdes_tx_data), + .serdes_tx_data_valid(serdes_tx_data_valid), + .serdes_tx_hdr(serdes_tx_hdr), + .serdes_tx_hdr_valid(serdes_tx_hdr_valid), + .serdes_tx_gbx_req_start(serdes_tx_gbx_req_start), + .serdes_tx_gbx_req_stall(serdes_tx_gbx_req_stall), + .serdes_tx_gbx_start(serdes_tx_gbx_start), + .serdes_rx_data(serdes_rx_data), + .serdes_rx_data_valid(serdes_rx_data_valid), + .serdes_rx_hdr(serdes_rx_hdr), + .serdes_rx_hdr_valid(serdes_rx_hdr_valid), + .serdes_rx_bitslip(serdes_rx_bitslip) + ); -if (!SIM) begin - assign serdes_rx_data = gt_rxdata; - assign serdes_rx_hdr = gt_rxheader[1:0]; end taxi_eth_mac_phy_10g #( .DATA_W(DATA_W), .HDR_W(HDR_W), + .TX_GBX_IF_EN(CFG_LOW_LATENCY), + .RX_GBX_IF_EN(CFG_LOW_LATENCY), .PADDING_EN(PADDING_EN), .DIC_EN(DIC_EN), .MIN_FRAME_LEN(MIN_FRAME_LEN), @@ -445,9 +562,16 @@ eth_mac_phy_10g_inst ( * Serdes interface */ .serdes_tx_data(serdes_tx_data), + .serdes_tx_data_valid(serdes_tx_data_valid), .serdes_tx_hdr(serdes_tx_hdr), + .serdes_tx_hdr_valid(serdes_tx_hdr_valid), + .serdes_tx_gbx_req_start(serdes_tx_gbx_req_start), + .serdes_tx_gbx_req_stall(serdes_tx_gbx_req_stall), + .serdes_tx_gbx_start(serdes_tx_gbx_start), .serdes_rx_data(serdes_rx_data), + .serdes_rx_data_valid(serdes_rx_data_valid), .serdes_rx_hdr(serdes_rx_hdr), + .serdes_rx_hdr_valid(serdes_rx_hdr_valid), .serdes_rx_bitslip(serdes_rx_bitslip), .serdes_rx_reset_req(rx_reset_req), diff --git a/src/eth/rtl/us/taxi_eth_phy_25g_us_gt.sv b/src/eth/rtl/us/taxi_eth_phy_25g_us_gt.sv index 2279349..7f4d45c 100644 --- a/src/eth/rtl/us/taxi_eth_phy_25g_us_gt.sv +++ b/src/eth/rtl/us/taxi_eth_phy_25g_us_gt.sv @@ -45,7 +45,11 @@ module taxi_eth_phy_25g_us_gt # parameter logic GT_RX_PD = 1'b0, parameter logic GT_RX_QPLL_SEL = 1'b0, parameter logic GT_RX_LPM_EN = 1'b0, - parameter logic GT_RX_POLARITY = 1'b0 + parameter logic GT_RX_POLARITY = 1'b0, + + // MAC/PHY parameters + parameter DATA_W = 64, + parameter HDR_W = 2 ) ( input wire logic xcvr_ctrl_clk, @@ -105,13 +109,18 @@ module taxi_eth_phy_25g_us_gt # /* * Serdes interface */ - input wire logic [5:0] gt_txheader, - input wire logic [63:0] gt_txdata, - input wire logic gt_rxgearboxslip, - output wire logic [5:0] gt_rxheader, - output wire logic [1:0] gt_rxheadervalid, - output wire logic [63:0] gt_rxdata, - output wire logic [1:0] gt_rxdatavalid + input wire logic [DATA_W-1:0] serdes_tx_data, + input wire logic serdes_tx_data_valid, + input wire logic [HDR_W-1:0] serdes_tx_hdr, + input wire logic serdes_tx_hdr_valid, + output wire logic serdes_tx_gbx_req_start, + output wire logic serdes_tx_gbx_req_stall, + input wire logic serdes_tx_gbx_start, + output wire logic [DATA_W-1:0] serdes_rx_data, + output wire logic serdes_rx_data_valid, + output wire logic [HDR_W-1:0] serdes_rx_hdr, + output wire logic serdes_rx_hdr_valid, + input wire logic serdes_rx_bitslip ); localparam GT_USP = FAMILY == "kintexuplus" || FAMILY == "virtexuplus" || FAMILY == "virtexuplusHBM" @@ -340,6 +349,30 @@ gt_rx_reset_inst ( .rx_lpm_en_in(GT_RX_LPM_EN) ); +wire [6:0] gt_txsequence; +wire [5:0] gt_txheader; +wire [63:0] gt_txdata; +wire gt_rxgearboxslip; +wire [1:0] gt_rxstartofseq; +wire [5:0] gt_rxheader; +wire [1:0] gt_rxheadervalid; +wire [63:0] gt_rxdata; +wire [1:0] gt_rxdatavalid; + +assign gt_txdata = serdes_tx_data; +assign gt_txheader = {4'd0, serdes_tx_hdr}; +assign gt_rxgearboxslip = serdes_rx_bitslip; + +if (!SIM) begin + assign serdes_rx_data = gt_rxdata; + assign serdes_rx_data_valid = gt_rxdatavalid; + assign serdes_rx_hdr = gt_rxheader[1:0]; + assign serdes_rx_hdr_valid = gt_rxheadervalid[0]; +end + +assign serdes_tx_gbx_req_start = 1'b0; +assign serdes_tx_gbx_req_stall = 1'b0; + if (SIM) begin : xcvr // simulation (no GT core) @@ -771,8 +804,8 @@ end else if (HAS_COMMON && GT_TYPE == "GTH" && !GT_USP) begin : xcvr end else if (!HAS_COMMON && GT_TYPE == "GTY") begin : xcvr // UltraScale/UltraScale+ GTY (channel only) - taxi_eth_phy_25g_us_gty_channel - taxi_eth_phy_25g_us_gty_channel_inst ( + taxi_eth_phy_25g_us_gty_ch + taxi_eth_phy_25g_us_gty_ch_inst ( // Common .gtpowergood_out(xcvr_gtpowergood_out), @@ -864,8 +897,8 @@ end else if (!HAS_COMMON && GT_TYPE == "GTY") begin : xcvr end else if (!HAS_COMMON && GT_TYPE == "GTH") begin : xcvr // UltraScale/UltraScale+ GTY (channel only) - taxi_eth_phy_25g_us_gth_channel - taxi_eth_phy_25g_us_gth_channel_inst ( + taxi_eth_phy_25g_us_gth_ch + taxi_eth_phy_25g_us_gth_ch_inst ( // Common .gtpowergood_out(xcvr_gtpowergood_out), diff --git a/src/eth/rtl/us/taxi_eth_phy_25g_us_gt_ll.f b/src/eth/rtl/us/taxi_eth_phy_25g_us_gt_ll.f new file mode 100644 index 0000000..e4c0305 --- /dev/null +++ b/src/eth/rtl/us/taxi_eth_phy_25g_us_gt_ll.f @@ -0,0 +1,6 @@ +taxi_eth_phy_25g_us_gt_ll.sv +../../lib/taxi/src/sync/rtl/taxi_sync_reset.sv +../../lib/taxi/src/sync/rtl/taxi_sync_signal.sv +../../lib/taxi/src/hip/rtl/us/taxi_gt_qpll_reset.sv +../../lib/taxi/src/hip/rtl/us/taxi_gt_rx_reset.sv +../../lib/taxi/src/hip/rtl/us/taxi_gt_tx_reset.sv diff --git a/src/eth/rtl/us/taxi_eth_phy_25g_us_gt_ll.sv b/src/eth/rtl/us/taxi_eth_phy_25g_us_gt_ll.sv new file mode 100644 index 0000000..92ff6d8 --- /dev/null +++ b/src/eth/rtl/us/taxi_eth_phy_25g_us_gt_ll.sv @@ -0,0 +1,1127 @@ +// SPDX-License-Identifier: CERN-OHL-S-2.0 +/* + +Copyright (c) 2025 FPGA Ninja, LLC + +Authors: +- Alex Forencich + +*/ + +`resetall +`timescale 1ns / 1ps +`default_nettype none + +/* + * Transceiver wrapper for UltraScale/UltraScale+ (low latency) + */ +module taxi_eth_phy_25g_us_gt_ll # +( + parameter logic SIM = 1'b0, + parameter string VENDOR = "XILINX", + parameter string FAMILY = "virtexuplus", + + parameter logic HAS_COMMON = 1'b1, + + // GT type + parameter string GT_TYPE = "GTY", + + // PLL parameters + parameter logic QPLL0_PD = 1'b0, + parameter logic QPLL1_PD = 1'b1, + parameter logic QPLL0_EXT_CTRL = 1'b0, + parameter logic QPLL1_EXT_CTRL = 1'b0, + + // GT parameters + parameter logic GT_TX_PD = 1'b0, + parameter logic GT_TX_QPLL_SEL = 1'b0, + parameter logic GT_TX_POLARITY = 1'b0, + parameter logic GT_TX_ELECIDLE = 1'b0, + parameter logic GT_TX_INHIBIT = 1'b0, + parameter logic [4:0] GT_TX_DIFFCTRL = 5'd16, + parameter logic [6:0] GT_TX_MAINCURSOR = 7'd64, + parameter logic [4:0] GT_TX_POSTCURSOR = 5'd0, + parameter logic [4:0] GT_TX_PRECURSOR = 5'd0, + parameter logic GT_RX_PD = 1'b0, + parameter logic GT_RX_QPLL_SEL = 1'b0, + parameter logic GT_RX_LPM_EN = 1'b0, + parameter logic GT_RX_POLARITY = 1'b0, + + // MAC/PHY parameters + parameter DATA_W = 64, + parameter HDR_W = 2 +) +( + input wire logic xcvr_ctrl_clk, + input wire logic xcvr_ctrl_rst, + + /* + * Common + */ + output wire logic xcvr_gtpowergood_out, + + /* + * PLL out + */ + input wire logic xcvr_gtrefclk00_in = 1'b0, + input wire logic xcvr_qpll0pd_in = 1'b0, + input wire logic xcvr_qpll0reset_in = 1'b0, + input wire logic [2:0] xcvr_qpll0pcierate_in = 3'd0, + output wire logic xcvr_qpll0lock_out, + output wire logic xcvr_qpll0clk_out, + output wire logic xcvr_qpll0refclk_out, + input wire logic xcvr_gtrefclk01_in = 1'b0, + input wire logic xcvr_qpll1pd_in = 1'b0, + input wire logic xcvr_qpll1reset_in = 1'b0, + input wire logic [2:0] xcvr_qpll1pcierate_in = 3'd0, + output wire logic xcvr_qpll1lock_out, + output wire logic xcvr_qpll1clk_out, + output wire logic xcvr_qpll1refclk_out, + + /* + * PLL in + */ + input wire logic xcvr_qpll0lock_in = 1'b0, + input wire logic xcvr_qpll0clk_in = 1'b0, + input wire logic xcvr_qpll0refclk_in = 1'b0, + input wire logic xcvr_qpll1lock_in = 1'b0, + input wire logic xcvr_qpll1clk_in = 1'b0, + input wire logic xcvr_qpll1refclk_in = 1'b0, + + /* + * Serial data + */ + output wire logic xcvr_txp, + output wire logic xcvr_txn, + input wire logic xcvr_rxp, + input wire logic xcvr_rxn, + + /* + * GT user clocks + */ + output wire logic rx_clk, + input wire logic rx_rst_in = 1'b0, + output wire logic rx_rst_out, + output wire logic tx_clk, + input wire logic tx_rst_in = 1'b0, + output wire logic tx_rst_out, + + /* + * Serdes interface + */ + input wire logic [DATA_W-1:0] serdes_tx_data, + input wire logic serdes_tx_data_valid, + input wire logic [HDR_W-1:0] serdes_tx_hdr, + input wire logic serdes_tx_hdr_valid, + output wire logic serdes_tx_gbx_req_start, + output wire logic serdes_tx_gbx_req_stall, + input wire logic serdes_tx_gbx_start, + output wire logic [DATA_W-1:0] serdes_rx_data, + output wire logic serdes_rx_data_valid, + output wire logic [HDR_W-1:0] serdes_rx_hdr, + output wire logic serdes_rx_hdr_valid, + input wire logic serdes_rx_bitslip +); + +localparam GT_USP = FAMILY == "kintexuplus" || FAMILY == "virtexuplus" || FAMILY == "virtexuplusHBM" + || FAMILY == "virtexuplus58G" || FAMILY == "zynquplus" || FAMILY == "zynquplusRFSOC"; + +wire xcvr_ctrl_rst_sync; + +taxi_sync_reset #( + .N(4) +) +reset_sync_inst ( + .clk(xcvr_ctrl_clk), + .rst(xcvr_ctrl_rst), + .out(xcvr_ctrl_rst_sync) +); + +wire gt_qpll0_pd; +wire gt_qpll0_reset; +wire gt_qpll1_pd; +wire gt_qpll1_reset; + +wire qpll0_lock; +wire qpll1_lock; + +if (HAS_COMMON) begin : common_ctrl + + taxi_gt_qpll_reset #( + .QPLL_PD(QPLL0_PD), + .CNT_W(8) + ) + qpll0_reset_inst ( + .clk(xcvr_ctrl_clk), + .rst(xcvr_ctrl_rst_sync), + + /* + * GT + */ + .gt_qpll_reset_out(gt_qpll0_reset), + .gt_qpll_pd_out(gt_qpll0_pd), + .gt_qpll_lock_in(xcvr_qpll0lock_out), + + /* + * Control/status + */ + .qpll_reset_in(1'b0), + .qpll_pd_in(QPLL0_PD), + .qpll_lock_out(qpll0_lock) + ); + + taxi_gt_qpll_reset #( + .QPLL_PD(QPLL1_PD), + .CNT_W(8) + ) + qpll1_reset_inst ( + .clk(xcvr_ctrl_clk), + .rst(xcvr_ctrl_rst_sync), + + /* + * GT + */ + .gt_qpll_reset_out(gt_qpll1_reset), + .gt_qpll_pd_out(gt_qpll1_pd), + .gt_qpll_lock_in(xcvr_qpll1lock_out), + + /* + * Control/status + */ + .qpll_reset_in(1'b0), + .qpll_pd_in(QPLL1_PD), + .qpll_lock_out(qpll1_lock) + ); + +end else begin : common_ctrl + + assign gt_qpll0_pd = 1'b1; + assign gt_qpll0_reset = 1'b1; + assign gt_qpll1_pd = 1'b1; + assign gt_qpll1_reset = 1'b1; + + taxi_sync_signal #( + .WIDTH(2), + .N(2) + ) + qpll_lock_sync_inst ( + .clk(xcvr_ctrl_clk), + .in({xcvr_qpll1lock_in, xcvr_qpll0lock_in}), + .out({qpll1_lock, qpll0_lock}) + ); + +end + +wire gt_tx_pd; +wire gt_tx_reset; +wire gt_tx_reset_done; +wire gt_userclk_tx_active; +wire gt_tx_pma_reset; +wire gt_tx_pcs_reset; +wire gt_tx_pma_reset_done; +wire gt_tx_prgdiv_reset; +wire gt_tx_prgdiv_reset_done; +wire gt_tx_qpll_sel; +wire gt_tx_userrdy; + +wire tx_reset_done; + +taxi_sync_reset #( + .N(4) +) +tx_reset_sync_inst ( + .clk(tx_clk), + .rst(!tx_reset_done || tx_rst_in), + .out(tx_rst_out) +); + +taxi_gt_tx_reset #( + .GT_TX_PD(GT_TX_PD), + .GT_TX_QPLL_SEL(GT_TX_QPLL_SEL), + .CNT_W(8) +) +gt_tx_reset_inst ( + .clk(xcvr_ctrl_clk), + .rst(xcvr_ctrl_rst_sync), + + /* + * GT + */ + .gt_tx_pd_out(gt_tx_pd), + .gt_tx_reset_out(gt_tx_reset), + .gt_tx_reset_done_in(gt_tx_reset_done), + .gt_userclk_tx_active_in(gt_userclk_tx_active), + .gt_tx_pma_reset_out(gt_tx_pma_reset), + .gt_tx_pcs_reset_out(gt_tx_pcs_reset), + .gt_tx_pma_reset_done_in(gt_tx_pma_reset_done), + .gt_tx_prgdiv_reset_out(gt_tx_prgdiv_reset), + .gt_tx_prgdiv_reset_done_in(gt_tx_prgdiv_reset_done), + .gt_tx_qpll_sel_out(gt_tx_qpll_sel), + .gt_tx_userrdy_out(gt_tx_userrdy), + + /* + * Control/status + */ + .qpll0_lock_in(qpll0_lock), + .qpll1_lock_in(qpll1_lock), + .tx_reset_in(tx_rst_in), + .tx_reset_done_out(tx_reset_done), + .tx_pma_reset_in(1'b0), + .tx_pma_reset_done_out(), + .tx_prgdiv_reset_done_out(), + .tx_pcs_reset_in(1'b0), + .tx_pd_in(GT_TX_PD), + .tx_qpll_sel_in(GT_TX_QPLL_SEL) +); + +wire gt_rx_pd; +wire gt_rx_reset; +wire gt_rx_reset_done; +wire gt_userclk_rx_active; +wire gt_rx_pma_reset; +wire gt_rx_dfe_lpm_reset; +wire gt_rx_eyescan_reset; +wire gt_rx_pcs_reset; +wire gt_rx_pma_reset_done; +wire gt_rx_prgdiv_reset; +wire gt_rx_prgdiv_reset_done; +wire gt_rx_qpll_sel; +wire gt_rx_userrdy; +wire gt_rx_cdr_lock; +wire gt_rx_lpm_en; + +wire rx_reset_done; + +taxi_sync_reset #( + .N(4) +) +rx_reset_sync_inst ( + .clk(rx_clk), + .rst(!rx_reset_done || rx_rst_in), + .out(rx_rst_out) +); + +taxi_gt_rx_reset #( + .GT_RX_PD(GT_RX_PD), + .GT_RX_QPLL_SEL(GT_RX_QPLL_SEL), + .GT_RX_LPM_EN(GT_RX_LPM_EN), + .CNT_W(8), + .CDR_CNT_W(20) +) +gt_rx_reset_inst ( + .clk(xcvr_ctrl_clk), + .rst(xcvr_ctrl_rst_sync), + + /* + * GT + */ + .gt_rx_pd_out(gt_rx_pd), + .gt_rx_reset_out(gt_rx_reset), + .gt_rx_reset_done_in(gt_rx_reset_done), + .gt_userclk_rx_active_in(gt_userclk_rx_active), + .gt_rx_pma_reset_out(gt_rx_pma_reset), + .gt_rx_dfe_lpm_reset_out(gt_rx_dfe_lpm_reset), + .gt_rx_eyescan_reset_out(gt_rx_eyescan_reset), + .gt_rx_pcs_reset_out(gt_rx_pcs_reset), + .gt_rx_pma_reset_done_in(gt_rx_pma_reset_done), + .gt_rx_prgdiv_reset_out(gt_rx_prgdiv_reset), + .gt_rx_prgdiv_reset_done_in(gt_rx_prgdiv_reset_done), + .gt_rx_qpll_sel_out(gt_rx_qpll_sel), + .gt_rx_userrdy_out(gt_rx_userrdy), + .gt_rx_cdr_lock_in(gt_rx_cdr_lock), + .gt_rx_lpm_en_out(gt_rx_lpm_en), + + /* + * Control/status + */ + .qpll0_lock_in(qpll0_lock), + .qpll1_lock_in(qpll1_lock), + .rx_reset_in(rx_rst_in), + .rx_reset_done_out(rx_reset_done), + .rx_pma_reset_in(1'b0), + .rx_pma_reset_done_out(), + .rx_prgdiv_reset_done_out(), + .rx_pcs_reset_in(1'b0), + .rx_dfe_lpm_reset_in(1'b0), + .eyescan_reset_in(1'b0), + .rx_pd_in(GT_RX_PD), + .rx_qpll_sel_in(GT_RX_QPLL_SEL), + .rx_lpm_en_in(GT_RX_LPM_EN) +); + +wire [6:0] gt_txsequence; +wire [5:0] gt_txheader; +wire [63:0] gt_txdata; +wire gt_rxgearboxslip; +wire [1:0] gt_rxstartofseq; +wire [5:0] gt_rxheader; +wire [1:0] gt_rxheadervalid; +wire [63:0] gt_rxdata; +wire [1:0] gt_rxdatavalid; + +assign gt_txdata = serdes_tx_data; +assign gt_txheader = {4'd0, serdes_tx_hdr}; +assign gt_rxgearboxslip = serdes_rx_bitslip; + +if (!SIM) begin + assign serdes_rx_data = gt_rxdata; + assign serdes_rx_data_valid = gt_rxdatavalid; + assign serdes_rx_hdr = gt_rxheader[1:0]; + assign serdes_rx_hdr_valid = gt_rxheadervalid[0]; +end + +if (GT_TYPE == "GTY") begin : tx_seq + // 66 clock cycle sequence for GTY, with two stalls on cycles 64 and 65 + // 64-bit internal, 64-bit external datapath width (required for operation at 25G) + + // Generate gearbox request signals + logic [6:0] tx_seq_gen_reg = '0; + logic tx_req_start_reg = 1'b0; + logic tx_req_stall_reg = 1'b0; + + assign serdes_tx_gbx_req_start = tx_req_start_reg; + assign serdes_tx_gbx_req_stall = tx_req_stall_reg; + + always @(posedge tx_clk) begin + tx_req_start_reg <= 1'b0; + tx_req_stall_reg <= 1'b0; + + tx_seq_gen_reg <= tx_seq_gen_reg - 1; + if (tx_seq_gen_reg == 0) begin + tx_seq_gen_reg <= 65; + tx_req_start_reg <= 1'b1; + end + if (tx_seq_gen_reg == 2 || tx_seq_gen_reg == 1) begin + tx_req_stall_reg <= 1'b1; + end + end + + // Generate TX sequence + logic [6:0] tx_seq_reg = '0; + + assign gt_txsequence = {1'b0, tx_seq_reg[6:1]}; + + always @(posedge tx_clk) begin + tx_seq_reg <= tx_seq_reg + 1; + if (tx_seq_reg == 65) begin + tx_seq_reg <= '0; + end + if (serdes_tx_gbx_start) begin + tx_seq_reg <= 1; + end + end + +end else begin : tx_seq + // 33 clock cycle sequence for GTH, with one stall on cycle 32 + // 32-bit internal, 64-bit external datapath width + + // Generate gearbox request signals + logic [5:0] tx_seq_gen_reg = '0; + logic tx_req_start_reg = 1'b0; + logic tx_req_stall_reg = 1'b0; + + assign serdes_tx_gbx_req_start = tx_req_start_reg; + assign serdes_tx_gbx_req_stall = tx_req_stall_reg; + + always @(posedge tx_clk) begin + tx_req_start_reg <= 1'b0; + tx_req_stall_reg <= 1'b0; + + tx_seq_gen_reg <= tx_seq_gen_reg - 1; + if (tx_seq_gen_reg == 0) begin + tx_seq_gen_reg <= 32; + tx_req_start_reg <= 1'b1; + end + if (tx_seq_gen_reg == 1) begin + tx_req_stall_reg <= 1'b1; + end + end + + // Generate TX sequence + logic [5:0] tx_seq_reg = '0; + + assign gt_txsequence = {1'b0, tx_seq_reg}; + + always @(posedge tx_clk) begin + tx_seq_reg <= tx_seq_reg + 1; + if (tx_seq_reg == 32) begin + tx_seq_reg <= '0; + end + if (serdes_tx_gbx_start) begin + tx_seq_reg <= 1; + end + end + +end + +if (SIM) begin : xcvr + // simulation (no GT core) + + assign xcvr_gtpowergood_out = 1'b1; + + assign xcvr_qpll0lock_out = !gt_qpll0_reset && !gt_qpll0_pd; + assign xcvr_qpll0clk_out = 1'b0; + assign xcvr_qpll0refclk_out = xcvr_gtrefclk00_in; + + assign xcvr_qpll1lock_out = !gt_qpll1_reset && !gt_qpll0_pd; + assign xcvr_qpll1clk_out = 1'b0; + assign xcvr_qpll1refclk_out = xcvr_gtrefclk01_in; + + assign gt_tx_reset_done = !gt_tx_reset; + assign gt_userclk_tx_active = gt_tx_qpll_sel ? qpll1_lock : qpll0_lock; + assign gt_tx_pma_reset_done = gt_tx_reset_done; + assign gt_tx_prgdiv_reset_done = gt_tx_reset_done; + + assign gt_rx_reset_done = !gt_rx_reset; + assign gt_userclk_rx_active = gt_rx_qpll_sel ? qpll1_lock : qpll0_lock; + assign gt_rx_pma_reset_done = gt_rx_reset_done; + assign gt_rx_prgdiv_reset_done = gt_rx_reset_done; + assign gt_rx_cdr_lock = gt_rx_reset_done; + +end else if (HAS_COMMON && GT_TYPE == "GTY" && GT_USP) begin : xcvr + // UltraScale+ GTY (with common) + + taxi_eth_phy_25g_us_gty_ll_full + taxi_eth_phy_25g_us_gty_ll_full_inst ( + // Common + .gtpowergood_out(xcvr_gtpowergood_out), + + // PLL + .gtrefclk00_in(xcvr_gtrefclk00_in), + .qpll0lock_out(xcvr_qpll0lock_out), + .qpll0outclk_out(xcvr_qpll0clk_out), + .qpll0outrefclk_out(xcvr_qpll0refclk_out), + .gtrefclk01_in(xcvr_gtrefclk01_in), + .qpll1lock_out(xcvr_qpll1lock_out), + .qpll1outclk_out(xcvr_qpll1clk_out), + .qpll1outrefclk_out(xcvr_qpll1refclk_out), + + .qpll0pd_in(QPLL0_EXT_CTRL ? xcvr_qpll0pd_in : gt_qpll0_pd), + .qpll0reset_in(QPLL0_EXT_CTRL ? xcvr_qpll0reset_in : gt_qpll0_reset), + .qpll1pd_in(QPLL1_EXT_CTRL ? xcvr_qpll1pd_in : gt_qpll1_pd), + .qpll1reset_in(QPLL1_EXT_CTRL ? xcvr_qpll1reset_in : gt_qpll1_reset), + + .pcierateqpll0_in(QPLL0_EXT_CTRL ? xcvr_qpll0pcierate_in : 3'd0), + .pcierateqpll1_in(QPLL1_EXT_CTRL ? xcvr_qpll1pcierate_in : 3'd0), + + // Serial data + .gtytxp_out(xcvr_txp), + .gtytxn_out(xcvr_txn), + .gtyrxp_in(xcvr_rxp), + .gtyrxn_in(xcvr_rxn), + + // Transmit + .gtwiz_userclk_tx_reset_in(gt_tx_reset), + .gtwiz_userclk_tx_srcclk_out(), + .gtwiz_userclk_tx_usrclk_out(), + .gtwiz_userclk_tx_usrclk2_out(tx_clk), + .gtwiz_userclk_tx_active_out(gt_userclk_tx_active), + .gtwiz_reset_tx_done_in(tx_reset_done), + .gtwiz_buffbypass_tx_reset_in(1'b0), + .gtwiz_buffbypass_tx_start_user_in(1'b0), + .gtwiz_buffbypass_tx_done_out(), + .gtwiz_buffbypass_tx_error_out(), + .txpdelecidlemode_in(1'b1), + .txpd_in(gt_tx_pd ? 2'b11 : 2'b00), + .gttxreset_in(gt_tx_reset), + .txpmareset_in(gt_tx_pma_reset), + .txpcsreset_in(gt_tx_pcs_reset), + .txresetdone_out(gt_tx_reset_done), + .txpmaresetdone_out(gt_tx_pma_reset_done), + .txprogdivreset_in(gt_tx_prgdiv_reset), + .txprgdivresetdone_out(gt_tx_prgdiv_reset_done), + .txpllclksel_in(gt_tx_qpll_sel ? 2'b10 : 2'b11), + .txsysclksel_in(gt_tx_qpll_sel ? 2'b11 : 2'b10), + .txuserrdy_in(gt_tx_userrdy), + + .txpolarity_in(GT_TX_POLARITY), + .txelecidle_in(GT_TX_ELECIDLE), + .txinhibit_in(GT_TX_INHIBIT), + .txdiffctrl_in(GT_TX_DIFFCTRL), + .txmaincursor_in(GT_TX_MAINCURSOR), + .txprecursor_in(GT_TX_PRECURSOR), + .txpostcursor_in(GT_TX_POSTCURSOR), + + .gtwiz_userdata_tx_in(gt_txdata), + .txheader_in(gt_txheader), + .txsequence_in(gt_txsequence), + + // Receive + .gtwiz_userclk_rx_reset_in(gt_rx_reset), + .gtwiz_userclk_rx_srcclk_out(), + .gtwiz_userclk_rx_usrclk_out(), + .gtwiz_userclk_rx_usrclk2_out(rx_clk), + .gtwiz_userclk_rx_active_out(gt_userclk_rx_active), + .gtwiz_reset_rx_done_in(rx_reset_done), + .gtwiz_buffbypass_rx_reset_in(1'b0), + .gtwiz_buffbypass_rx_start_user_in(1'b0), + .gtwiz_buffbypass_rx_done_out(), + .gtwiz_buffbypass_rx_error_out(), + .rxpd_in(gt_rx_pd ? 2'b11 : 2'b00), + .gtrxreset_in(gt_rx_reset), + .rxpmareset_in(gt_rx_pma_reset), + .rxdfelpmreset_in(gt_rx_dfe_lpm_reset), + .eyescanreset_in(gt_rx_eyescan_reset), + .rxpcsreset_in(gt_rx_pcs_reset), + .rxresetdone_out(gt_rx_reset_done), + .rxpmaresetdone_out(gt_rx_pma_reset_done), + .rxprogdivreset_in(gt_rx_prgdiv_reset), + .rxprgdivresetdone_out(gt_rx_prgdiv_reset_done), + .rxpllclksel_in(gt_rx_qpll_sel ? 2'b10 : 2'b11), + .rxsysclksel_in(gt_rx_qpll_sel ? 2'b11 : 2'b10), + .rxuserrdy_in(gt_rx_userrdy), + + .rxcdrlock_out(gt_rx_cdr_lock), + .rxcdrhold_in(1'b0), + .rxcdrovrden_in(1'b0), + + .rxlpmen_in(gt_rx_lpm_en), + + .rxpolarity_in(GT_RX_POLARITY), + + .rxgearboxslip_in(gt_rxgearboxslip), + .gtwiz_userdata_rx_out(gt_rxdata), + .rxdatavalid_out(gt_rxdatavalid), + .rxheader_out(gt_rxheader), + .rxheadervalid_out(gt_rxheadervalid), + .rxstartofseq_out(gt_rxstartofseq) + ); + +end else if (HAS_COMMON && GT_TYPE == "GTH" && GT_USP) begin : xcvr + // UltraScale+ GTH (with common) + + taxi_eth_phy_25g_us_gth_ll_full + taxi_eth_phy_25g_us_gth_ll_full_inst ( + // Common + .gtpowergood_out(xcvr_gtpowergood_out), + + // PLL + .gtrefclk00_in(xcvr_gtrefclk00_in), + .qpll0lock_out(xcvr_qpll0lock_out), + .qpll0outclk_out(xcvr_qpll0clk_out), + .qpll0outrefclk_out(xcvr_qpll0refclk_out), + .gtrefclk01_in(xcvr_gtrefclk01_in), + .qpll1lock_out(xcvr_qpll1lock_out), + .qpll1outclk_out(xcvr_qpll1clk_out), + .qpll1outrefclk_out(xcvr_qpll1refclk_out), + + .qpll0pd_in(QPLL0_EXT_CTRL ? xcvr_qpll0pd_in : gt_qpll0_pd), + .qpll0reset_in(QPLL0_EXT_CTRL ? xcvr_qpll0reset_in : gt_qpll0_reset), + .qpll1pd_in(QPLL1_EXT_CTRL ? xcvr_qpll1pd_in : gt_qpll1_pd), + .qpll1reset_in(QPLL1_EXT_CTRL ? xcvr_qpll1reset_in : gt_qpll1_reset), + + .pcierateqpll0_in(QPLL0_EXT_CTRL ? xcvr_qpll0pcierate_in : 3'd0), + .pcierateqpll1_in(QPLL1_EXT_CTRL ? xcvr_qpll1pcierate_in : 3'd0), + + // Serial data + .gthtxp_out(xcvr_txp), + .gthtxn_out(xcvr_txn), + .gthrxp_in(xcvr_rxp), + .gthrxn_in(xcvr_rxn), + + // Transmit + .gtwiz_userclk_tx_reset_in(gt_tx_reset), + .gtwiz_userclk_tx_srcclk_out(), + .gtwiz_userclk_tx_usrclk_out(), + .gtwiz_userclk_tx_usrclk2_out(tx_clk), + .gtwiz_userclk_tx_active_out(gt_userclk_tx_active), + .gtwiz_reset_tx_done_in(tx_reset_done), + .gtwiz_buffbypass_tx_reset_in(1'b0), + .gtwiz_buffbypass_tx_start_user_in(1'b0), + .gtwiz_buffbypass_tx_done_out(), + .gtwiz_buffbypass_tx_error_out(), + .txpdelecidlemode_in(1'b1), + .txpd_in(gt_tx_pd ? 2'b11 : 2'b00), + .gttxreset_in(gt_tx_reset), + .txpmareset_in(gt_tx_pma_reset), + .txpcsreset_in(gt_tx_pcs_reset), + .txresetdone_out(gt_tx_reset_done), + .txpmaresetdone_out(gt_tx_pma_reset_done), + .txprogdivreset_in(gt_tx_prgdiv_reset), + .txprgdivresetdone_out(gt_tx_prgdiv_reset_done), + .txpllclksel_in(gt_tx_qpll_sel ? 2'b10 : 2'b11), + .txsysclksel_in(gt_tx_qpll_sel ? 2'b11 : 2'b10), + .txuserrdy_in(gt_tx_userrdy), + + .txpolarity_in(GT_TX_POLARITY), + .txelecidle_in(GT_TX_ELECIDLE), + .txinhibit_in(GT_TX_INHIBIT), + .txdiffctrl_in(GT_TX_DIFFCTRL), + .txmaincursor_in(GT_TX_MAINCURSOR), + .txprecursor_in(GT_TX_PRECURSOR), + .txpostcursor_in(GT_TX_POSTCURSOR), + + .gtwiz_userdata_tx_in(gt_txdata), + .txheader_in(gt_txheader), + .txsequence_in(gt_txsequence), + + // Receive + .gtwiz_userclk_rx_reset_in(gt_rx_reset), + .gtwiz_userclk_rx_srcclk_out(), + .gtwiz_userclk_rx_usrclk_out(), + .gtwiz_userclk_rx_usrclk2_out(rx_clk), + .gtwiz_userclk_rx_active_out(gt_userclk_rx_active), + .gtwiz_reset_rx_done_in(rx_reset_done), + .gtwiz_buffbypass_rx_reset_in(1'b0), + .gtwiz_buffbypass_rx_start_user_in(1'b0), + .gtwiz_buffbypass_rx_done_out(), + .gtwiz_buffbypass_rx_error_out(), + .rxpd_in(gt_rx_pd ? 2'b11 : 2'b00), + .gtrxreset_in(gt_rx_reset), + .rxpmareset_in(gt_rx_pma_reset), + .rxdfelpmreset_in(gt_rx_dfe_lpm_reset), + .eyescanreset_in(gt_rx_eyescan_reset), + .rxpcsreset_in(gt_rx_pcs_reset), + .rxresetdone_out(gt_rx_reset_done), + .rxpmaresetdone_out(gt_rx_pma_reset_done), + .rxprogdivreset_in(gt_rx_prgdiv_reset), + .rxprgdivresetdone_out(gt_rx_prgdiv_reset_done), + .rxpllclksel_in(gt_rx_qpll_sel ? 2'b10 : 2'b11), + .rxsysclksel_in(gt_rx_qpll_sel ? 2'b11 : 2'b10), + .rxuserrdy_in(gt_rx_userrdy), + + .rxcdrlock_out(gt_rx_cdr_lock), + .rxcdrhold_in(1'b0), + .rxcdrovrden_in(1'b0), + + .rxlpmen_in(gt_rx_lpm_en), + + .rxpolarity_in(GT_RX_POLARITY), + + .rxgearboxslip_in(gt_rxgearboxslip), + .gtwiz_userdata_rx_out(gt_rxdata), + .rxdatavalid_out(gt_rxdatavalid), + .rxheader_out(gt_rxheader), + .rxheadervalid_out(gt_rxheadervalid), + .rxstartofseq_out(gt_rxstartofseq) + ); + +end else if (HAS_COMMON && GT_TYPE == "GTY" && !GT_USP) begin : xcvr + // UltraScale GTY (with common) + + taxi_eth_phy_25g_us_gty_ll_full + taxi_eth_phy_25g_us_gty_ll_full_inst ( + // Common + .gtpowergood_out(xcvr_gtpowergood_out), + + // PLL + .gtrefclk00_in(xcvr_gtrefclk00_in), + .qpll0lock_out(xcvr_qpll0lock_out), + .qpll0outclk_out(xcvr_qpll0clk_out), + .qpll0outrefclk_out(xcvr_qpll0refclk_out), + .gtrefclk01_in(xcvr_gtrefclk01_in), + .qpll1lock_out(xcvr_qpll1lock_out), + .qpll1outclk_out(xcvr_qpll1clk_out), + .qpll1outrefclk_out(xcvr_qpll1refclk_out), + + .qpll0pd_in(QPLL0_EXT_CTRL ? xcvr_qpll0pd_in : gt_qpll0_pd), + .qpll0reset_in(QPLL0_EXT_CTRL ? xcvr_qpll0reset_in : gt_qpll0_reset), + .qpll1pd_in(QPLL1_EXT_CTRL ? xcvr_qpll1pd_in : gt_qpll1_pd), + .qpll1reset_in(QPLL1_EXT_CTRL ? xcvr_qpll1reset_in : gt_qpll1_reset), + + .qpllrsvd2_in(QPLL0_EXT_CTRL ? {2'd0, xcvr_qpll0pcierate_in} : 5'd0), // [2:0] : QPLL0 rate + .qpllrsvd3_in(QPLL1_EXT_CTRL ? {2'd0, xcvr_qpll1pcierate_in} : 5'd0), // [2:0] : QPLL1 rate + + // Serial data + .gtytxp_out(xcvr_txp), + .gtytxn_out(xcvr_txn), + .gtyrxp_in(xcvr_rxp), + .gtyrxn_in(xcvr_rxn), + + // Transmit + .gtwiz_userclk_tx_reset_in(gt_tx_reset), + .gtwiz_userclk_tx_srcclk_out(), + .gtwiz_userclk_tx_usrclk_out(), + .gtwiz_userclk_tx_usrclk2_out(tx_clk), + .gtwiz_userclk_tx_active_out(gt_userclk_tx_active), + .gtwiz_reset_tx_done_in(tx_reset_done), + .gtwiz_buffbypass_tx_reset_in(1'b0), + .gtwiz_buffbypass_tx_start_user_in(1'b0), + .gtwiz_buffbypass_tx_done_out(), + .gtwiz_buffbypass_tx_error_out(), + .txpdelecidlemode_in(1'b1), + .txpd_in(gt_tx_pd ? 2'b11 : 2'b00), + .gttxreset_in(gt_tx_reset), + .txpmareset_in(gt_tx_pma_reset), + .txpcsreset_in(gt_tx_pcs_reset), + .txresetdone_out(gt_tx_reset_done), + .txpmaresetdone_out(gt_tx_pma_reset_done), + .txprogdivreset_in(gt_tx_prgdiv_reset), + .txprgdivresetdone_out(gt_tx_prgdiv_reset_done), + .txpllclksel_in(gt_tx_qpll_sel ? 2'b10 : 2'b11), + .txsysclksel_in(gt_tx_qpll_sel ? 2'b11 : 2'b10), + .txuserrdy_in(gt_tx_userrdy), + + .txpolarity_in(GT_TX_POLARITY), + .txelecidle_in(GT_TX_ELECIDLE), + .txinhibit_in(GT_TX_INHIBIT), + .txdiffctrl_in(GT_TX_DIFFCTRL), + .txmaincursor_in(GT_TX_MAINCURSOR), + .txprecursor_in(GT_TX_PRECURSOR), + .txpostcursor_in(GT_TX_POSTCURSOR), + + .gtwiz_userdata_tx_in(gt_txdata), + .txheader_in(gt_txheader), + .txsequence_in(gt_txsequence), + + // Receive + .gtwiz_userclk_rx_reset_in(gt_rx_reset), + .gtwiz_userclk_rx_srcclk_out(), + .gtwiz_userclk_rx_usrclk_out(), + .gtwiz_userclk_rx_usrclk2_out(rx_clk), + .gtwiz_userclk_rx_active_out(gt_userclk_rx_active), + .gtwiz_reset_rx_done_in(rx_reset_done), + .gtwiz_buffbypass_rx_reset_in(1'b0), + .gtwiz_buffbypass_rx_start_user_in(1'b0), + .gtwiz_buffbypass_rx_done_out(), + .gtwiz_buffbypass_rx_error_out(), + .rxpd_in(gt_rx_pd ? 2'b11 : 2'b00), + .gtrxreset_in(gt_rx_reset), + .rxpmareset_in(gt_rx_pma_reset), + .rxdfelpmreset_in(gt_rx_dfe_lpm_reset), + .eyescanreset_in(gt_rx_eyescan_reset), + .rxpcsreset_in(gt_rx_pcs_reset), + .rxresetdone_out(gt_rx_reset_done), + .rxpmaresetdone_out(gt_rx_pma_reset_done), + .rxprogdivreset_in(gt_rx_prgdiv_reset), + .rxprgdivresetdone_out(gt_rx_prgdiv_reset_done), + .rxpllclksel_in(gt_rx_qpll_sel ? 2'b10 : 2'b11), + .rxsysclksel_in(gt_rx_qpll_sel ? 2'b11 : 2'b10), + .rxuserrdy_in(gt_rx_userrdy), + + .rxcdrlock_out(gt_rx_cdr_lock), + .rxcdrhold_in(1'b0), + .rxcdrovrden_in(1'b0), + + .rxlpmen_in(gt_rx_lpm_en), + + .rxpolarity_in(GT_RX_POLARITY), + + .rxgearboxslip_in(gt_rxgearboxslip), + .gtwiz_userdata_rx_out(gt_rxdata), + .rxdatavalid_out(gt_rxdatavalid), + .rxheader_out(gt_rxheader), + .rxheadervalid_out(gt_rxheadervalid), + .rxstartofseq_out(gt_rxstartofseq) + ); + +end else if (HAS_COMMON && GT_TYPE == "GTH" && !GT_USP) begin : xcvr + // UltraScale GTH (with common) + + taxi_eth_phy_25g_us_gth_ll_full + taxi_eth_phy_25g_us_gth_ll_full_inst ( + // Common + .gtpowergood_out(xcvr_gtpowergood_out), + + // PLL + .gtrefclk00_in(xcvr_gtrefclk00_in), + .qpll0lock_out(xcvr_qpll0lock_out), + .qpll0outclk_out(xcvr_qpll0clk_out), + .qpll0outrefclk_out(xcvr_qpll0refclk_out), + .gtrefclk01_in(xcvr_gtrefclk01_in), + .qpll1lock_out(xcvr_qpll1lock_out), + .qpll1outclk_out(xcvr_qpll1clk_out), + .qpll1outrefclk_out(xcvr_qpll1refclk_out), + + .qpll0pd_in(QPLL0_EXT_CTRL ? xcvr_qpll0pd_in : gt_qpll0_pd), + .qpll0reset_in(QPLL0_EXT_CTRL ? xcvr_qpll0reset_in : gt_qpll0_reset), + .qpll1pd_in(QPLL1_EXT_CTRL ? xcvr_qpll1pd_in : gt_qpll1_pd), + .qpll1reset_in(QPLL1_EXT_CTRL ? xcvr_qpll1reset_in : gt_qpll1_reset), + + .qpllrsvd2_in(QPLL0_EXT_CTRL ? {2'd0, xcvr_qpll0pcierate_in} : 5'd0), // [2:0] : QPLL0 rate + .qpllrsvd3_in(QPLL1_EXT_CTRL ? {2'd0, xcvr_qpll1pcierate_in} : 5'd0), // [2:0] : QPLL1 rate + + // Serial data + .gthtxp_out(xcvr_txp), + .gthtxn_out(xcvr_txn), + .gthrxp_in(xcvr_rxp), + .gthrxn_in(xcvr_rxn), + + // Transmit + .gtwiz_userclk_tx_reset_in(gt_tx_reset), + .gtwiz_userclk_tx_srcclk_out(), + .gtwiz_userclk_tx_usrclk_out(), + .gtwiz_userclk_tx_usrclk2_out(tx_clk), + .gtwiz_userclk_tx_active_out(gt_userclk_tx_active), + .gtwiz_reset_tx_done_in(tx_reset_done), + .gtwiz_buffbypass_tx_reset_in(1'b0), + .gtwiz_buffbypass_tx_start_user_in(1'b0), + .gtwiz_buffbypass_tx_done_out(), + .gtwiz_buffbypass_tx_error_out(), + .txpdelecidlemode_in(1'b1), + .txpd_in(gt_tx_pd ? 2'b11 : 2'b00), + .gttxreset_in(gt_tx_reset), + .txpmareset_in(gt_tx_pma_reset), + .txpcsreset_in(gt_tx_pcs_reset), + .txresetdone_out(gt_tx_reset_done), + .txpmaresetdone_out(gt_tx_pma_reset_done), + .txprogdivreset_in(gt_tx_prgdiv_reset), + .txprgdivresetdone_out(gt_tx_prgdiv_reset_done), + .txpllclksel_in(gt_tx_qpll_sel ? 2'b10 : 2'b11), + .txsysclksel_in(gt_tx_qpll_sel ? 2'b11 : 2'b10), + .txuserrdy_in(gt_tx_userrdy), + + .txpolarity_in(GT_TX_POLARITY), + .txelecidle_in(GT_TX_ELECIDLE), + .txinhibit_in(GT_TX_INHIBIT), + .txdiffctrl_in(GT_TX_DIFFCTRL), + .txmaincursor_in(GT_TX_MAINCURSOR), + .txprecursor_in(GT_TX_PRECURSOR), + .txpostcursor_in(GT_TX_POSTCURSOR), + + .gtwiz_userdata_tx_in(gt_txdata), + .txheader_in(gt_txheader), + .txsequence_in(gt_txsequence), + + // Receive + .gtwiz_userclk_rx_reset_in(gt_rx_reset), + .gtwiz_userclk_rx_srcclk_out(), + .gtwiz_userclk_rx_usrclk_out(), + .gtwiz_userclk_rx_usrclk2_out(rx_clk), + .gtwiz_userclk_rx_active_out(gt_userclk_rx_active), + .gtwiz_reset_rx_done_in(rx_reset_done), + .gtwiz_buffbypass_rx_reset_in(1'b0), + .gtwiz_buffbypass_rx_start_user_in(1'b0), + .gtwiz_buffbypass_rx_done_out(), + .gtwiz_buffbypass_rx_error_out(), + .rxpd_in(gt_rx_pd ? 2'b11 : 2'b00), + .gtrxreset_in(gt_rx_reset), + .rxpmareset_in(gt_rx_pma_reset), + .rxdfelpmreset_in(gt_rx_dfe_lpm_reset), + .eyescanreset_in(gt_rx_eyescan_reset), + .rxpcsreset_in(gt_rx_pcs_reset), + .rxresetdone_out(gt_rx_reset_done), + .rxpmaresetdone_out(gt_rx_pma_reset_done), + .rxprogdivreset_in(gt_rx_prgdiv_reset), + .rxprgdivresetdone_out(gt_rx_prgdiv_reset_done), + .rxpllclksel_in(gt_rx_qpll_sel ? 2'b10 : 2'b11), + .rxsysclksel_in(gt_rx_qpll_sel ? 2'b11 : 2'b10), + .rxuserrdy_in(gt_rx_userrdy), + + .rxcdrlock_out(gt_rx_cdr_lock), + .rxcdrhold_in(1'b0), + .rxcdrovrden_in(1'b0), + + .rxlpmen_in(gt_rx_lpm_en), + + .rxpolarity_in(GT_RX_POLARITY), + + .rxgearboxslip_in(gt_rxgearboxslip), + .gtwiz_userdata_rx_out(gt_rxdata), + .rxdatavalid_out(gt_rxdatavalid), + .rxheader_out(gt_rxheader), + .rxheadervalid_out(gt_rxheadervalid), + .rxstartofseq_out(gt_rxstartofseq) + ); + +end else if (!HAS_COMMON && GT_TYPE == "GTY") begin : xcvr + // UltraScale/UltraScale+ GTY (channel only) + + taxi_eth_phy_25g_us_gty_ll_ch + taxi_eth_phy_25g_us_gty_ll_ch_inst ( + // Common + .gtpowergood_out(xcvr_gtpowergood_out), + + // PLL + .qpll0clk_in(xcvr_qpll0clk_in), + .qpll0refclk_in(xcvr_qpll0refclk_in), + .qpll1clk_in(xcvr_qpll1clk_in), + .qpll1refclk_in(xcvr_qpll1refclk_in), + + // Serial data + .gtytxp_out(xcvr_txp), + .gtytxn_out(xcvr_txn), + .gtyrxp_in(xcvr_rxp), + .gtyrxn_in(xcvr_rxn), + + // Transmit + .gtwiz_userclk_tx_reset_in(gt_tx_reset), + .gtwiz_userclk_tx_srcclk_out(), + .gtwiz_userclk_tx_usrclk_out(), + .gtwiz_userclk_tx_usrclk2_out(tx_clk), + .gtwiz_userclk_tx_active_out(gt_userclk_tx_active), + .gtwiz_reset_tx_done_in(tx_reset_done), + .gtwiz_buffbypass_tx_reset_in(1'b0), + .gtwiz_buffbypass_tx_start_user_in(1'b0), + .gtwiz_buffbypass_tx_done_out(), + .gtwiz_buffbypass_tx_error_out(), + .txpdelecidlemode_in(1'b1), + .txpd_in(gt_tx_pd ? 2'b11 : 2'b00), + .gttxreset_in(gt_tx_reset), + .txpmareset_in(gt_tx_pma_reset), + .txpcsreset_in(gt_tx_pcs_reset), + .txresetdone_out(gt_tx_reset_done), + .txpmaresetdone_out(gt_tx_pma_reset_done), + .txprogdivreset_in(gt_tx_prgdiv_reset), + .txprgdivresetdone_out(gt_tx_prgdiv_reset_done), + .txpllclksel_in(gt_tx_qpll_sel ? 2'b10 : 2'b11), + .txsysclksel_in(gt_tx_qpll_sel ? 2'b11 : 2'b10), + .txuserrdy_in(gt_tx_userrdy), + + .txpolarity_in(GT_TX_POLARITY), + .txelecidle_in(GT_TX_ELECIDLE), + .txinhibit_in(GT_TX_INHIBIT), + .txdiffctrl_in(GT_TX_DIFFCTRL), + .txmaincursor_in(GT_TX_MAINCURSOR), + .txprecursor_in(GT_TX_PRECURSOR), + .txpostcursor_in(GT_TX_POSTCURSOR), + + .gtwiz_userdata_tx_in(gt_txdata), + .txheader_in(gt_txheader), + .txsequence_in(gt_txsequence), + + // Receive + .gtwiz_userclk_rx_reset_in(gt_rx_reset), + .gtwiz_userclk_rx_srcclk_out(), + .gtwiz_userclk_rx_usrclk_out(), + .gtwiz_userclk_rx_usrclk2_out(rx_clk), + .gtwiz_userclk_rx_active_out(gt_userclk_rx_active), + .gtwiz_reset_rx_done_in(rx_reset_done), + .gtwiz_buffbypass_rx_reset_in(1'b0), + .gtwiz_buffbypass_rx_start_user_in(1'b0), + .gtwiz_buffbypass_rx_done_out(), + .gtwiz_buffbypass_rx_error_out(), + .rxpd_in(gt_rx_pd ? 2'b11 : 2'b00), + .gtrxreset_in(gt_rx_reset), + .rxpmareset_in(gt_rx_pma_reset), + .rxdfelpmreset_in(gt_rx_dfe_lpm_reset), + .eyescanreset_in(gt_rx_eyescan_reset), + .rxpcsreset_in(gt_rx_pcs_reset), + .rxresetdone_out(gt_rx_reset_done), + .rxpmaresetdone_out(gt_rx_pma_reset_done), + .rxprogdivreset_in(gt_rx_prgdiv_reset), + .rxprgdivresetdone_out(gt_rx_prgdiv_reset_done), + .rxpllclksel_in(gt_rx_qpll_sel ? 2'b10 : 2'b11), + .rxsysclksel_in(gt_rx_qpll_sel ? 2'b11 : 2'b10), + .rxuserrdy_in(gt_rx_userrdy), + + .rxcdrlock_out(gt_rx_cdr_lock), + .rxcdrhold_in(1'b0), + .rxcdrovrden_in(1'b0), + + .rxlpmen_in(gt_rx_lpm_en), + + .rxpolarity_in(GT_RX_POLARITY), + + .rxgearboxslip_in(gt_rxgearboxslip), + .gtwiz_userdata_rx_out(gt_rxdata), + .rxdatavalid_out(gt_rxdatavalid), + .rxheader_out(gt_rxheader), + .rxheadervalid_out(gt_rxheadervalid), + .rxstartofseq_out(gt_rxstartofseq) + ); + + assign xcvr_qpll0lock_out = 1'b0; + assign xcvr_qpll0clk_out = 1'b0; + assign xcvr_qpll0refclk_out = 1'b0; + +end else if (!HAS_COMMON && GT_TYPE == "GTH") begin : xcvr + // UltraScale/UltraScale+ GTY (channel only) + + taxi_eth_phy_25g_us_gth_ll_ch + taxi_eth_phy_25g_us_gth_ll_ch_inst ( + // Common + .gtpowergood_out(xcvr_gtpowergood_out), + + // PLL + .qpll0clk_in(xcvr_qpll0clk_in), + .qpll0refclk_in(xcvr_qpll0refclk_in), + .qpll1clk_in(xcvr_qpll1clk_in), + .qpll1refclk_in(xcvr_qpll1refclk_in), + + // Serial data + .gthtxp_out(xcvr_txp), + .gthtxn_out(xcvr_txn), + .gthrxp_in(xcvr_rxp), + .gthrxn_in(xcvr_rxn), + + // Transmit + .gtwiz_userclk_tx_reset_in(gt_tx_reset), + .gtwiz_userclk_tx_srcclk_out(), + .gtwiz_userclk_tx_usrclk_out(), + .gtwiz_userclk_tx_usrclk2_out(tx_clk), + .gtwiz_userclk_tx_active_out(gt_userclk_tx_active), + .gtwiz_reset_tx_done_in(tx_reset_done), + .gtwiz_buffbypass_tx_reset_in(1'b0), + .gtwiz_buffbypass_tx_start_user_in(1'b0), + .gtwiz_buffbypass_tx_done_out(), + .gtwiz_buffbypass_tx_error_out(), + .txpdelecidlemode_in(1'b1), + .txpd_in(gt_tx_pd ? 2'b11 : 2'b00), + .gttxreset_in(gt_tx_reset), + .txpmareset_in(gt_tx_pma_reset), + .txpcsreset_in(gt_tx_pcs_reset), + .txresetdone_out(gt_tx_reset_done), + .txpmaresetdone_out(gt_tx_pma_reset_done), + .txprogdivreset_in(gt_tx_prgdiv_reset), + .txprgdivresetdone_out(gt_tx_prgdiv_reset_done), + .txpllclksel_in(gt_tx_qpll_sel ? 2'b10 : 2'b11), + .txsysclksel_in(gt_tx_qpll_sel ? 2'b11 : 2'b10), + .txuserrdy_in(gt_tx_userrdy), + + .txpolarity_in(GT_TX_POLARITY), + .txelecidle_in(GT_TX_ELECIDLE), + .txinhibit_in(GT_TX_INHIBIT), + .txdiffctrl_in(GT_TX_DIFFCTRL), + .txmaincursor_in(GT_TX_MAINCURSOR), + .txprecursor_in(GT_TX_PRECURSOR), + .txpostcursor_in(GT_TX_POSTCURSOR), + + .gtwiz_userdata_tx_in(gt_txdata), + .txheader_in(gt_txheader), + .txsequence_in(gt_txsequence), + + // Receive + .gtwiz_userclk_rx_reset_in(gt_rx_reset), + .gtwiz_userclk_rx_srcclk_out(), + .gtwiz_userclk_rx_usrclk_out(), + .gtwiz_userclk_rx_usrclk2_out(rx_clk), + .gtwiz_userclk_rx_active_out(gt_userclk_rx_active), + .gtwiz_reset_rx_done_in(rx_reset_done), + .gtwiz_buffbypass_rx_reset_in(1'b0), + .gtwiz_buffbypass_rx_start_user_in(1'b0), + .gtwiz_buffbypass_rx_done_out(), + .gtwiz_buffbypass_rx_error_out(), + .rxpd_in(gt_rx_pd ? 2'b11 : 2'b00), + .gtrxreset_in(gt_rx_reset), + .rxpmareset_in(gt_rx_pma_reset), + .rxdfelpmreset_in(gt_rx_dfe_lpm_reset), + .eyescanreset_in(gt_rx_eyescan_reset), + .rxpcsreset_in(gt_rx_pcs_reset), + .rxresetdone_out(gt_rx_reset_done), + .rxpmaresetdone_out(gt_rx_pma_reset_done), + .rxprogdivreset_in(gt_rx_prgdiv_reset), + .rxprgdivresetdone_out(gt_rx_prgdiv_reset_done), + .rxpllclksel_in(gt_rx_qpll_sel ? 2'b10 : 2'b11), + .rxsysclksel_in(gt_rx_qpll_sel ? 2'b11 : 2'b10), + .rxuserrdy_in(gt_rx_userrdy), + + .rxcdrlock_out(gt_rx_cdr_lock), + .rxcdrhold_in(1'b0), + .rxcdrovrden_in(1'b0), + + .rxlpmen_in(gt_rx_lpm_en), + + .rxpolarity_in(GT_RX_POLARITY), + + .rxgearboxslip_in(gt_rxgearboxslip), + .gtwiz_userdata_rx_out(gt_rxdata), + .rxdatavalid_out(gt_rxdatavalid), + .rxheader_out(gt_rxheader), + .rxheadervalid_out(gt_rxheadervalid), + .rxstartofseq_out(gt_rxstartofseq) + ); + + assign xcvr_qpll0lock_out = 1'b0; + assign xcvr_qpll0clk_out = 1'b0; + assign xcvr_qpll0refclk_out = 1'b0; + +end else begin + + $fatal(0, "Error: invalid configuration (%m)"); + +end + +endmodule + +`resetall diff --git a/src/eth/rtl/us/taxi_eth_phy_25g_us_gth_10g_156.tcl b/src/eth/rtl/us/taxi_eth_phy_25g_us_gth_10g_156.tcl index fcedb7c..2f13481 100644 --- a/src/eth/rtl/us/taxi_eth_phy_25g_us_gth_10g_156.tcl +++ b/src/eth/rtl/us/taxi_eth_phy_25g_us_gth_10g_156.tcl @@ -35,8 +35,8 @@ if {[string first uplus [get_property FAMILY [get_property PART [current_project lappend extra_pll_ports qpllrsvd2_in qpllrsvd3_in } # channel reset -lappend extra_ports gttxreset_in txuserrdy_in txpmareset_in txpcsreset_in txresetdone_out txpmaresetdone_out -lappend extra_ports gtrxreset_in rxuserrdy_in rxpmareset_in rxdfelpmreset_in eyescanreset_in rxpcsreset_in rxresetdone_out rxpmaresetdone_out +lappend extra_ports gttxreset_in txuserrdy_in txpmareset_in txpcsreset_in txprogdivreset_in txresetdone_out txpmaresetdone_out txprgdivresetdone_out +lappend extra_ports gtrxreset_in rxuserrdy_in rxpmareset_in rxdfelpmreset_in eyescanreset_in rxpcsreset_in rxprogdivreset_in rxresetdone_out rxpmaresetdone_out rxprgdivresetdone_out # channel power down lappend extra_ports txpd_in txpdelecidlemode_in rxpd_in # channel clock selection @@ -91,6 +91,14 @@ proc create_gtwizard_ip {name preset config} { set_property -dict $config_list $ip } +# normal latency (async gearbox) +dict set config TX_DATA_ENCODING {64B66B_ASYNC} +dict set config TX_BUFFER_MODE {1} +dict set config TX_OUTCLK_SOURCE {TXPROGDIVCLK} +dict set config RX_DATA_DECODING {64B66B_ASYNC} +dict set config RX_BUFFER_MODE {1} +dict set config RX_OUTCLK_SOURCE {RXPROGDIVCLK} + # variant with channel and common dict set config ENABLE_OPTIONAL_PORTS [concat $extra_pll_ports $extra_ports] dict set config LOCATE_COMMON {CORE} @@ -101,4 +109,24 @@ create_gtwizard_ip "${base_name}_full" $preset $config dict set config ENABLE_OPTIONAL_PORTS $extra_ports dict set config LOCATE_COMMON {EXAMPLE_DESIGN} -create_gtwizard_ip "${base_name}_channel" $preset $config +create_gtwizard_ip "${base_name}_ch" $preset $config + +# low latency (async gearbox with buffer bypass) +dict set config TX_DATA_ENCODING {64B66B} +dict set config TX_BUFFER_MODE {0} +dict set config TX_OUTCLK_SOURCE {TXPROGDIVCLK} +dict set config RX_DATA_DECODING {64B66B} +dict set config RX_BUFFER_MODE {0} +dict set config RX_OUTCLK_SOURCE {RXOUTCLKPMA} + +# variant with channel and common +dict set config ENABLE_OPTIONAL_PORTS [concat $extra_pll_ports $extra_ports] +dict set config LOCATE_COMMON {CORE} + +create_gtwizard_ip "${base_name}_ll_full" $preset $config + +# variant with channel only +dict set config ENABLE_OPTIONAL_PORTS $extra_ports +dict set config LOCATE_COMMON {EXAMPLE_DESIGN} + +create_gtwizard_ip "${base_name}_ll_ch" $preset $config diff --git a/src/eth/rtl/us/taxi_eth_phy_25g_us_gth_10g_161.tcl b/src/eth/rtl/us/taxi_eth_phy_25g_us_gth_10g_161.tcl index 03f2e0c..011edc2 100644 --- a/src/eth/rtl/us/taxi_eth_phy_25g_us_gth_10g_161.tcl +++ b/src/eth/rtl/us/taxi_eth_phy_25g_us_gth_10g_161.tcl @@ -35,8 +35,8 @@ if {[string first uplus [get_property FAMILY [get_property PART [current_project lappend extra_pll_ports qpllrsvd2_in qpllrsvd3_in } # channel reset -lappend extra_ports gttxreset_in txuserrdy_in txpmareset_in txpcsreset_in txresetdone_out txpmaresetdone_out -lappend extra_ports gtrxreset_in rxuserrdy_in rxpmareset_in rxdfelpmreset_in eyescanreset_in rxpcsreset_in rxresetdone_out rxpmaresetdone_out +lappend extra_ports gttxreset_in txuserrdy_in txpmareset_in txpcsreset_in txprogdivreset_in txresetdone_out txpmaresetdone_out txprgdivresetdone_out +lappend extra_ports gtrxreset_in rxuserrdy_in rxpmareset_in rxdfelpmreset_in eyescanreset_in rxpcsreset_in rxprogdivreset_in rxresetdone_out rxpmaresetdone_out rxprgdivresetdone_out # channel power down lappend extra_ports txpd_in txpdelecidlemode_in rxpd_in # channel clock selection @@ -91,6 +91,14 @@ proc create_gtwizard_ip {name preset config} { set_property -dict $config_list $ip } +# normal latency (async gearbox) +dict set config TX_DATA_ENCODING {64B66B_ASYNC} +dict set config TX_BUFFER_MODE {1} +dict set config TX_OUTCLK_SOURCE {TXPROGDIVCLK} +dict set config RX_DATA_DECODING {64B66B_ASYNC} +dict set config RX_BUFFER_MODE {1} +dict set config RX_OUTCLK_SOURCE {RXPROGDIVCLK} + # variant with channel and common dict set config ENABLE_OPTIONAL_PORTS [concat $extra_pll_ports $extra_ports] dict set config LOCATE_COMMON {CORE} @@ -101,4 +109,24 @@ create_gtwizard_ip "${base_name}_full" $preset $config dict set config ENABLE_OPTIONAL_PORTS $extra_ports dict set config LOCATE_COMMON {EXAMPLE_DESIGN} -create_gtwizard_ip "${base_name}_channel" $preset $config +create_gtwizard_ip "${base_name}_ch" $preset $config + +# low latency (async gearbox with buffer bypass) +dict set config TX_DATA_ENCODING {64B66B} +dict set config TX_BUFFER_MODE {0} +dict set config TX_OUTCLK_SOURCE {TXPROGDIVCLK} +dict set config RX_DATA_DECODING {64B66B} +dict set config RX_BUFFER_MODE {0} +dict set config RX_OUTCLK_SOURCE {RXOUTCLKPMA} + +# variant with channel and common +dict set config ENABLE_OPTIONAL_PORTS [concat $extra_pll_ports $extra_ports] +dict set config LOCATE_COMMON {CORE} + +create_gtwizard_ip "${base_name}_ll_full" $preset $config + +# variant with channel only +dict set config ENABLE_OPTIONAL_PORTS $extra_ports +dict set config LOCATE_COMMON {EXAMPLE_DESIGN} + +create_gtwizard_ip "${base_name}_ll_ch" $preset $config diff --git a/src/eth/rtl/us/taxi_eth_phy_25g_us_gth_10g_322.tcl b/src/eth/rtl/us/taxi_eth_phy_25g_us_gth_10g_322.tcl index 10c1412..bd98dbb 100644 --- a/src/eth/rtl/us/taxi_eth_phy_25g_us_gth_10g_322.tcl +++ b/src/eth/rtl/us/taxi_eth_phy_25g_us_gth_10g_322.tcl @@ -35,8 +35,8 @@ if {[string first uplus [get_property FAMILY [get_property PART [current_project lappend extra_pll_ports qpllrsvd2_in qpllrsvd3_in } # channel reset -lappend extra_ports gttxreset_in txuserrdy_in txpmareset_in txpcsreset_in txresetdone_out txpmaresetdone_out -lappend extra_ports gtrxreset_in rxuserrdy_in rxpmareset_in rxdfelpmreset_in eyescanreset_in rxpcsreset_in rxresetdone_out rxpmaresetdone_out +lappend extra_ports gttxreset_in txuserrdy_in txpmareset_in txpcsreset_in txprogdivreset_in txresetdone_out txpmaresetdone_out txprgdivresetdone_out +lappend extra_ports gtrxreset_in rxuserrdy_in rxpmareset_in rxdfelpmreset_in eyescanreset_in rxpcsreset_in rxprogdivreset_in rxresetdone_out rxpmaresetdone_out rxprgdivresetdone_out # channel power down lappend extra_ports txpd_in txpdelecidlemode_in rxpd_in # channel clock selection @@ -91,6 +91,14 @@ proc create_gtwizard_ip {name preset config} { set_property -dict $config_list $ip } +# normal latency (async gearbox) +dict set config TX_DATA_ENCODING {64B66B_ASYNC} +dict set config TX_BUFFER_MODE {1} +dict set config TX_OUTCLK_SOURCE {TXPROGDIVCLK} +dict set config RX_DATA_DECODING {64B66B_ASYNC} +dict set config RX_BUFFER_MODE {1} +dict set config RX_OUTCLK_SOURCE {RXPROGDIVCLK} + # variant with channel and common dict set config ENABLE_OPTIONAL_PORTS [concat $extra_pll_ports $extra_ports] dict set config LOCATE_COMMON {CORE} @@ -101,4 +109,24 @@ create_gtwizard_ip "${base_name}_full" $preset $config dict set config ENABLE_OPTIONAL_PORTS $extra_ports dict set config LOCATE_COMMON {EXAMPLE_DESIGN} -create_gtwizard_ip "${base_name}_channel" $preset $config +create_gtwizard_ip "${base_name}_ch" $preset $config + +# low latency (async gearbox with buffer bypass) +dict set config TX_DATA_ENCODING {64B66B} +dict set config TX_BUFFER_MODE {0} +dict set config TX_OUTCLK_SOURCE {TXPROGDIVCLK} +dict set config RX_DATA_DECODING {64B66B} +dict set config RX_BUFFER_MODE {0} +dict set config RX_OUTCLK_SOURCE {RXOUTCLKPMA} + +# variant with channel and common +dict set config ENABLE_OPTIONAL_PORTS [concat $extra_pll_ports $extra_ports] +dict set config LOCATE_COMMON {CORE} + +create_gtwizard_ip "${base_name}_ll_full" $preset $config + +# variant with channel only +dict set config ENABLE_OPTIONAL_PORTS $extra_ports +dict set config LOCATE_COMMON {EXAMPLE_DESIGN} + +create_gtwizard_ip "${base_name}_ll_ch" $preset $config diff --git a/src/eth/rtl/us/taxi_eth_phy_25g_us_gty_10g_156.tcl b/src/eth/rtl/us/taxi_eth_phy_25g_us_gty_10g_156.tcl index 054c8c4..277c77a 100644 --- a/src/eth/rtl/us/taxi_eth_phy_25g_us_gty_10g_156.tcl +++ b/src/eth/rtl/us/taxi_eth_phy_25g_us_gty_10g_156.tcl @@ -35,8 +35,8 @@ if {[string first uplus [get_property FAMILY [get_property PART [current_project lappend extra_pll_ports qpllrsvd2_in qpllrsvd3_in } # channel reset -lappend extra_ports gttxreset_in txuserrdy_in txpmareset_in txpcsreset_in txresetdone_out txpmaresetdone_out -lappend extra_ports gtrxreset_in rxuserrdy_in rxpmareset_in rxdfelpmreset_in eyescanreset_in rxpcsreset_in rxresetdone_out rxpmaresetdone_out +lappend extra_ports gttxreset_in txuserrdy_in txpmareset_in txpcsreset_in txprogdivreset_in txresetdone_out txpmaresetdone_out txprgdivresetdone_out +lappend extra_ports gtrxreset_in rxuserrdy_in rxpmareset_in rxdfelpmreset_in eyescanreset_in rxpcsreset_in rxprogdivreset_in rxresetdone_out rxpmaresetdone_out rxprgdivresetdone_out # channel power down lappend extra_ports txpd_in txpdelecidlemode_in rxpd_in # channel clock selection @@ -91,6 +91,14 @@ proc create_gtwizard_ip {name preset config} { set_property -dict $config_list $ip } +# normal latency (async gearbox) +dict set config TX_DATA_ENCODING {64B66B_ASYNC} +dict set config TX_BUFFER_MODE {1} +dict set config TX_OUTCLK_SOURCE {TXPROGDIVCLK} +dict set config RX_DATA_DECODING {64B66B_ASYNC} +dict set config RX_BUFFER_MODE {1} +dict set config RX_OUTCLK_SOURCE {RXPROGDIVCLK} + # variant with channel and common dict set config ENABLE_OPTIONAL_PORTS [concat $extra_pll_ports $extra_ports] dict set config LOCATE_COMMON {CORE} @@ -101,4 +109,24 @@ create_gtwizard_ip "${base_name}_full" $preset $config dict set config ENABLE_OPTIONAL_PORTS $extra_ports dict set config LOCATE_COMMON {EXAMPLE_DESIGN} -create_gtwizard_ip "${base_name}_channel" $preset $config +create_gtwizard_ip "${base_name}_ch" $preset $config + +# low latency (async gearbox with buffer bypass) +dict set config TX_DATA_ENCODING {64B66B} +dict set config TX_BUFFER_MODE {0} +dict set config TX_OUTCLK_SOURCE {TXPROGDIVCLK} +dict set config RX_DATA_DECODING {64B66B} +dict set config RX_BUFFER_MODE {0} +dict set config RX_OUTCLK_SOURCE {RXOUTCLKPMA} + +# variant with channel and common +dict set config ENABLE_OPTIONAL_PORTS [concat $extra_pll_ports $extra_ports] +dict set config LOCATE_COMMON {CORE} + +create_gtwizard_ip "${base_name}_ll_full" $preset $config + +# variant with channel only +dict set config ENABLE_OPTIONAL_PORTS $extra_ports +dict set config LOCATE_COMMON {EXAMPLE_DESIGN} + +create_gtwizard_ip "${base_name}_ll_ch" $preset $config diff --git a/src/eth/rtl/us/taxi_eth_phy_25g_us_gty_10g_161.tcl b/src/eth/rtl/us/taxi_eth_phy_25g_us_gty_10g_161.tcl index ade0dd0..b5319fb 100644 --- a/src/eth/rtl/us/taxi_eth_phy_25g_us_gty_10g_161.tcl +++ b/src/eth/rtl/us/taxi_eth_phy_25g_us_gty_10g_161.tcl @@ -35,8 +35,8 @@ if {[string first uplus [get_property FAMILY [get_property PART [current_project lappend extra_pll_ports qpllrsvd2_in qpllrsvd3_in } # channel reset -lappend extra_ports gttxreset_in txuserrdy_in txpmareset_in txpcsreset_in txresetdone_out txpmaresetdone_out -lappend extra_ports gtrxreset_in rxuserrdy_in rxpmareset_in rxdfelpmreset_in eyescanreset_in rxpcsreset_in rxresetdone_out rxpmaresetdone_out +lappend extra_ports gttxreset_in txuserrdy_in txpmareset_in txpcsreset_in txprogdivreset_in txresetdone_out txpmaresetdone_out txprgdivresetdone_out +lappend extra_ports gtrxreset_in rxuserrdy_in rxpmareset_in rxdfelpmreset_in eyescanreset_in rxpcsreset_in rxprogdivreset_in rxresetdone_out rxpmaresetdone_out rxprgdivresetdone_out # channel power down lappend extra_ports txpd_in txpdelecidlemode_in rxpd_in # channel clock selection @@ -91,6 +91,14 @@ proc create_gtwizard_ip {name preset config} { set_property -dict $config_list $ip } +# normal latency (async gearbox) +dict set config TX_DATA_ENCODING {64B66B_ASYNC} +dict set config TX_BUFFER_MODE {1} +dict set config TX_OUTCLK_SOURCE {TXPROGDIVCLK} +dict set config RX_DATA_DECODING {64B66B_ASYNC} +dict set config RX_BUFFER_MODE {1} +dict set config RX_OUTCLK_SOURCE {RXPROGDIVCLK} + # variant with channel and common dict set config ENABLE_OPTIONAL_PORTS [concat $extra_pll_ports $extra_ports] dict set config LOCATE_COMMON {CORE} @@ -101,4 +109,24 @@ create_gtwizard_ip "${base_name}_full" $preset $config dict set config ENABLE_OPTIONAL_PORTS $extra_ports dict set config LOCATE_COMMON {EXAMPLE_DESIGN} -create_gtwizard_ip "${base_name}_channel" $preset $config +create_gtwizard_ip "${base_name}_ch" $preset $config + +# low latency (async gearbox with buffer bypass) +dict set config TX_DATA_ENCODING {64B66B} +dict set config TX_BUFFER_MODE {0} +dict set config TX_OUTCLK_SOURCE {TXPROGDIVCLK} +dict set config RX_DATA_DECODING {64B66B} +dict set config RX_BUFFER_MODE {0} +dict set config RX_OUTCLK_SOURCE {RXOUTCLKPMA} + +# variant with channel and common +dict set config ENABLE_OPTIONAL_PORTS [concat $extra_pll_ports $extra_ports] +dict set config LOCATE_COMMON {CORE} + +create_gtwizard_ip "${base_name}_ll_full" $preset $config + +# variant with channel only +dict set config ENABLE_OPTIONAL_PORTS $extra_ports +dict set config LOCATE_COMMON {EXAMPLE_DESIGN} + +create_gtwizard_ip "${base_name}_ll_ch" $preset $config diff --git a/src/eth/rtl/us/taxi_eth_phy_25g_us_gty_10g_322.tcl b/src/eth/rtl/us/taxi_eth_phy_25g_us_gty_10g_322.tcl index 3f85c54..f71bbc9 100644 --- a/src/eth/rtl/us/taxi_eth_phy_25g_us_gty_10g_322.tcl +++ b/src/eth/rtl/us/taxi_eth_phy_25g_us_gty_10g_322.tcl @@ -35,8 +35,8 @@ if {[string first uplus [get_property FAMILY [get_property PART [current_project lappend extra_pll_ports qpllrsvd2_in qpllrsvd3_in } # channel reset -lappend extra_ports gttxreset_in txuserrdy_in txpmareset_in txpcsreset_in txresetdone_out txpmaresetdone_out -lappend extra_ports gtrxreset_in rxuserrdy_in rxpmareset_in rxdfelpmreset_in eyescanreset_in rxpcsreset_in rxresetdone_out rxpmaresetdone_out +lappend extra_ports gttxreset_in txuserrdy_in txpmareset_in txpcsreset_in txprogdivreset_in txresetdone_out txpmaresetdone_out txprgdivresetdone_out +lappend extra_ports gtrxreset_in rxuserrdy_in rxpmareset_in rxdfelpmreset_in eyescanreset_in rxpcsreset_in rxprogdivreset_in rxresetdone_out rxpmaresetdone_out rxprgdivresetdone_out # channel power down lappend extra_ports txpd_in txpdelecidlemode_in rxpd_in # channel clock selection @@ -91,6 +91,14 @@ proc create_gtwizard_ip {name preset config} { set_property -dict $config_list $ip } +# normal latency (async gearbox) +dict set config TX_DATA_ENCODING {64B66B_ASYNC} +dict set config TX_BUFFER_MODE {1} +dict set config TX_OUTCLK_SOURCE {TXPROGDIVCLK} +dict set config RX_DATA_DECODING {64B66B_ASYNC} +dict set config RX_BUFFER_MODE {1} +dict set config RX_OUTCLK_SOURCE {RXPROGDIVCLK} + # variant with channel and common dict set config ENABLE_OPTIONAL_PORTS [concat $extra_pll_ports $extra_ports] dict set config LOCATE_COMMON {CORE} @@ -101,4 +109,24 @@ create_gtwizard_ip "${base_name}_full" $preset $config dict set config ENABLE_OPTIONAL_PORTS $extra_ports dict set config LOCATE_COMMON {EXAMPLE_DESIGN} -create_gtwizard_ip "${base_name}_channel" $preset $config +create_gtwizard_ip "${base_name}_ch" $preset $config + +# low latency (async gearbox with buffer bypass) +dict set config TX_DATA_ENCODING {64B66B} +dict set config TX_BUFFER_MODE {0} +dict set config TX_OUTCLK_SOURCE {TXPROGDIVCLK} +dict set config RX_DATA_DECODING {64B66B} +dict set config RX_BUFFER_MODE {0} +dict set config RX_OUTCLK_SOURCE {RXOUTCLKPMA} + +# variant with channel and common +dict set config ENABLE_OPTIONAL_PORTS [concat $extra_pll_ports $extra_ports] +dict set config LOCATE_COMMON {CORE} + +create_gtwizard_ip "${base_name}_ll_full" $preset $config + +# variant with channel only +dict set config ENABLE_OPTIONAL_PORTS $extra_ports +dict set config LOCATE_COMMON {EXAMPLE_DESIGN} + +create_gtwizard_ip "${base_name}_ll_ch" $preset $config diff --git a/src/eth/rtl/us/taxi_eth_phy_25g_us_gty_25g_156.tcl b/src/eth/rtl/us/taxi_eth_phy_25g_us_gty_25g_156.tcl index 2399e22..6014181 100644 --- a/src/eth/rtl/us/taxi_eth_phy_25g_us_gty_25g_156.tcl +++ b/src/eth/rtl/us/taxi_eth_phy_25g_us_gty_25g_156.tcl @@ -35,8 +35,8 @@ if {[string first uplus [get_property FAMILY [get_property PART [current_project lappend extra_pll_ports qpllrsvd2_in qpllrsvd3_in } # channel reset -lappend extra_ports gttxreset_in txuserrdy_in txpmareset_in txpcsreset_in txresetdone_out txpmaresetdone_out -lappend extra_ports gtrxreset_in rxuserrdy_in rxpmareset_in rxdfelpmreset_in eyescanreset_in rxpcsreset_in rxresetdone_out rxpmaresetdone_out +lappend extra_ports gttxreset_in txuserrdy_in txpmareset_in txpcsreset_in txprogdivreset_in txresetdone_out txpmaresetdone_out txprgdivresetdone_out +lappend extra_ports gtrxreset_in rxuserrdy_in rxpmareset_in rxdfelpmreset_in eyescanreset_in rxpcsreset_in rxprogdivreset_in rxresetdone_out rxpmaresetdone_out rxprgdivresetdone_out # channel power down lappend extra_ports txpd_in txpdelecidlemode_in rxpd_in # channel clock selection @@ -91,6 +91,14 @@ proc create_gtwizard_ip {name preset config} { set_property -dict $config_list $ip } +# normal latency (async gearbox) +dict set config TX_DATA_ENCODING {64B66B_ASYNC} +dict set config TX_BUFFER_MODE {1} +dict set config TX_OUTCLK_SOURCE {TXPROGDIVCLK} +dict set config RX_DATA_DECODING {64B66B_ASYNC} +dict set config RX_BUFFER_MODE {1} +dict set config RX_OUTCLK_SOURCE {RXPROGDIVCLK} + # variant with channel and common dict set config ENABLE_OPTIONAL_PORTS [concat $extra_pll_ports $extra_ports] dict set config LOCATE_COMMON {CORE} @@ -101,4 +109,24 @@ create_gtwizard_ip "${base_name}_full" $preset $config dict set config ENABLE_OPTIONAL_PORTS $extra_ports dict set config LOCATE_COMMON {EXAMPLE_DESIGN} -create_gtwizard_ip "${base_name}_channel" $preset $config +create_gtwizard_ip "${base_name}_ch" $preset $config + +# low latency (async gearbox with buffer bypass) +dict set config TX_DATA_ENCODING {64B66B} +dict set config TX_BUFFER_MODE {0} +dict set config TX_OUTCLK_SOURCE {TXPROGDIVCLK} +dict set config RX_DATA_DECODING {64B66B} +dict set config RX_BUFFER_MODE {0} +dict set config RX_OUTCLK_SOURCE {RXOUTCLKPMA} + +# variant with channel and common +dict set config ENABLE_OPTIONAL_PORTS [concat $extra_pll_ports $extra_ports] +dict set config LOCATE_COMMON {CORE} + +create_gtwizard_ip "${base_name}_ll_full" $preset $config + +# variant with channel only +dict set config ENABLE_OPTIONAL_PORTS $extra_ports +dict set config LOCATE_COMMON {EXAMPLE_DESIGN} + +create_gtwizard_ip "${base_name}_ll_ch" $preset $config diff --git a/src/eth/rtl/us/taxi_eth_phy_25g_us_gty_25g_161.tcl b/src/eth/rtl/us/taxi_eth_phy_25g_us_gty_25g_161.tcl index c2792e4..4cec58a 100644 --- a/src/eth/rtl/us/taxi_eth_phy_25g_us_gty_25g_161.tcl +++ b/src/eth/rtl/us/taxi_eth_phy_25g_us_gty_25g_161.tcl @@ -35,8 +35,8 @@ if {[string first uplus [get_property FAMILY [get_property PART [current_project lappend extra_pll_ports qpllrsvd2_in qpllrsvd3_in } # channel reset -lappend extra_ports gttxreset_in txuserrdy_in txpmareset_in txpcsreset_in txresetdone_out txpmaresetdone_out -lappend extra_ports gtrxreset_in rxuserrdy_in rxpmareset_in rxdfelpmreset_in eyescanreset_in rxpcsreset_in rxresetdone_out rxpmaresetdone_out +lappend extra_ports gttxreset_in txuserrdy_in txpmareset_in txpcsreset_in txprogdivreset_in txresetdone_out txpmaresetdone_out txprgdivresetdone_out +lappend extra_ports gtrxreset_in rxuserrdy_in rxpmareset_in rxdfelpmreset_in eyescanreset_in rxpcsreset_in rxprogdivreset_in rxresetdone_out rxpmaresetdone_out rxprgdivresetdone_out # channel power down lappend extra_ports txpd_in txpdelecidlemode_in rxpd_in # channel clock selection @@ -91,6 +91,14 @@ proc create_gtwizard_ip {name preset config} { set_property -dict $config_list $ip } +# normal latency (async gearbox) +dict set config TX_DATA_ENCODING {64B66B_ASYNC} +dict set config TX_BUFFER_MODE {1} +dict set config TX_OUTCLK_SOURCE {TXPROGDIVCLK} +dict set config RX_DATA_DECODING {64B66B_ASYNC} +dict set config RX_BUFFER_MODE {1} +dict set config RX_OUTCLK_SOURCE {RXPROGDIVCLK} + # variant with channel and common dict set config ENABLE_OPTIONAL_PORTS [concat $extra_pll_ports $extra_ports] dict set config LOCATE_COMMON {CORE} @@ -101,4 +109,24 @@ create_gtwizard_ip "${base_name}_full" $preset $config dict set config ENABLE_OPTIONAL_PORTS $extra_ports dict set config LOCATE_COMMON {EXAMPLE_DESIGN} -create_gtwizard_ip "${base_name}_channel" $preset $config +create_gtwizard_ip "${base_name}_ch" $preset $config + +# low latency (async gearbox with buffer bypass) +dict set config TX_DATA_ENCODING {64B66B} +dict set config TX_BUFFER_MODE {0} +dict set config TX_OUTCLK_SOURCE {TXPROGDIVCLK} +dict set config RX_DATA_DECODING {64B66B} +dict set config RX_BUFFER_MODE {0} +dict set config RX_OUTCLK_SOURCE {RXOUTCLKPMA} + +# variant with channel and common +dict set config ENABLE_OPTIONAL_PORTS [concat $extra_pll_ports $extra_ports] +dict set config LOCATE_COMMON {CORE} + +create_gtwizard_ip "${base_name}_ll_full" $preset $config + +# variant with channel only +dict set config ENABLE_OPTIONAL_PORTS $extra_ports +dict set config LOCATE_COMMON {EXAMPLE_DESIGN} + +create_gtwizard_ip "${base_name}_ll_ch" $preset $config diff --git a/src/eth/rtl/us/taxi_eth_phy_25g_us_gty_25g_322.tcl b/src/eth/rtl/us/taxi_eth_phy_25g_us_gty_25g_322.tcl index 57fd89a..a423d9d 100644 --- a/src/eth/rtl/us/taxi_eth_phy_25g_us_gty_25g_322.tcl +++ b/src/eth/rtl/us/taxi_eth_phy_25g_us_gty_25g_322.tcl @@ -35,8 +35,8 @@ if {[string first uplus [get_property FAMILY [get_property PART [current_project lappend extra_pll_ports qpllrsvd2_in qpllrsvd3_in } # channel reset -lappend extra_ports gttxreset_in txuserrdy_in txpmareset_in txpcsreset_in txresetdone_out txpmaresetdone_out -lappend extra_ports gtrxreset_in rxuserrdy_in rxpmareset_in rxdfelpmreset_in eyescanreset_in rxpcsreset_in rxresetdone_out rxpmaresetdone_out +lappend extra_ports gttxreset_in txuserrdy_in txpmareset_in txpcsreset_in txprogdivreset_in txresetdone_out txpmaresetdone_out txprgdivresetdone_out +lappend extra_ports gtrxreset_in rxuserrdy_in rxpmareset_in rxdfelpmreset_in eyescanreset_in rxpcsreset_in rxprogdivreset_in rxresetdone_out rxpmaresetdone_out rxprgdivresetdone_out # channel power down lappend extra_ports txpd_in txpdelecidlemode_in rxpd_in # channel clock selection @@ -91,6 +91,14 @@ proc create_gtwizard_ip {name preset config} { set_property -dict $config_list $ip } +# normal latency (async gearbox) +dict set config TX_DATA_ENCODING {64B66B_ASYNC} +dict set config TX_BUFFER_MODE {1} +dict set config TX_OUTCLK_SOURCE {TXPROGDIVCLK} +dict set config RX_DATA_DECODING {64B66B_ASYNC} +dict set config RX_BUFFER_MODE {1} +dict set config RX_OUTCLK_SOURCE {RXPROGDIVCLK} + # variant with channel and common dict set config ENABLE_OPTIONAL_PORTS [concat $extra_pll_ports $extra_ports] dict set config LOCATE_COMMON {CORE} @@ -101,4 +109,24 @@ create_gtwizard_ip "${base_name}_full" $preset $config dict set config ENABLE_OPTIONAL_PORTS $extra_ports dict set config LOCATE_COMMON {EXAMPLE_DESIGN} -create_gtwizard_ip "${base_name}_channel" $preset $config +create_gtwizard_ip "${base_name}_ch" $preset $config + +# low latency (async gearbox with buffer bypass) +dict set config TX_DATA_ENCODING {64B66B} +dict set config TX_BUFFER_MODE {0} +dict set config TX_OUTCLK_SOURCE {TXPROGDIVCLK} +dict set config RX_DATA_DECODING {64B66B} +dict set config RX_BUFFER_MODE {0} +dict set config RX_OUTCLK_SOURCE {RXOUTCLKPMA} + +# variant with channel and common +dict set config ENABLE_OPTIONAL_PORTS [concat $extra_pll_ports $extra_ports] +dict set config LOCATE_COMMON {CORE} + +create_gtwizard_ip "${base_name}_ll_full" $preset $config + +# variant with channel only +dict set config ENABLE_OPTIONAL_PORTS $extra_ports +dict set config LOCATE_COMMON {EXAMPLE_DESIGN} + +create_gtwizard_ip "${base_name}_ll_ch" $preset $config diff --git a/src/eth/tb/baser.py b/src/eth/tb/baser.py index 09e2090..83eaa56 100644 --- a/src/eth/tb/baser.py +++ b/src/eth/tb/baser.py @@ -24,19 +24,24 @@ from cocotbext.eth import XgmiiFrame class BaseRSerdesSource(): - def __init__(self, data, hdr, clock, enable=None, slip=None, scramble=True, reverse=False, *args, **kwargs): + def __init__(self, data, hdr, clock, enable=None, slip=None, data_valid=None, hdr_valid=None, + gbx_start=None, scramble=True, reverse=False, gbx_cfg=None, *args, **kwargs): + self.log = logging.getLogger(f"cocotb.{data._path}") self.data = data self.hdr = hdr self.clock = clock self.enable = enable self.slip = slip + self.data_valid = data_valid + self.hdr_valid = hdr_valid + self.gbx_start = gbx_start self.scramble = scramble self.reverse = reverse self.log.info("BASE-R serdes source") - self.log.info("Copyright (c) 2021 Alex Forencich") - self.log.info("https://github.com/alexforencich/verilog-ethernet") + self.log.info("Copyright (c) 2021-2025 FPGA Ninja, LLC") + self.log.info("https://github.com/fpganinja/taxi") super().__init__(*args, **kwargs) @@ -53,6 +58,13 @@ class BaseRSerdesSource(): self.bit_offset = 0 + self.gbx_seq = 0 + self.gbx_seq_len = None + self.gbx_seq_stall = None + self.gbx_in_bits = 66 + self.gbx_out_bits = 66 + self.gbx_bit_cnt = 0 + self.queue_occupancy_bytes = 0 self.queue_occupancy_frames = 0 @@ -71,11 +83,64 @@ class BaseRSerdesSource(): self.log.info(" Enable scrambler: %s", self.scramble) self.log.info(" Bit reverse: %s", self.reverse) + if gbx_cfg: + self.set_gbx_cfg(*gbx_cfg) + self.data.setimmediatevalue(0) + if self.data_valid is not None: + self.data_valid.setimmediatevalue(0) self.hdr.setimmediatevalue(0) + if self.hdr_valid is not None: + self.hdr_valid.setimmediatevalue(0) + if self.gbx_start is not None: + self.gbx_start.setimmediatevalue(0) self._run_cr = cocotb.start_soon(self._run()) + def set_gbx_cfg(self, seq_len=None, seq_stall=None): + self.log.info("Set gearbox configuration") + + if seq_len is None: + self.log.info("Gearbox disabled") + self.gbx_bit_cnt = 0 + self.gbx_seq_len = None + self.gbx_seq_stall = None + self.gbx_in_bits = 66 + self.gbx_out_bits = 66 + self.gbx_seq = 0 + + seq_stall = sorted(list(set(seq_stall))) + + for x in seq_stall: + assert 0 <= x < seq_len + + self.log.info(" Sequence length: %d cycles", seq_len) + self.log.info(" Stall cycles: %s", seq_stall) + + out_bits = 66 + in_cycles = seq_len + out_cycles = in_cycles - len(seq_stall) + in_bits = (out_bits * out_cycles) // in_cycles + + self.log.info(" Input: %d bits (%d cycles)", in_bits, in_cycles) + self.log.info(" Output: %d bits (%d cycles)", out_bits, out_cycles) + self.log.info(" Gearbox ratio: %d:%d", in_bits, out_bits) + + assert in_cycles*in_bits == out_cycles*out_bits + + self.gbx_seq = 0 + self.gbx_seq_len = seq_len + self.gbx_seq_stall = set(seq_stall) + self.gbx_in_bits = in_bits + self.gbx_out_bits = out_bits + self.gbx_bit_cnt = 0 + + for k in range(self.gbx_seq_len): + self.gbx_bit_cnt += in_bits + if k in self.gbx_seq_stall: + continue + self.gbx_bit_cnt = max(self.gbx_bit_cnt - out_bits, 0) + async def send(self, frame): while self.full(): self.dequeue_event.clear() @@ -134,13 +199,52 @@ class BaseRSerdesSource(): last_d = 0 self.active = False + clk_period = 0 + last_clk = 0 + gbx_delay = 0 + while True: await RisingEdge(self.clock) + if not clk_period: + if last_clk: + clk_period = get_sim_time() - last_clk + else: + last_clk = get_sim_time() + # clock enable if self.enable is not None and not self.enable.value: continue + # gearbox sequence + if self.gbx_seq_len: + self.gbx_seq = (self.gbx_seq + 1) % self.gbx_seq_len + + if self.gbx_start is not None: + self.gbx_start.value = (self.gbx_seq == 0) + + self.gbx_bit_cnt += self.gbx_in_bits + + # stall cycle + if self.gbx_seq in self.gbx_seq_stall: + self.data.value = 0 + if self.data_valid is not None: + self.data_valid.value = 0 + self.hdr.value = 0 + if self.hdr_valid is not None: + self.hdr_valid.value = 0 + continue + + self.gbx_bit_cnt = max(self.gbx_bit_cnt - self.gbx_out_bits, 0) + gbx_delay = (self.gbx_bit_cnt * clk_period) // self.gbx_in_bits + else: + self.gbx_seq = 0 + self.gbx_bit_cnt = 0 + gbx_delay = 0 + + if self.gbx_start is not None: + self.gbx_start.value = 0 + if ifg_cnt + deficit_idle_cnt > self.byte_lanes-1 or (not self.enable_dic and ifg_cnt > 4): # in IFG ifg_cnt = ifg_cnt - self.byte_lanes @@ -158,7 +262,7 @@ class BaseRSerdesSource(): self.queue_occupancy_bytes -= len(frame) self.queue_occupancy_frames -= 1 self.current_frame = frame - frame.sim_time_start = get_sim_time() + frame.sim_time_start = get_sim_time() - gbx_delay frame.sim_time_sfd = None frame.sim_time_end = None self.log.info("TX frame: %s", frame) @@ -201,14 +305,14 @@ class BaseRSerdesSource(): if frame is not None: d = frame.data[frame_offset] if frame.sim_time_sfd is None and d == EthPre.SFD: - frame.sim_time_sfd = get_sim_time() + frame.sim_time_sfd = get_sim_time() - gbx_delay dl.append(d) cl.append(frame.ctrl[frame_offset]) frame_offset += 1 if frame_offset >= len(frame.data): ifg_cnt = max(self.ifg - (self.byte_lanes-k), 0) - frame.sim_time_end = get_sim_time() + frame.sim_time_end = get_sim_time() - gbx_delay frame.handle_tx_complete() frame = None self.current_frame = None @@ -349,23 +453,35 @@ class BaseRSerdesSource(): hdr = sum(1 << (1-i) for i in range(2) if (hdr >> i) & 1) self.data.value = data + if self.data_valid is not None: + self.data_valid.value = 1 self.hdr.value = hdr + if self.hdr_valid is not None: + self.hdr_valid.value = 1 class BaseRSerdesSink: - def __init__(self, data, hdr, clock, enable=None, scramble=True, reverse=False, *args, **kwargs): + def __init__(self, data, hdr, clock, enable=None, data_valid=None, hdr_valid=None, + gbx_req_start=None, gbx_req_stall=None, gbx_start=None, + scramble=True, reverse=False, gbx_cfg=None, *args, **kwargs): + self.log = logging.getLogger(f"cocotb.{data._path}") self.data = data self.hdr = hdr self.clock = clock self.enable = enable + self.data_valid = data_valid + self.hdr_valid = hdr_valid + self.gbx_req_start = gbx_req_start + self.gbx_req_stall = gbx_req_stall + self.gbx_start = gbx_start self.scramble = scramble self.reverse = reverse self.log.info("BASE-R serdes sink") - self.log.info("Copyright (c) 2021 Alex Forencich") - self.log.info("https://github.com/alexforencich/verilog-ethernet") + self.log.info("Copyright (c) 2021-2025 FPGA Ninja, LLC") + self.log.info("https://github.com/fpganinja/taxi") super().__init__(*args, **kwargs) @@ -373,6 +489,14 @@ class BaseRSerdesSink: self.queue = Queue() self.active_event = Event() + self.gbx_seq = 0 + self.gbx_seq_gen = 0 + self.gbx_seq_len = None + self.gbx_seq_stall = None + self.gbx_in_bits = 66 + self.gbx_out_bits = 66 + self.gbx_bit_cnt = 0 + self.queue_occupancy_bytes = 0 self.queue_occupancy_frames = 0 @@ -388,8 +512,57 @@ class BaseRSerdesSink: self.log.info(" Enable scrambler: %s", self.scramble) self.log.info(" Bit reverse: %s", self.reverse) + if gbx_cfg: + self.set_gbx_cfg(*gbx_cfg) + + if self.gbx_req_start is not None: + self.gbx_req_start.setimmediatevalue(0) + if self.gbx_req_stall is not None: + self.gbx_req_stall.setimmediatevalue(0) + self._run_cr = cocotb.start_soon(self._run()) + def set_gbx_cfg(self, seq_len=None, seq_stall=None): + self.log.info("Set gearbox configuration") + + if seq_len is None: + self.log.info("Gearbox disabled") + self.gbx_seq_len = None + self.gbx_seq_stall = None + + seq_stall = sorted(list(set(seq_stall))) + + for x in seq_stall: + assert 0 <= x < seq_len + + self.log.info(" Sequence length: %d cycles", seq_len) + self.log.info(" Stall cycles: %s", seq_stall) + + in_bits = 66 + out_cycles = seq_len + in_cycles = out_cycles - len(seq_stall) + out_bits = (in_bits * in_cycles) // out_cycles + + self.log.info(" Input: %d bits (%d cycles)", in_bits, in_cycles) + self.log.info(" Output: %d bits (%d cycles)", out_bits, out_cycles) + self.log.info(" Gearbox ratio: %d:%d", in_bits, out_bits) + + assert in_cycles*in_bits == out_cycles*out_bits + + self.gbx_seq = 0 + self.gbx_seq_gen = 0 + self.gbx_seq_len = seq_len + self.gbx_seq_stall = set(seq_stall) + self.gbx_in_bits = in_bits + self.gbx_out_bits = out_bits + self.gbx_bit_cnt = 0 + + for k in range(self.gbx_seq_len): + self.gbx_bit_cnt = max(self.gbx_bit_cnt - out_bits, 0) + if k in self.gbx_seq_stall: + continue + self.gbx_bit_cnt += in_bits + def _recv(self, frame, compact=True): if self.queue.empty(): self.active_event.clear() @@ -436,13 +609,69 @@ class BaseRSerdesSink: scrambler_state = 0 self.active = False + clk_period = 0 + last_clk = 0 + gbx_delay = 0 + sync_bad = True + while True: await RisingEdge(self.clock) + if not clk_period: + if last_clk: + clk_period = get_sim_time() - last_clk + else: + last_clk = get_sim_time() + # clock enable if self.enable is not None and not self.enable.value: continue + # gearbox sequence + if self.gbx_seq_len: + # generation + self.gbx_seq_gen = (self.gbx_seq_gen + 1) % self.gbx_seq_len + + if self.gbx_req_start is not None: + self.gbx_req_start.value = (self.gbx_seq_gen == 0) + + # stall cycle + if self.gbx_req_stall is not None: + self.gbx_req_stall.value = (self.gbx_seq_gen in self.gbx_seq_stall) + + # sync + self.gbx_seq = (self.gbx_seq + 1) % self.gbx_seq_len + + if self.gbx_start is not None: + if self.gbx_start.value.integer: + self.gbx_seq = 0 + + self.gbx_bit_cnt = max(self.gbx_bit_cnt - self.gbx_out_bits, 0) + + if self.gbx_seq in self.gbx_seq_stall: + continue + + self.gbx_bit_cnt += self.gbx_in_bits + gbx_delay = (self.gbx_bit_cnt * clk_period) // self.gbx_out_bits + else: + self.gbx_seq = 0 + self.gbx_seq_gen = 0 + self.gbx_bit_cnt = 0 + gbx_delay = 0 + + if self.gbx_start is not None: + self.gbx_start.value = 1 + + if self.data_valid is not None: + if not self.data_valid.value.integer: + # stall + if self.gbx_seq_len and not sync_bad: + sync_bad = True + self.log.warning("Data not valid outside of gearbox stall cycle") + continue + + sync_bad = False + data = self.data.value.integer hdr = self.hdr.value.integer @@ -590,7 +819,7 @@ class BaseRSerdesSink: if c_val and d_val == XgmiiCtrl.START: # start frame = XgmiiFrame(bytearray([EthPre.PRE]), [0]) - frame.sim_time_start = get_sim_time() + frame.sim_time_start = get_sim_time() + gbx_delay frame.start_lane = offset else: if c_val: @@ -601,7 +830,7 @@ class BaseRSerdesSink: frame.ctrl.append(c_val) frame.compact() - frame.sim_time_end = get_sim_time() + frame.sim_time_end = get_sim_time() + gbx_delay self.log.info("RX frame: %s", frame) self.queue_occupancy_bytes += len(frame) @@ -613,7 +842,7 @@ class BaseRSerdesSink: frame = None else: if frame.sim_time_sfd is None and d_val == EthPre.SFD: - frame.sim_time_sfd = get_sim_time() + frame.sim_time_sfd = get_sim_time() + gbx_delay frame.data.append(d_val) frame.ctrl.append(c_val) diff --git a/src/eth/tb/taxi_axis_baser_rx_64/Makefile b/src/eth/tb/taxi_axis_baser_rx_64/Makefile index 04318b8..c32ed65 100644 --- a/src/eth/tb/taxi_axis_baser_rx_64/Makefile +++ b/src/eth/tb/taxi_axis_baser_rx_64/Makefile @@ -36,6 +36,7 @@ VERILOG_SOURCES := $(call uniq_base,$(call process_f_files,$(VERILOG_SOURCES))) # module parameters export PARAM_DATA_W := 64 export PARAM_HDR_W := 2 +export PARAM_GBX_IF_EN := 1 export PARAM_PTP_TS_EN := 1 export PARAM_PTP_TS_FMT_TOD := 1 diff --git a/src/eth/tb/taxi_axis_baser_rx_64/test_taxi_axis_baser_rx_64.py b/src/eth/tb/taxi_axis_baser_rx_64/test_taxi_axis_baser_rx_64.py index 1b6a045..50e0a2f 100644 --- a/src/eth/tb/taxi_axis_baser_rx_64/test_taxi_axis_baser_rx_64.py +++ b/src/eth/tb/taxi_axis_baser_rx_64/test_taxi_axis_baser_rx_64.py @@ -15,6 +15,7 @@ import os import sys import cocotb_test.simulator +import pytest import cocotb from cocotb.clock import Clock @@ -37,15 +38,28 @@ except ImportError: class TB: - def __init__(self, dut): + def __init__(self, dut, gbx_cfg=None): self.dut = dut self.log = logging.getLogger("cocotb.tb") self.log.setLevel(logging.DEBUG) - cocotb.start_soon(Clock(dut.clk, 6.4, units="ns").start()) + if gbx_cfg: + self.clk_period = 6.206 + else: + self.clk_period = 6.4 - self.source = BaseRSerdesSource(dut.encoded_rx_data, dut.encoded_rx_hdr, dut.clk, scramble=False) + cocotb.start_soon(Clock(dut.clk, self.clk_period, units="ns").start()) + + self.source = BaseRSerdesSource( + data=dut.encoded_rx_data, + data_valid=dut.encoded_rx_data_valid, + hdr=dut.encoded_rx_hdr, + hdr_valid=dut.encoded_rx_hdr_valid, + clock=dut.clk, + scramble=False, + gbx_cfg=gbx_cfg + ) self.sink = AxiStreamSink(AxiStreamBus.from_entity(dut.m_axis_rx), dut.clk, dut.rst) self.ptp_clock = PtpClockSimTime(ts_tod=dut.ptp_ts, clock=dut.clk) @@ -96,9 +110,9 @@ class TB: self.stats[stat] += int(getattr(self.dut, stat).value) -async def run_test(dut, payload_lengths=None, payload_data=None, ifg=12): +async def run_test(dut, gbx_cfg=None, payload_lengths=None, payload_data=None, ifg=12): - tb = TB(dut) + tb = TB(dut, gbx_cfg) tb.source.ifg = ifg tb.dut.cfg_rx_max_pkt_len.value = 9218 @@ -138,7 +152,8 @@ async def run_test(dut, payload_lengths=None, payload_data=None, ifg=12): assert rx_frame.tdata == test_data assert frame_error == 0 - assert abs(ptp_ts_ns - tx_frame_sfd_ns - 6.4) < 0.01 + if gbx_cfg is None: + assert abs(ptp_ts_ns - tx_frame_sfd_ns - 6.4) < 0.01 assert tb.sink.empty() @@ -161,13 +176,13 @@ async def run_test(dut, payload_lengths=None, payload_data=None, ifg=12): assert tb.stats["stat_rx_err_framing"] == 0 assert tb.stats["stat_rx_err_preamble"] == 0 - await RisingEdge(dut.clk) - await RisingEdge(dut.clk) + for k in range(10): + await RisingEdge(dut.clk) -async def run_test_oversize(dut, ifg=12): +async def run_test_oversize(dut, gbx_cfg=None, ifg=12): - tb = TB(dut) + tb = TB(dut, gbx_cfg) tb.source.ifg = ifg tb.dut.cfg_rx_max_pkt_len.value = 1518 @@ -250,8 +265,8 @@ async def run_test_oversize(dut, ifg=12): assert tb.stats["stat_rx_err_framing"] == 0 assert tb.stats["stat_rx_err_preamble"] == 0 - await RisingEdge(dut.clk) - await RisingEdge(dut.clk) + for k in range(10): + await RisingEdge(dut.clk) def size_list(): @@ -268,14 +283,22 @@ def cycle_en(): if cocotb.SIM_NAME: + gbx_cfgs = [None] + + if cocotb.top.GBX_IF_EN.value: + gbx_cfgs.append((33, [32])) + gbx_cfgs.append((66, [64, 65])) + factory = TestFactory(run_test) factory.add_option("payload_lengths", [size_list]) factory.add_option("payload_data", [incrementing_payload]) factory.add_option("ifg", list(range(0, 13))) + factory.add_option("gbx_cfg", gbx_cfgs) factory.generate_tests() factory = TestFactory(run_test_oversize) factory.add_option("ifg", list(range(0, 13))) + factory.add_option("gbx_cfg", gbx_cfgs) factory.generate_tests() @@ -300,7 +323,8 @@ def process_f_files(files): return list(lst.values()) -def test_taxi_axis_baser_rx_64(request): +@pytest.mark.parametrize("gbx_en", [1, 0]) +def test_taxi_axis_baser_rx_64(request, gbx_en): dut = "taxi_axis_baser_rx_64" module = os.path.splitext(os.path.basename(__file__))[0] toplevel = module @@ -318,6 +342,7 @@ def test_taxi_axis_baser_rx_64(request): parameters['DATA_W'] = 64 parameters['HDR_W'] = 2 + parameters['GBX_IF_EN'] = gbx_en parameters['PTP_TS_EN'] = 1 parameters['PTP_TS_FMT_TOD'] = 1 parameters['PTP_TS_W'] = 96 if parameters['PTP_TS_FMT_TOD'] else 64 diff --git a/src/eth/tb/taxi_axis_baser_rx_64/test_taxi_axis_baser_rx_64.sv b/src/eth/tb/taxi_axis_baser_rx_64/test_taxi_axis_baser_rx_64.sv index 9fed152..4065a91 100644 --- a/src/eth/tb/taxi_axis_baser_rx_64/test_taxi_axis_baser_rx_64.sv +++ b/src/eth/tb/taxi_axis_baser_rx_64/test_taxi_axis_baser_rx_64.sv @@ -20,6 +20,7 @@ module test_taxi_axis_baser_rx_64 # /* verilator lint_off WIDTHTRUNC */ parameter DATA_W = 64, parameter HDR_W = 2, + parameter logic GBX_IF_EN = 1'b0, parameter logic PTP_TS_EN = 1'b0, parameter logic PTP_TS_FMT_TOD = 1'b1, parameter PTP_TS_W = PTP_TS_FMT_TOD ? 96 : 64 @@ -33,7 +34,9 @@ logic clk; logic rst; logic [DATA_W-1:0] encoded_rx_data; +logic encoded_rx_data_valid; logic [HDR_W-1:0] encoded_rx_hdr; +logic encoded_rx_hdr_valid; taxi_axis_if #(.DATA_W(DATA_W), .USER_EN(1), .USER_W(USER_W)) m_axis_rx(); @@ -62,6 +65,7 @@ logic stat_rx_err_preamble; taxi_axis_baser_rx_64 #( .DATA_W(DATA_W), .HDR_W(HDR_W), + .GBX_IF_EN(GBX_IF_EN), .PTP_TS_EN(PTP_TS_EN), .PTP_TS_FMT_TOD(PTP_TS_FMT_TOD), .PTP_TS_W(PTP_TS_W) @@ -74,7 +78,9 @@ uut ( * 10GBASE-R encoded input */ .encoded_rx_data(encoded_rx_data), + .encoded_rx_data_valid(encoded_rx_data_valid), .encoded_rx_hdr(encoded_rx_hdr), + .encoded_rx_hdr_valid(encoded_rx_hdr_valid), /* * AXI4-Stream output (source) diff --git a/src/eth/tb/taxi_axis_baser_tx_64/Makefile b/src/eth/tb/taxi_axis_baser_tx_64/Makefile index 805abee..ae54662 100644 --- a/src/eth/tb/taxi_axis_baser_tx_64/Makefile +++ b/src/eth/tb/taxi_axis_baser_tx_64/Makefile @@ -36,6 +36,8 @@ VERILOG_SOURCES := $(call uniq_base,$(call process_f_files,$(VERILOG_SOURCES))) # module parameters export PARAM_DATA_W := 64 export PARAM_HDR_W := 2 +export PARAM_GBX_IF_EN := 1 +export PARAM_GBX_CNT := 1 export PARAM_PADDING_EN := 1 export PARAM_DIC_EN := 1 export PARAM_MIN_FRAME_LEN := 64 diff --git a/src/eth/tb/taxi_axis_baser_tx_64/test_taxi_axis_baser_tx_64.py b/src/eth/tb/taxi_axis_baser_tx_64/test_taxi_axis_baser_tx_64.py index 21385f8..4d51693 100644 --- a/src/eth/tb/taxi_axis_baser_tx_64/test_taxi_axis_baser_tx_64.py +++ b/src/eth/tb/taxi_axis_baser_tx_64/test_taxi_axis_baser_tx_64.py @@ -38,16 +38,32 @@ except ImportError: class TB: - def __init__(self, dut): + def __init__(self, dut, gbx_cfg=None): self.dut = dut self.log = logging.getLogger("cocotb.tb") self.log.setLevel(logging.DEBUG) - cocotb.start_soon(Clock(dut.clk, 6.4, units="ns").start()) + if gbx_cfg: + self.clk_period = 6.206 + else: + self.clk_period = 6.4 + + cocotb.start_soon(Clock(dut.clk, self.clk_period, units="ns").start()) self.source = AxiStreamSource(AxiStreamBus.from_entity(dut.s_axis_tx), dut.clk, dut.rst) - self.sink = BaseRSerdesSink(dut.encoded_tx_data, dut.encoded_tx_hdr, dut.clk, scramble=False) + self.sink = BaseRSerdesSink( + data=dut.encoded_tx_data, + data_valid=dut.encoded_tx_data_valid, + hdr=dut.encoded_tx_hdr, + hdr_valid=dut.encoded_tx_hdr_valid, + gbx_req_start=dut.tx_gbx_req_start, + gbx_req_stall=dut.tx_gbx_req_stall, + gbx_start=dut.tx_gbx_start, + clock=dut.clk, + scramble=False, + gbx_cfg=gbx_cfg + ) self.ptp_clock = PtpClockSimTime(ts_tod=dut.ptp_ts, clock=dut.clk) self.tx_cpl_sink = AxiStreamSink(AxiStreamBus.from_entity(dut.m_axis_tx_cpl), dut.clk, dut.rst) @@ -95,16 +111,20 @@ class TB: self.stats[stat] += int(getattr(self.dut, stat).value) -async def run_test(dut, payload_lengths=None, payload_data=None, ifg=12): +async def run_test(dut, gbx_cfg=None, payload_lengths=None, payload_data=None, ifg=12): - tb = TB(dut) + tb = TB(dut, gbx_cfg) tb.dut.cfg_tx_max_pkt_len.value = 9218 tb.dut.cfg_tx_ifg.value = ifg - tb.dut.cfg_tx_enable.value = 1 await tb.reset() + for k in range(100): + await RisingEdge(dut.clk) + + tb.dut.cfg_tx_enable.value = 1 + test_frames = [payload_data(x) for x in payload_lengths()] total_bytes = 0 @@ -134,7 +154,8 @@ async def run_test(dut, payload_lengths=None, payload_data=None, ifg=12): assert rx_frame.get_payload() == test_data assert rx_frame.check_fcs() assert rx_frame.ctrl is None - assert abs(rx_frame_sfd_ns - ptp_ts_ns - 12.8) < 0.01 + if gbx_cfg is None: + assert abs(rx_frame_sfd_ns - ptp_ts_ns - 12.8) < 0.01 assert tb.sink.empty() @@ -153,24 +174,28 @@ async def run_test(dut, payload_lengths=None, payload_data=None, ifg=12): assert tb.stats["stat_tx_err_user"] == 0 assert tb.stats["stat_tx_err_underflow"] == 0 - await RisingEdge(dut.clk) - await RisingEdge(dut.clk) + for k in range(10): + await RisingEdge(dut.clk) -async def run_test_alignment(dut, payload_data=None, ifg=12): +async def run_test_alignment(dut, gbx_cfg=None, payload_data=None, ifg=12): enable_dic = int(dut.DIC_EN.value) - tb = TB(dut) + tb = TB(dut, gbx_cfg) byte_width = tb.source.width // 8 tb.dut.cfg_tx_max_pkt_len.value = 9218 tb.dut.cfg_tx_ifg.value = ifg - tb.dut.cfg_tx_enable.value = 1 await tb.reset() + for k in range(100): + await RisingEdge(dut.clk) + + tb.dut.cfg_tx_enable.value = 1 + total_bytes = 0 total_pkts = 0 @@ -206,7 +231,8 @@ async def run_test_alignment(dut, payload_data=None, ifg=12): assert rx_frame.get_payload() == test_data assert rx_frame.check_fcs() assert rx_frame.ctrl is None - assert abs(rx_frame_sfd_ns - ptp_ts_ns - 12.8) < 0.01 + if gbx_cfg is None: + assert abs(rx_frame_sfd_ns - ptp_ts_ns - 12.8) < 0.01 start_lane.append(rx_frame.start_lane) @@ -261,20 +287,24 @@ async def run_test_alignment(dut, payload_data=None, ifg=12): assert tb.stats["stat_tx_err_user"] == 0 assert tb.stats["stat_tx_err_underflow"] == 0 - await RisingEdge(dut.clk) - await RisingEdge(dut.clk) + for k in range(10): + await RisingEdge(dut.clk) -async def run_test_underrun(dut, ifg=12): +async def run_test_underrun(dut, gbx_cfg=None, ifg=12): - tb = TB(dut) + tb = TB(dut, gbx_cfg) tb.dut.cfg_tx_max_pkt_len.value = 9218 tb.dut.cfg_tx_ifg.value = ifg - tb.dut.cfg_tx_enable.value = 1 await tb.reset() + for k in range(100): + await RisingEdge(dut.clk) + + tb.dut.cfg_tx_enable.value = 1 + test_data = bytes(x for x in range(60)) for k in range(3): @@ -319,20 +349,24 @@ async def run_test_underrun(dut, ifg=12): assert tb.stats["stat_tx_err_user"] == 0 assert tb.stats["stat_tx_err_underflow"] == 1 - await RisingEdge(dut.clk) - await RisingEdge(dut.clk) + for k in range(10): + await RisingEdge(dut.clk) -async def run_test_error(dut, ifg=12): +async def run_test_error(dut, gbx_cfg=None, ifg=12): - tb = TB(dut) + tb = TB(dut, gbx_cfg) tb.dut.cfg_tx_max_pkt_len.value = 9218 tb.dut.cfg_tx_ifg.value = ifg - tb.dut.cfg_tx_enable.value = 1 await tb.reset() + for k in range(100): + await RisingEdge(dut.clk) + + tb.dut.cfg_tx_enable.value = 1 + test_data = bytes(x for x in range(60)) for k in range(3): @@ -369,20 +403,24 @@ async def run_test_error(dut, ifg=12): assert tb.stats["stat_tx_err_user"] == 1 assert tb.stats["stat_tx_err_underflow"] == 0 - await RisingEdge(dut.clk) - await RisingEdge(dut.clk) + for k in range(10): + await RisingEdge(dut.clk) -async def run_test_oversize(dut, ifg=12): +async def run_test_oversize(dut, gbx_cfg=None, ifg=12): - tb = TB(dut) + tb = TB(dut, gbx_cfg) tb.dut.cfg_tx_max_pkt_len.value = 1518 tb.dut.cfg_tx_ifg.value = ifg - tb.dut.cfg_tx_enable.value = 1 await tb.reset() + for k in range(100): + await RisingEdge(dut.clk) + + tb.dut.cfg_tx_enable.value = 1 + for max_len in range(128-4-8, 128-4+9): tb.stats_reset() @@ -454,8 +492,8 @@ async def run_test_oversize(dut, ifg=12): assert tb.stats["stat_tx_err_user"] == 0 assert tb.stats["stat_tx_err_underflow"] == 0 - await RisingEdge(dut.clk) - await RisingEdge(dut.clk) + for k in range(10): + await RisingEdge(dut.clk) def size_list(): @@ -472,15 +510,23 @@ def cycle_en(): if cocotb.SIM_NAME: + gbx_cfgs = [None] + + if cocotb.top.GBX_IF_EN.value: + gbx_cfgs.append((33, [32])) + gbx_cfgs.append((66, [64, 65])) + factory = TestFactory(run_test) factory.add_option("payload_lengths", [size_list]) factory.add_option("payload_data", [incrementing_payload]) factory.add_option("ifg", [12]) + factory.add_option("gbx_cfg", gbx_cfgs) factory.generate_tests() factory = TestFactory(run_test_alignment) factory.add_option("payload_data", [incrementing_payload]) factory.add_option("ifg", [12]) + factory.add_option("gbx_cfg", gbx_cfgs) factory.generate_tests() for test in [ @@ -491,6 +537,7 @@ if cocotb.SIM_NAME: factory = TestFactory(test) factory.add_option("ifg", [12]) + factory.add_option("gbx_cfg", gbx_cfgs) factory.generate_tests() @@ -516,7 +563,8 @@ def process_f_files(files): @pytest.mark.parametrize("dic_en", [1, 0]) -def test_taxi_axis_baser_tx_64(request, dic_en): +@pytest.mark.parametrize("gbx_en", [1, 0]) +def test_taxi_axis_baser_tx_64(request, gbx_en, dic_en): dut = "taxi_axis_baser_tx_64" module = os.path.splitext(os.path.basename(__file__))[0] toplevel = module @@ -534,6 +582,8 @@ def test_taxi_axis_baser_tx_64(request, dic_en): parameters['DATA_W'] = 64 parameters['HDR_W'] = 2 + parameters['GBX_IF_EN'] = gbx_en + parameters['GBX_CNT'] = 1 parameters['PADDING_EN'] = 1 parameters['DIC_EN'] = dic_en parameters['MIN_FRAME_LEN'] = 64 diff --git a/src/eth/tb/taxi_axis_baser_tx_64/test_taxi_axis_baser_tx_64.sv b/src/eth/tb/taxi_axis_baser_tx_64/test_taxi_axis_baser_tx_64.sv index 73deac2..aab6bdd 100644 --- a/src/eth/tb/taxi_axis_baser_tx_64/test_taxi_axis_baser_tx_64.sv +++ b/src/eth/tb/taxi_axis_baser_tx_64/test_taxi_axis_baser_tx_64.sv @@ -20,6 +20,8 @@ module test_taxi_axis_baser_tx_64 # /* verilator lint_off WIDTHTRUNC */ parameter DATA_W = 64, parameter HDR_W = 2, + parameter logic GBX_IF_EN = 1'b0, + parameter GBX_CNT = 1, parameter logic PADDING_EN = 1'b1, parameter logic DIC_EN = 1'b1, parameter MIN_FRAME_LEN = 64, @@ -41,7 +43,12 @@ taxi_axis_if #(.DATA_W(DATA_W), .USER_EN(1), .USER_W(USER_W), .ID_EN(1), .ID_W(T taxi_axis_if #(.DATA_W(PTP_TS_W), .KEEP_W(1), .ID_EN(1), .ID_W(TX_TAG_W)) m_axis_tx_cpl(); logic [DATA_W-1:0] encoded_tx_data; +logic encoded_tx_data_valid; logic [HDR_W-1:0] encoded_tx_hdr; +logic encoded_tx_hdr_valid; +logic [GBX_CNT-1:0] tx_gbx_req_start; +logic tx_gbx_req_stall; +logic [GBX_CNT-1:0] tx_gbx_start; logic [PTP_TS_W-1:0] ptp_ts; @@ -65,6 +72,7 @@ logic stat_tx_err_underflow; taxi_axis_baser_tx_64 #( .DATA_W(DATA_W), .HDR_W(HDR_W), + .GBX_IF_EN(GBX_IF_EN), .PADDING_EN(PADDING_EN), .DIC_EN(DIC_EN), .MIN_FRAME_LEN(MIN_FRAME_LEN), @@ -86,7 +94,12 @@ uut ( * 10GBASE-R encoded interface */ .encoded_tx_data(encoded_tx_data), + .encoded_tx_data_valid(encoded_tx_data_valid), .encoded_tx_hdr(encoded_tx_hdr), + .encoded_tx_hdr_valid(encoded_tx_hdr_valid), + .tx_gbx_req_start(tx_gbx_req_start), + .tx_gbx_req_stall(tx_gbx_req_stall), + .tx_gbx_start(tx_gbx_start), /* * PTP diff --git a/src/eth/tb/taxi_eth_mac_phy_10g/Makefile b/src/eth/tb/taxi_eth_mac_phy_10g/Makefile index 3d72df3..495dd63 100644 --- a/src/eth/tb/taxi_eth_mac_phy_10g/Makefile +++ b/src/eth/tb/taxi_eth_mac_phy_10g/Makefile @@ -34,6 +34,8 @@ VERILOG_SOURCES := $(call uniq_base,$(call process_f_files,$(VERILOG_SOURCES))) # module parameters export PARAM_DATA_W := 64 export PARAM_HDR_W := 2 +export PARAM_TX_GBX_IF_EN := 1 +export PARAM_RX_GBX_IF_EN := $(PARAM_TX_GBX_IF_EN) export PARAM_PADDING_EN := 1 export PARAM_DIC_EN := 1 export PARAM_MIN_FRAME_LEN := 64 diff --git a/src/eth/tb/taxi_eth_mac_phy_10g/test_taxi_eth_mac_phy_10g.py b/src/eth/tb/taxi_eth_mac_phy_10g/test_taxi_eth_mac_phy_10g.py index 770bf68..3c9c1a0 100644 --- a/src/eth/tb/taxi_eth_mac_phy_10g/test_taxi_eth_mac_phy_10g.py +++ b/src/eth/tb/taxi_eth_mac_phy_10g/test_taxi_eth_mac_phy_10g.py @@ -41,23 +41,47 @@ except ImportError: class TB: - def __init__(self, dut): + def __init__(self, dut, gbx_cfg=None): self.dut = dut self.log = logging.getLogger("cocotb.tb") self.log.setLevel(logging.DEBUG) if len(dut.serdes_tx_data) == 64: - self.clk_period = 6.4 + if gbx_cfg: + self.clk_period = 6.206 + else: + self.clk_period = 6.4 else: - self.clk_period = 3.2 + if gbx_cfg: + self.clk_period = 3.102 + else: + self.clk_period = 3.2 cocotb.start_soon(Clock(dut.rx_clk, self.clk_period, units="ns").start()) cocotb.start_soon(Clock(dut.tx_clk, self.clk_period, units="ns").start()) cocotb.start_soon(Clock(dut.stat_clk, self.clk_period, units="ns").start()) - self.serdes_source = BaseRSerdesSource(dut.serdes_rx_data, dut.serdes_rx_hdr, dut.rx_clk, slip=dut.serdes_rx_bitslip) - self.serdes_sink = BaseRSerdesSink(dut.serdes_tx_data, dut.serdes_tx_hdr, dut.tx_clk) + self.serdes_source = BaseRSerdesSource( + data=dut.serdes_rx_data, + data_valid=dut.serdes_rx_data_valid, + hdr=dut.serdes_rx_hdr, + hdr_valid=dut.serdes_rx_hdr_valid, + clock=dut.rx_clk, + slip=dut.serdes_rx_bitslip, + gbx_cfg=gbx_cfg + ) + self.serdes_sink = BaseRSerdesSink( + data=dut.serdes_tx_data, + data_valid=dut.serdes_tx_data_valid, + hdr=dut.serdes_tx_hdr, + hdr_valid=dut.serdes_tx_hdr_valid, + gbx_req_start=dut.serdes_tx_gbx_req_start, + gbx_req_stall=dut.serdes_tx_gbx_req_stall, + gbx_start=dut.serdes_tx_gbx_start, + clock=dut.tx_clk, + gbx_cfg=gbx_cfg + ) self.axis_source = AxiStreamSource(AxiStreamBus.from_entity(dut.s_axis_tx), dut.tx_clk, dut.tx_rst) self.tx_cpl_sink = AxiStreamSink(AxiStreamBus.from_entity(dut.m_axis_tx_cpl), dut.tx_clk, dut.tx_rst) @@ -127,9 +151,9 @@ class TB: await RisingEdge(self.dut.rx_clk) -async def run_test_rx(dut, payload_lengths=None, payload_data=None, ifg=12): +async def run_test_rx(dut, gbx_cfg=None, payload_lengths=None, payload_data=None, ifg=12): - tb = TB(dut) + tb = TB(dut, gbx_cfg) tb.serdes_source.ifg = ifg tb.dut.cfg_tx_ifg.value = ifg @@ -171,20 +195,22 @@ async def run_test_rx(dut, payload_lengths=None, payload_data=None, ifg=12): tb.log.info("RX frame PTP TS: %f ns", ptp_ts_ns) tb.log.info("TX frame SFD sim time: %f ns", tx_frame_sfd_ns) tb.log.info("Difference: %f ns", abs(ptp_ts_ns - tx_frame_sfd_ns)) + tb.log.info("Error: %f ns", abs(ptp_ts_ns - tx_frame_sfd_ns - tb.clk_period*4)) assert rx_frame.tdata == test_data assert frame_error == 0 - assert abs(ptp_ts_ns - tx_frame_sfd_ns - tb.clk_period*4) < 0.01 + if gbx_cfg is None: + assert abs(ptp_ts_ns - tx_frame_sfd_ns - tb.clk_period*4) < 0.01 assert tb.axis_sink.empty() - await RisingEdge(dut.rx_clk) - await RisingEdge(dut.rx_clk) + for k in range(10): + await RisingEdge(dut.rx_clk) -async def run_test_tx(dut, payload_lengths=None, payload_data=None, ifg=12): +async def run_test_tx(dut, gbx_cfg=None, payload_lengths=None, payload_data=None, ifg=12): - tb = TB(dut) + tb = TB(dut, gbx_cfg) tb.serdes_source.ifg = ifg tb.dut.cfg_tx_max_pkt_len.value = 9218 @@ -192,6 +218,9 @@ async def run_test_tx(dut, payload_lengths=None, payload_data=None, ifg=12): await tb.reset() + for k in range(100): + await RisingEdge(dut.tx_clk) + tb.dut.cfg_tx_enable.value = 1 test_frames = [payload_data(x) for x in payload_lengths()] @@ -214,23 +243,25 @@ async def run_test_tx(dut, payload_lengths=None, payload_data=None, ifg=12): tb.log.info("TX frame PTP TS: %f ns", ptp_ts_ns) tb.log.info("RX frame SFD sim time: %f ns", rx_frame_sfd_ns) tb.log.info("Difference: %f ns", abs(rx_frame_sfd_ns - ptp_ts_ns)) + tb.log.info("Error: %f ns", abs(rx_frame_sfd_ns - ptp_ts_ns - tb.clk_period*5)) assert rx_frame.get_payload() == test_data assert rx_frame.check_fcs() assert rx_frame.ctrl is None - assert abs(rx_frame_sfd_ns - ptp_ts_ns - tb.clk_period*5) < 0.01 + if gbx_cfg is None: + assert abs(rx_frame_sfd_ns - ptp_ts_ns - tb.clk_period*5) < 0.01 assert tb.serdes_sink.empty() - await RisingEdge(dut.tx_clk) - await RisingEdge(dut.tx_clk) + for k in range(10): + await RisingEdge(dut.tx_clk) -async def run_test_tx_alignment(dut, payload_data=None, ifg=12): +async def run_test_tx_alignment(dut, gbx_cfg=None, payload_data=None, ifg=12): dic_en = int(cocotb.top.DIC_EN.value) - tb = TB(dut) + tb = TB(dut, gbx_cfg) byte_width = tb.axis_source.width // 8 @@ -240,6 +271,9 @@ async def run_test_tx_alignment(dut, payload_data=None, ifg=12): await tb.reset() + for k in range(100): + await RisingEdge(dut.tx_clk) + tb.dut.cfg_tx_enable.value = 1 for length in range(60, 92): @@ -272,7 +306,8 @@ async def run_test_tx_alignment(dut, payload_data=None, ifg=12): assert rx_frame.get_payload() == test_data assert rx_frame.check_fcs() assert rx_frame.ctrl is None - assert abs(rx_frame_sfd_ns - ptp_ts_ns - tb.clk_period*5) < 0.01 + if gbx_cfg is None: + assert abs(rx_frame_sfd_ns - ptp_ts_ns - tb.clk_period*5) < 0.01 start_lane.append(rx_frame.start_lane) @@ -312,13 +347,13 @@ async def run_test_tx_alignment(dut, payload_data=None, ifg=12): assert tb.serdes_sink.empty() - await RisingEdge(dut.tx_clk) - await RisingEdge(dut.tx_clk) + for k in range(10): + await RisingEdge(dut.tx_clk) -async def run_test_tx_underrun(dut, ifg=12): +async def run_test_tx_underrun(dut, gbx_cfg=None, ifg=12): - tb = TB(dut) + tb = TB(dut, gbx_cfg) tb.serdes_source.ifg = ifg tb.dut.cfg_tx_max_pkt_len.value = 9218 @@ -326,6 +361,9 @@ async def run_test_tx_underrun(dut, ifg=12): await tb.reset() + for k in range(100): + await RisingEdge(dut.tx_clk) + tb.dut.cfg_tx_enable.value = 1 test_data = bytes(x for x in range(60)) @@ -357,13 +395,13 @@ async def run_test_tx_underrun(dut, ifg=12): assert tb.serdes_sink.empty() - await RisingEdge(dut.tx_clk) - await RisingEdge(dut.tx_clk) + for k in range(10): + await RisingEdge(dut.tx_clk) -async def run_test_tx_error(dut, ifg=12): +async def run_test_tx_error(dut, gbx_cfg=None, ifg=12): - tb = TB(dut) + tb = TB(dut, gbx_cfg) tb.serdes_source.ifg = ifg tb.dut.cfg_tx_max_pkt_len.value = 9218 @@ -371,6 +409,9 @@ async def run_test_tx_error(dut, ifg=12): await tb.reset() + for k in range(100): + await RisingEdge(dut.tx_clk) + tb.dut.cfg_tx_enable.value = 1 test_data = bytes(x for x in range(60)) @@ -394,13 +435,13 @@ async def run_test_tx_error(dut, ifg=12): assert tb.serdes_sink.empty() - await RisingEdge(dut.tx_clk) - await RisingEdge(dut.tx_clk) + for k in range(10): + await RisingEdge(dut.tx_clk) -async def run_test_rx_frame_sync(dut): +async def run_test_rx_frame_sync(dut, gbx_cfg=None): - tb = TB(dut) + tb = TB(dut, gbx_cfg) await tb.reset() @@ -432,13 +473,13 @@ async def run_test_rx_frame_sync(dut): tb.log.info("Check for high BER deassert") assert not int(dut.rx_high_ber.value) - await RisingEdge(dut.rx_clk) - await RisingEdge(dut.rx_clk) + for k in range(10): + await RisingEdge(dut.rx_clk) -async def run_test_lfc(dut, ifg=12): +async def run_test_lfc(dut, gbx_cfg=None, ifg=12): - tb = TB(dut) + tb = TB(dut, gbx_cfg) tb.serdes_source.ifg = ifg tb.dut.cfg_tx_max_pkt_len.value = 9218 @@ -447,6 +488,9 @@ async def run_test_lfc(dut, ifg=12): await tb.reset() + for k in range(100): + await RisingEdge(dut.tx_clk) + tb.log.info("Wait for block lock") while not int(dut.rx_block_lock.value): await RisingEdge(dut.rx_clk) @@ -584,13 +628,13 @@ async def run_test_lfc(dut, ifg=12): assert tb.axis_sink.empty() assert tb.serdes_sink.empty() - await RisingEdge(dut.tx_clk) - await RisingEdge(dut.tx_clk) + for k in range(10): + await RisingEdge(dut.tx_clk) -async def run_test_pfc(dut, ifg=12): +async def run_test_pfc(dut, gbx_cfg=None, ifg=12): - tb = TB(dut) + tb = TB(dut, gbx_cfg) tb.serdes_source.ifg = ifg tb.dut.cfg_tx_max_pkt_len.value = 9218 @@ -599,6 +643,9 @@ async def run_test_pfc(dut, ifg=12): await tb.reset() + for k in range(100): + await RisingEdge(dut.tx_clk) + tb.log.info("Wait for block lock") while not int(dut.rx_block_lock.value): await RisingEdge(dut.rx_clk) @@ -726,8 +773,8 @@ async def run_test_pfc(dut, ifg=12): assert tb.axis_sink.empty() assert tb.serdes_sink.empty() - await RisingEdge(dut.tx_clk) - await RisingEdge(dut.tx_clk) + for k in range(10): + await RisingEdge(dut.tx_clk) def size_list(): @@ -744,23 +791,32 @@ def cycle_en(): if cocotb.SIM_NAME: + gbx_cfgs = [None] + + if cocotb.top.RX_GBX_IF_EN.value: + gbx_cfgs.append((33, [32])) + gbx_cfgs.append((66, [64, 65])) + for test in [run_test_rx, run_test_tx]: factory = TestFactory(test) factory.add_option("payload_lengths", [size_list]) factory.add_option("payload_data", [incrementing_payload]) factory.add_option("ifg", [12, 0]) + factory.add_option("gbx_cfg", gbx_cfgs) factory.generate_tests() factory = TestFactory(run_test_tx_alignment) factory.add_option("payload_data", [incrementing_payload]) factory.add_option("ifg", [12]) + factory.add_option("gbx_cfg", gbx_cfgs) factory.generate_tests() for test in [run_test_tx_underrun, run_test_tx_error]: factory = TestFactory(test) factory.add_option("ifg", [12]) + factory.add_option("gbx_cfg", gbx_cfgs) factory.generate_tests() factory = TestFactory(run_test_rx_frame_sync) @@ -770,6 +826,7 @@ if cocotb.SIM_NAME: for test in [run_test_lfc, run_test_pfc]: factory = TestFactory(test) factory.add_option("ifg", [12]) + factory.add_option("gbx_cfg", gbx_cfgs) factory.generate_tests() @@ -795,8 +852,9 @@ def process_f_files(files): @pytest.mark.parametrize(("dic_en", "pfc_en"), [(1, 1), (1, 0), (0, 0)]) +@pytest.mark.parametrize("gbx_en", [1, 0]) @pytest.mark.parametrize("data_w", [64]) -def test_taxi_eth_mac_phy_10g(request, data_w, dic_en, pfc_en): +def test_taxi_eth_mac_phy_10g(request, data_w, gbx_en, dic_en, pfc_en): dut = "taxi_eth_mac_phy_10g" module = os.path.splitext(os.path.basename(__file__))[0] toplevel = module @@ -812,6 +870,8 @@ def test_taxi_eth_mac_phy_10g(request, data_w, dic_en, pfc_en): parameters['DATA_W'] = data_w parameters['HDR_W'] = 2 + parameters['TX_GBX_IF_EN'] = gbx_en + parameters['RX_GBX_IF_EN'] = parameters['TX_GBX_IF_EN'] parameters['PADDING_EN'] = 1 parameters['DIC_EN'] = dic_en parameters['MIN_FRAME_LEN'] = 64 diff --git a/src/eth/tb/taxi_eth_mac_phy_10g/test_taxi_eth_mac_phy_10g.sv b/src/eth/tb/taxi_eth_mac_phy_10g/test_taxi_eth_mac_phy_10g.sv index 2c21fb5..5e38377 100644 --- a/src/eth/tb/taxi_eth_mac_phy_10g/test_taxi_eth_mac_phy_10g.sv +++ b/src/eth/tb/taxi_eth_mac_phy_10g/test_taxi_eth_mac_phy_10g.sv @@ -20,6 +20,8 @@ module test_taxi_eth_mac_phy_10g # /* verilator lint_off WIDTHTRUNC */ parameter DATA_W = 64, parameter HDR_W = 2, + parameter logic TX_GBX_IF_EN = 1'b0, + parameter logic RX_GBX_IF_EN = TX_GBX_IF_EN, parameter logic PADDING_EN = 1'b1, parameter logic DIC_EN = 1'b1, parameter MIN_FRAME_LEN = 64, @@ -61,9 +63,16 @@ taxi_axis_if #(.DATA_W(PTP_TS_W), .KEEP_W(1), .ID_EN(1), .ID_W(TX_TAG_W)) m_axis taxi_axis_if #(.DATA_W(DATA_W), .USER_EN(1), .USER_W(RX_USER_W)) m_axis_rx(); logic [DATA_W-1:0] serdes_tx_data; +logic serdes_tx_data_valid; logic [HDR_W-1:0] serdes_tx_hdr; +logic serdes_tx_hdr_valid; +logic serdes_tx_gbx_req_start; +logic serdes_tx_gbx_req_stall; +logic serdes_tx_gbx_start; logic [DATA_W-1:0] serdes_rx_data; +logic serdes_rx_data_valid; logic [HDR_W-1:0] serdes_rx_hdr; +logic serdes_rx_hdr_valid; logic serdes_rx_bitslip; logic serdes_rx_reset_req; @@ -184,6 +193,8 @@ logic cfg_rx_pfc_en; taxi_eth_mac_phy_10g #( .DATA_W(DATA_W), .HDR_W(HDR_W), + .TX_GBX_IF_EN(TX_GBX_IF_EN), + .RX_GBX_IF_EN(RX_GBX_IF_EN), .PADDING_EN(PADDING_EN), .DIC_EN(DIC_EN), .MIN_FRAME_LEN(MIN_FRAME_LEN), @@ -229,9 +240,16 @@ uut ( * SERDES interface */ .serdes_tx_data(serdes_tx_data), + .serdes_tx_data_valid(serdes_tx_data_valid), .serdes_tx_hdr(serdes_tx_hdr), + .serdes_tx_hdr_valid(serdes_tx_hdr_valid), + .serdes_tx_gbx_req_start(serdes_tx_gbx_req_start), + .serdes_tx_gbx_req_stall(serdes_tx_gbx_req_stall), + .serdes_tx_gbx_start(serdes_tx_gbx_start), .serdes_rx_data(serdes_rx_data), + .serdes_rx_data_valid(serdes_rx_data_valid), .serdes_rx_hdr(serdes_rx_hdr), + .serdes_rx_hdr_valid(serdes_rx_hdr_valid), .serdes_rx_bitslip(serdes_rx_bitslip), .serdes_rx_reset_req(serdes_rx_reset_req), diff --git a/src/eth/tb/taxi_eth_mac_phy_10g_fifo/Makefile b/src/eth/tb/taxi_eth_mac_phy_10g_fifo/Makefile index 9bd174e..7d4c4f4 100644 --- a/src/eth/tb/taxi_eth_mac_phy_10g_fifo/Makefile +++ b/src/eth/tb/taxi_eth_mac_phy_10g_fifo/Makefile @@ -34,6 +34,8 @@ VERILOG_SOURCES := $(call uniq_base,$(call process_f_files,$(VERILOG_SOURCES))) # module parameters export PARAM_DATA_W := 64 export PARAM_HDR_W := 2 +export PARAM_TX_GBX_IF_EN := 1 +export PARAM_RX_GBX_IF_EN := $(PARAM_TX_GBX_IF_EN) export PARAM_AXIS_DATA_W := $(PARAM_DATA_W) export PARAM_PADDING_EN := 1 export PARAM_DIC_EN := 1 diff --git a/src/eth/tb/taxi_eth_mac_phy_10g_fifo/test_taxi_eth_mac_phy_10g_fifo.py b/src/eth/tb/taxi_eth_mac_phy_10g_fifo/test_taxi_eth_mac_phy_10g_fifo.py index 52e133f..aab9f84 100644 --- a/src/eth/tb/taxi_eth_mac_phy_10g_fifo/test_taxi_eth_mac_phy_10g_fifo.py +++ b/src/eth/tb/taxi_eth_mac_phy_10g_fifo/test_taxi_eth_mac_phy_10g_fifo.py @@ -38,16 +38,22 @@ except ImportError: class TB: - def __init__(self, dut): + def __init__(self, dut, gbx_cfg=None): self.dut = dut self.log = logging.getLogger("cocotb.tb") self.log.setLevel(logging.DEBUG) if len(dut.serdes_tx_data) == 64: - self.clk_period = 6.4 + if gbx_cfg: + self.clk_period = 6.206 + else: + self.clk_period = 6.4 else: - self.clk_period = 3.2 + if gbx_cfg: + self.clk_period = 3.102 + else: + self.clk_period = 3.2 cocotb.start_soon(Clock(dut.logic_clk, self.clk_period, units="ns").start()) cocotb.start_soon(Clock(dut.rx_clk, self.clk_period, units="ns").start()) @@ -55,8 +61,26 @@ class TB: cocotb.start_soon(Clock(dut.stat_clk, self.clk_period, units="ns").start()) cocotb.start_soon(Clock(dut.ptp_sample_clk, 9.9, units="ns").start()) - self.serdes_source = BaseRSerdesSource(dut.serdes_rx_data, dut.serdes_rx_hdr, dut.rx_clk, slip=dut.serdes_rx_bitslip) - self.serdes_sink = BaseRSerdesSink(dut.serdes_tx_data, dut.serdes_tx_hdr, dut.tx_clk) + self.serdes_source = BaseRSerdesSource( + data=dut.serdes_rx_data, + data_valid=dut.serdes_rx_data_valid, + hdr=dut.serdes_rx_hdr, + hdr_valid=dut.serdes_rx_hdr_valid, + clock=dut.rx_clk, + slip=dut.serdes_rx_bitslip, + gbx_cfg=gbx_cfg + ) + self.serdes_sink = BaseRSerdesSink( + data=dut.serdes_tx_data, + data_valid=dut.serdes_tx_data_valid, + hdr=dut.serdes_tx_hdr, + hdr_valid=dut.serdes_tx_hdr_valid, + gbx_req_start=dut.serdes_tx_gbx_req_start, + gbx_req_stall=dut.serdes_tx_gbx_req_stall, + gbx_start=dut.serdes_tx_gbx_start, + clock=dut.tx_clk, + gbx_cfg=gbx_cfg + ) self.axis_source = AxiStreamSource(AxiStreamBus.from_entity(dut.s_axis_tx), dut.logic_clk, dut.logic_rst) self.tx_cpl_sink = AxiStreamSink(AxiStreamBus.from_entity(dut.m_axis_tx_cpl), dut.logic_clk, dut.logic_rst) @@ -97,9 +121,9 @@ class TB: await RisingEdge(self.dut.logic_clk) -async def run_test_rx(dut, payload_lengths=None, payload_data=None, ifg=12): +async def run_test_rx(dut, gbx_cfg=None, payload_lengths=None, payload_data=None, ifg=12): - tb = TB(dut) + tb = TB(dut, gbx_cfg) tb.serdes_source.ifg = ifg tb.dut.cfg_tx_ifg.value = ifg @@ -148,17 +172,18 @@ async def run_test_rx(dut, payload_lengths=None, payload_data=None, ifg=12): assert rx_frame.tdata == test_data assert frame_error == 0 - assert abs(ptp_ts_ns - tx_frame_sfd_ns - tb.clk_period*4) < tb.clk_period*2 + if gbx_cfg is None: + assert abs(ptp_ts_ns - tx_frame_sfd_ns - tb.clk_period*4) < tb.clk_period*2 assert tb.axis_sink.empty() - await RisingEdge(dut.logic_clk) - await RisingEdge(dut.logic_clk) + for k in range(10): + await RisingEdge(dut.logic_clk) -async def run_test_tx(dut, payload_lengths=None, payload_data=None, ifg=12): +async def run_test_tx(dut, gbx_cfg=None, payload_lengths=None, payload_data=None, ifg=12): - tb = TB(dut) + tb = TB(dut, gbx_cfg) tb.serdes_source.ifg = ifg tb.dut.cfg_tx_max_pkt_len.value = 9218 @@ -197,19 +222,20 @@ async def run_test_tx(dut, payload_lengths=None, payload_data=None, ifg=12): assert rx_frame.get_payload() == test_data assert rx_frame.check_fcs() assert rx_frame.ctrl is None - assert abs(rx_frame_sfd_ns - ptp_ts_ns - tb.clk_period*5) < tb.clk_period*2 + if gbx_cfg is None: + assert abs(rx_frame_sfd_ns - ptp_ts_ns - tb.clk_period*5) < tb.clk_period*2 assert tb.serdes_sink.empty() - await RisingEdge(dut.logic_clk) - await RisingEdge(dut.logic_clk) + for k in range(10): + await RisingEdge(dut.logic_clk) -async def run_test_tx_alignment(dut, payload_data=None, ifg=12): +async def run_test_tx_alignment(dut, gbx_cfg=None, payload_data=None, ifg=12): dic_en = int(cocotb.top.DIC_EN.value) - tb = TB(dut) + tb = TB(dut, gbx_cfg) byte_width = tb.axis_source.width // 8 @@ -256,7 +282,8 @@ async def run_test_tx_alignment(dut, payload_data=None, ifg=12): assert rx_frame.get_payload() == test_data assert rx_frame.check_fcs() assert rx_frame.ctrl is None - assert abs(rx_frame_sfd_ns - ptp_ts_ns - tb.clk_period*5) < tb.clk_period*2 + if gbx_cfg is None: + assert abs(rx_frame_sfd_ns - ptp_ts_ns - tb.clk_period*5) < tb.clk_period*2 start_lane.append(rx_frame.start_lane) @@ -296,13 +323,13 @@ async def run_test_tx_alignment(dut, payload_data=None, ifg=12): assert tb.serdes_sink.empty() - await RisingEdge(dut.logic_clk) - await RisingEdge(dut.logic_clk) + for k in range(10): + await RisingEdge(dut.logic_clk) -async def run_test_rx_frame_sync(dut): +async def run_test_rx_frame_sync(dut, gbx_cfg=None): - tb = TB(dut) + tb = TB(dut, gbx_cfg) await tb.reset() @@ -352,20 +379,29 @@ def cycle_en(): if cocotb.SIM_NAME: + gbx_cfgs = [None] + + if cocotb.top.RX_GBX_IF_EN.value: + gbx_cfgs.append((33, [32])) + gbx_cfgs.append((66, [64, 65])) + for test in [run_test_rx, run_test_tx]: factory = TestFactory(test) factory.add_option("payload_lengths", [size_list]) factory.add_option("payload_data", [incrementing_payload]) factory.add_option("ifg", [12, 0]) + factory.add_option("gbx_cfg", gbx_cfgs) factory.generate_tests() factory = TestFactory(run_test_tx_alignment) factory.add_option("payload_data", [incrementing_payload]) factory.add_option("ifg", [12]) + factory.add_option("gbx_cfg", gbx_cfgs) factory.generate_tests() factory = TestFactory(run_test_rx_frame_sync) + factory.add_option("gbx_cfg", gbx_cfgs) factory.generate_tests() @@ -391,8 +427,9 @@ def process_f_files(files): @pytest.mark.parametrize("dic_en", [1, 0]) +@pytest.mark.parametrize("gbx_en", [1, 0]) @pytest.mark.parametrize("data_w", [64]) -def test_taxi_eth_mac_phy_10g_fifo(request, data_w, dic_en): +def test_taxi_eth_mac_phy_10g_fifo(request, data_w, gbx_en, dic_en): dut = "taxi_eth_mac_phy_10g_fifo" module = os.path.splitext(os.path.basename(__file__))[0] toplevel = module @@ -408,6 +445,8 @@ def test_taxi_eth_mac_phy_10g_fifo(request, data_w, dic_en): parameters['DATA_W'] = data_w parameters['HDR_W'] = 2 + parameters['TX_GBX_IF_EN'] = gbx_en + parameters['RX_GBX_IF_EN'] = parameters['TX_GBX_IF_EN'] parameters['AXIS_DATA_W'] = parameters['DATA_W'] parameters['PADDING_EN'] = 1 parameters['DIC_EN'] = dic_en diff --git a/src/eth/tb/taxi_eth_mac_phy_10g_fifo/test_taxi_eth_mac_phy_10g_fifo.sv b/src/eth/tb/taxi_eth_mac_phy_10g_fifo/test_taxi_eth_mac_phy_10g_fifo.sv index 6f8b3dd..ca417ef 100644 --- a/src/eth/tb/taxi_eth_mac_phy_10g_fifo/test_taxi_eth_mac_phy_10g_fifo.sv +++ b/src/eth/tb/taxi_eth_mac_phy_10g_fifo/test_taxi_eth_mac_phy_10g_fifo.sv @@ -18,8 +18,10 @@ Authors: module test_taxi_eth_mac_phy_10g_fifo # ( /* verilator lint_off WIDTHTRUNC */ - parameter DATA_W = 8, + parameter DATA_W = 64, parameter HDR_W = 2, + parameter logic TX_GBX_IF_EN = 1'b0, + parameter logic RX_GBX_IF_EN = TX_GBX_IF_EN, parameter AXIS_DATA_W = 8, parameter logic PADDING_EN = 1'b1, parameter logic DIC_EN = 1'b1, @@ -76,9 +78,16 @@ taxi_axis_if #(.DATA_W(96), .KEEP_W(1), .ID_EN(1), .ID_W(TX_TAG_W)) m_axis_tx_cp taxi_axis_if #(.DATA_W(AXIS_DATA_W), .USER_EN(1), .USER_W(RX_USER_W)) m_axis_rx(); logic [DATA_W-1:0] serdes_tx_data; +logic serdes_tx_data_valid; logic [HDR_W-1:0] serdes_tx_hdr; +logic serdes_tx_hdr_valid; +logic serdes_tx_gbx_req_start; +logic serdes_tx_gbx_req_stall; +logic serdes_tx_gbx_start; logic [DATA_W-1:0] serdes_rx_data; +logic serdes_rx_data_valid; logic [HDR_W-1:0] serdes_rx_hdr; +logic serdes_rx_hdr_valid; logic serdes_rx_bitslip; logic serdes_rx_reset_req; @@ -115,6 +124,8 @@ logic cfg_rx_prbs31_enable; taxi_eth_mac_phy_10g_fifo #( .DATA_W(DATA_W), .HDR_W(HDR_W), + .TX_GBX_IF_EN(TX_GBX_IF_EN), + .RX_GBX_IF_EN(RX_GBX_IF_EN), .PADDING_EN(PADDING_EN), .DIC_EN(DIC_EN), .MIN_FRAME_LEN(MIN_FRAME_LEN), @@ -174,9 +185,16 @@ uut ( * SERDES interface */ .serdes_tx_data(serdes_tx_data), + .serdes_tx_data_valid(serdes_tx_data_valid), .serdes_tx_hdr(serdes_tx_hdr), + .serdes_tx_hdr_valid(serdes_tx_hdr_valid), + .serdes_tx_gbx_req_start(serdes_tx_gbx_req_start), + .serdes_tx_gbx_req_stall(serdes_tx_gbx_req_stall), + .serdes_tx_gbx_start(serdes_tx_gbx_start), .serdes_rx_data(serdes_rx_data), + .serdes_rx_data_valid(serdes_rx_data_valid), .serdes_rx_hdr(serdes_rx_hdr), + .serdes_rx_hdr_valid(serdes_rx_hdr_valid), .serdes_rx_bitslip(serdes_rx_bitslip), .serdes_rx_reset_req(serdes_rx_reset_req), diff --git a/src/eth/tb/taxi_eth_phy_10g/Makefile b/src/eth/tb/taxi_eth_phy_10g/Makefile index 7e9ecee..0d02711 100644 --- a/src/eth/tb/taxi_eth_phy_10g/Makefile +++ b/src/eth/tb/taxi_eth_phy_10g/Makefile @@ -34,6 +34,8 @@ VERILOG_SOURCES := $(call uniq_base,$(call process_f_files,$(VERILOG_SOURCES))) export PARAM_DATA_W := 64 export PARAM_CTRL_W := $(shell expr $(PARAM_DATA_W) / 8 ) export PARAM_HDR_W := 2 +export PARAM_TX_GBX_IF_EN := 0 +export PARAM_RX_GBX_IF_EN := $(PARAM_TX_GBX_IF_EN) export PARAM_BIT_REVERSE := "1'b0" export PARAM_SCRAMBLER_DISABLE := "1'b0" export PARAM_PRBS31_EN := "1'b1" diff --git a/src/eth/tb/taxi_eth_phy_10g/test_taxi_eth_phy_10g.py b/src/eth/tb/taxi_eth_phy_10g/test_taxi_eth_phy_10g.py index 8dfdcaf..992b9b7 100644 --- a/src/eth/tb/taxi_eth_phy_10g/test_taxi_eth_phy_10g.py +++ b/src/eth/tb/taxi_eth_phy_10g/test_taxi_eth_phy_10g.py @@ -35,7 +35,7 @@ except ImportError: class TB: - def __init__(self, dut): + def __init__(self, dut, gbx_cfg=None): self.dut = dut self.log = logging.getLogger("cocotb.tb") @@ -47,8 +47,26 @@ class TB: self.xgmii_source = XgmiiSource(dut.xgmii_txd, dut.xgmii_txc, dut.tx_clk, dut.tx_rst) self.xgmii_sink = XgmiiSink(dut.xgmii_rxd, dut.xgmii_rxc, dut.rx_clk, dut.rx_rst) - self.serdes_source = BaseRSerdesSource(dut.serdes_rx_data, dut.serdes_rx_hdr, dut.rx_clk, slip=dut.serdes_rx_bitslip) - self.serdes_sink = BaseRSerdesSink(dut.serdes_tx_data, dut.serdes_tx_hdr, dut.tx_clk) + self.serdes_source = BaseRSerdesSource( + data=dut.serdes_rx_data, + data_valid=dut.serdes_rx_data_valid, + hdr=dut.serdes_rx_hdr, + hdr_valid=dut.serdes_rx_hdr_valid, + clock=dut.rx_clk, + slip=dut.serdes_rx_bitslip, + gbx_cfg=gbx_cfg + ) + self.serdes_sink = BaseRSerdesSink( + data=dut.serdes_tx_data, + data_valid=dut.serdes_tx_data_valid, + hdr=dut.serdes_tx_hdr, + hdr_valid=dut.serdes_tx_hdr_valid, + gbx_req_start=dut.serdes_tx_gbx_req_start, + gbx_req_stall=dut.serdes_tx_gbx_req_stall, + gbx_start=dut.serdes_tx_gbx_start, + clock=dut.tx_clk, + gbx_cfg=gbx_cfg + ) dut.cfg_tx_prbs31_enable.setimmediatevalue(0) dut.cfg_rx_prbs31_enable.setimmediatevalue(0) @@ -231,6 +249,8 @@ def test_taxi_eth_phy_10g(request): parameters['DATA_W'] = 64 parameters['CTRL_W'] = parameters['DATA_W'] // 8 parameters['HDR_W'] = 2 + parameters['TX_GBX_IF_EN'] = 0 + parameters['RX_GBX_IF_EN'] = parameters['TX_GBX_IF_EN'] parameters['BIT_REVERSE'] = "1'b0" parameters['SCRAMBLER_DISABLE'] = "1'b0" parameters['PRBS31_EN'] = "1'b1" diff --git a/src/eth/tb/taxi_xgmii_baser_dec_64/Makefile b/src/eth/tb/taxi_xgmii_baser_dec_64/Makefile index 5579107..6738333 100644 --- a/src/eth/tb/taxi_xgmii_baser_dec_64/Makefile +++ b/src/eth/tb/taxi_xgmii_baser_dec_64/Makefile @@ -34,6 +34,7 @@ VERILOG_SOURCES := $(call uniq_base,$(call process_f_files,$(VERILOG_SOURCES))) export PARAM_DATA_W := 64 export PARAM_CTRL_W := $(shell expr $(PARAM_DATA_W) / 8 ) export PARAM_HDR_W := 2 +export PARAM_GBX_IF_EN := 0 ifeq ($(SIM), icarus) PLUSARGS += -fst diff --git a/src/eth/tb/taxi_xgmii_baser_dec_64/test_taxi_xgmii_baser_dec_64.py b/src/eth/tb/taxi_xgmii_baser_dec_64/test_taxi_xgmii_baser_dec_64.py index d737e8b..718fa6f 100644 --- a/src/eth/tb/taxi_xgmii_baser_dec_64/test_taxi_xgmii_baser_dec_64.py +++ b/src/eth/tb/taxi_xgmii_baser_dec_64/test_taxi_xgmii_baser_dec_64.py @@ -46,6 +46,9 @@ class TB: self.source = BaseRSerdesSource(dut.encoded_rx_data, dut.encoded_rx_hdr, dut.clk, scramble=False) self.sink = XgmiiSink(dut.xgmii_rxd, dut.xgmii_rxc, dut.clk, dut.rst) + dut.encoded_rx_data_valid.setimmediatevalue(1) + dut.encoded_rx_hdr_valid.setimmediatevalue(1) + async def reset(self): self.dut.rst.setimmediatevalue(0) await RisingEdge(self.dut.clk) @@ -227,6 +230,7 @@ def test_taxi_xgmii_baser_dec_64(request): parameters['DATA_W'] = 64 parameters['CTRL_W'] = parameters['DATA_W'] // 8 parameters['HDR_W'] = 2 + parameters['GBX_IF_EN'] = 0 extra_env = {f'PARAM_{k}': str(v) for k, v in parameters.items()} diff --git a/src/eth/tb/taxi_xgmii_baser_enc_64/Makefile b/src/eth/tb/taxi_xgmii_baser_enc_64/Makefile index 4673fc6..0999a9c 100644 --- a/src/eth/tb/taxi_xgmii_baser_enc_64/Makefile +++ b/src/eth/tb/taxi_xgmii_baser_enc_64/Makefile @@ -34,6 +34,7 @@ VERILOG_SOURCES := $(call uniq_base,$(call process_f_files,$(VERILOG_SOURCES))) export PARAM_DATA_W := 64 export PARAM_CTRL_W := $(shell expr $(PARAM_DATA_W) / 8 ) export PARAM_HDR_W := 2 +export PARAM_GBX_IF_EN := 0 ifeq ($(SIM), icarus) PLUSARGS += -fst diff --git a/src/eth/tb/taxi_xgmii_baser_enc_64/test_taxi_xgmii_baser_enc_64.py b/src/eth/tb/taxi_xgmii_baser_enc_64/test_taxi_xgmii_baser_enc_64.py index da943ce..527878b 100644 --- a/src/eth/tb/taxi_xgmii_baser_enc_64/test_taxi_xgmii_baser_enc_64.py +++ b/src/eth/tb/taxi_xgmii_baser_enc_64/test_taxi_xgmii_baser_enc_64.py @@ -46,6 +46,9 @@ class TB: self.source = XgmiiSource(dut.xgmii_txd, dut.xgmii_txc, dut.clk, dut.rst) self.sink = BaseRSerdesSink(dut.encoded_tx_data, dut.encoded_tx_hdr, dut.clk, scramble=False) + dut.xgmii_tx_valid.setimmediatevalue(1) + dut.tx_gbx_start_in.setimmediatevalue(0) + async def reset(self): self.dut.rst.setimmediatevalue(0) await RisingEdge(self.dut.clk) @@ -227,6 +230,7 @@ def test_taxi_xgmii_baser_enc_64(request): parameters['DATA_W'] = 64 parameters['CTRL_W'] = parameters['DATA_W'] // 8 parameters['HDR_W'] = 2 + parameters['GBX_IF_EN'] = 0 extra_env = {f'PARAM_{k}': str(v) for k, v in parameters.items()}