eth: Integrate PTP TD leaf clock into MACs

Signed-off-by: Alex Forencich <alex@alexforencich.com>
This commit is contained in:
Alex Forencich
2026-02-13 21:54:11 -08:00
parent 380e2d521a
commit 31553f5734
30 changed files with 880 additions and 155 deletions

View File

@@ -40,8 +40,10 @@ export PARAM_PADDING_EN := 1
export PARAM_DIC_EN := 1
export PARAM_MIN_FRAME_LEN := 64
export PARAM_PTP_TS_EN := 1
export PARAM_PTP_TD_EN := $(PARAM_PTP_TS_EN)
export PARAM_PTP_TS_FMT_TOD := 1
export PARAM_PTP_TS_W := $(if $(filter-out 1,$(PARAM_PTP_TS_FMT_TOD)),64,96)
export PARAM_PTP_TD_SDI_PIPELINE := 2
export PARAM_TX_TAG_W := 16
export PARAM_PFC_EN := 1
export PARAM_PAUSE_EN := $(PARAM_PFC_EN)

View File

@@ -0,0 +1 @@
../../lib/taxi/src/ptp/tb/ptp_td.py

View File

@@ -13,6 +13,7 @@ import itertools
import logging
import os
import struct
import sys
from scapy.layers.l2 import Ether
@@ -28,6 +29,16 @@ from cocotb.regression import TestFactory
from cocotbext.eth import XgmiiFrame, XgmiiSource, XgmiiSink, PtpClockSimTime
from cocotbext.axi import AxiStreamBus, AxiStreamSource, AxiStreamSink, AxiStreamFrame
try:
from ptp_td import PtpTdSource
except ImportError:
# attempt import from current directory
sys.path.insert(0, os.path.join(os.path.dirname(__file__)))
try:
from ptp_td import PtpTdSource
finally:
del sys.path[0]
class TB:
def __init__(self, dut):
@@ -54,8 +65,20 @@ class TB:
self.stat_sink = AxiStreamSink(AxiStreamBus.from_entity(dut.m_axis_stat), dut.stat_clk, dut.stat_rst)
self.rx_ptp_clock = PtpClockSimTime(ts_tod=dut.rx_ptp_ts, clock=dut.rx_clk)
self.tx_ptp_clock = PtpClockSimTime(ts_tod=dut.tx_ptp_ts, clock=dut.tx_clk)
self.rx_ptp_clock = PtpClockSimTime(ts_tod=dut.rx_ptp_ts_in, clock=dut.rx_clk)
self.tx_ptp_clock = PtpClockSimTime(ts_tod=dut.tx_ptp_ts_in, clock=dut.tx_clk)
self.ptp_clk_period = self.clk_period
cocotb.start_soon(Clock(dut.ptp_clk, self.ptp_clk_period, units="ns").start())
cocotb.start_soon(Clock(dut.ptp_sample_clk, 8, units="ns").start())
self.ptp_td_source = PtpTdSource(
data=dut.ptp_td_sdi,
clock=dut.ptp_clk,
reset=dut.ptp_rst,
period_ns=self.ptp_clk_period
)
dut.tx_lfc_req.setimmediatevalue(0)
dut.tx_lfc_resend.setimmediatevalue(0)
@@ -112,20 +135,26 @@ class TB:
async def reset(self):
self.dut.rx_rst.setimmediatevalue(0)
self.dut.tx_rst.setimmediatevalue(0)
self.dut.ptp_rst.setimmediatevalue(0)
self.dut.stat_rst.setimmediatevalue(0)
await RisingEdge(self.dut.rx_clk)
await RisingEdge(self.dut.rx_clk)
self.dut.rx_rst.value = 1
self.dut.tx_rst.value = 1
self.dut.ptp_rst.value = 1
self.dut.stat_rst.value = 1
await RisingEdge(self.dut.rx_clk)
await RisingEdge(self.dut.rx_clk)
self.dut.rx_rst.value = 0
self.dut.tx_rst.value = 0
self.dut.ptp_rst.value = 0
self.dut.stat_rst.value = 0
await RisingEdge(self.dut.rx_clk)
await RisingEdge(self.dut.rx_clk)
self.ptp_td_source.set_ts_tod_sim_time()
self.ptp_td_source.set_ts_rel_sim_time()
async def run_test_rx(dut, payload_lengths=None, payload_data=None, ifg=12):
@@ -138,6 +167,13 @@ async def run_test_rx(dut, payload_lengths=None, payload_data=None, ifg=12):
await tb.reset()
if dut.PTP_TD_EN.value:
tb.log.info("Wait for PTP CDC lock")
while not int(dut.rx_ptp_locked.value):
await RisingEdge(dut.rx_clk)
for k in range(2000):
await RisingEdge(dut.rx_clk)
test_frames = [payload_data(x) for x in payload_lengths()]
tx_frames = []
@@ -165,7 +201,10 @@ 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) < 0.01
if dut.PTP_TD_EN.value:
assert abs(ptp_ts_ns - tx_frame_sfd_ns - tb.clk_period) < tb.clk_period*5
else:
assert abs(ptp_ts_ns - tx_frame_sfd_ns - tb.clk_period) < 0.01
assert tb.axis_sink.empty()
@@ -184,6 +223,13 @@ async def run_test_tx(dut, payload_lengths=None, payload_data=None, ifg=12):
await tb.reset()
if dut.PTP_TD_EN.value:
tb.log.info("Wait for PTP CDC lock")
while not int(dut.tx_ptp_locked.value):
await RisingEdge(dut.tx_clk)
for k in range(2000):
await RisingEdge(dut.tx_clk)
test_frames = [payload_data(x) for x in payload_lengths()]
for test_data in test_frames:
@@ -208,7 +254,10 @@ 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) < 0.01
if dut.PTP_TD_EN.value:
assert abs(rx_frame_sfd_ns - ptp_ts_ns - tb.clk_period) < tb.clk_period*5
else:
assert abs(rx_frame_sfd_ns - ptp_ts_ns - tb.clk_period) < 0.01
assert tb.xgmii_sink.empty()
@@ -231,6 +280,13 @@ async def run_test_tx_alignment(dut, payload_data=None, ifg=12):
await tb.reset()
if dut.PTP_TD_EN.value:
tb.log.info("Wait for PTP CDC lock")
while not int(dut.tx_ptp_locked.value):
await RisingEdge(dut.tx_clk)
for k in range(2000):
await RisingEdge(dut.tx_clk)
for length in range(60, 92):
for k in range(10):
@@ -261,7 +317,10 @@ 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) < 0.01
if dut.PTP_TD_EN.value:
assert abs(rx_frame_sfd_ns - ptp_ts_ns - tb.clk_period) < tb.clk_period*5
else:
assert abs(rx_frame_sfd_ns - ptp_ts_ns - tb.clk_period) < 0.01
start_lane.append(rx_frame.start_lane)
@@ -731,8 +790,9 @@ def process_f_files(files):
@pytest.mark.parametrize(("dic_en", "pfc_en"), [(1, 1), (1, 0), (0, 0)])
@pytest.mark.parametrize("ptp_td_en", [1, 0])
@pytest.mark.parametrize("data_w", [32, 64])
def test_taxi_eth_mac_10g(request, data_w, dic_en, pfc_en):
def test_taxi_eth_mac_10g(request, data_w, ptp_td_en, dic_en, pfc_en):
dut = "taxi_eth_mac_10g"
module = os.path.splitext(os.path.basename(__file__))[0]
toplevel = module
@@ -754,8 +814,10 @@ def test_taxi_eth_mac_10g(request, data_w, dic_en, pfc_en):
parameters['DIC_EN'] = dic_en
parameters['MIN_FRAME_LEN'] = 64
parameters['PTP_TS_EN'] = 1
parameters['PTP_TD_EN'] = ptp_td_en
parameters['PTP_TS_FMT_TOD'] = 1
parameters['PTP_TS_W'] = 96 if parameters['PTP_TS_FMT_TOD'] else 64
parameters['PTP_TD_SDI_PIPELINE'] = 2
parameters['TX_TAG_W'] = 16
parameters['PFC_EN'] = pfc_en
parameters['PAUSE_EN'] = parameters['PFC_EN']

View File

@@ -26,8 +26,10 @@ module test_taxi_eth_mac_10g #
parameter logic DIC_EN = 1'b1,
parameter MIN_FRAME_LEN = 64,
parameter logic PTP_TS_EN = 1'b0,
parameter logic PTP_TD_EN = PTP_TS_EN,
parameter logic PTP_TS_FMT_TOD = 1'b1,
parameter PTP_TS_W = PTP_TS_FMT_TOD ? 96 : 64,
parameter PTP_TD_SDI_PIPELINE = 2,
parameter TX_TAG_W = 16,
parameter logic PFC_EN = 1'b0,
parameter logic PAUSE_EN = PFC_EN,
@@ -65,8 +67,18 @@ logic [GBX_CNT-1:0] tx_gbx_req_sync;
logic tx_gbx_req_stall;
logic [GBX_CNT-1:0] tx_gbx_sync;
logic [PTP_TS_W-1:0] tx_ptp_ts;
logic [PTP_TS_W-1:0] rx_ptp_ts;
logic ptp_clk;
logic ptp_rst;
logic ptp_sample_clk;
logic ptp_td_sdi;
logic [PTP_TS_W-1:0] tx_ptp_ts_in;
logic [PTP_TS_W-1:0] tx_ptp_ts_out;
logic tx_ptp_ts_step_out;
logic tx_ptp_locked;
logic [PTP_TS_W-1:0] rx_ptp_ts_in;
logic [PTP_TS_W-1:0] rx_ptp_ts_out;
logic rx_ptp_ts_step_out;
logic rx_ptp_locked;
logic tx_lfc_req;
logic tx_lfc_resend;
@@ -183,8 +195,10 @@ taxi_eth_mac_10g #(
.DIC_EN(DIC_EN),
.MIN_FRAME_LEN(MIN_FRAME_LEN),
.PTP_TS_EN(PTP_TS_EN),
.PTP_TD_EN(PTP_TD_EN),
.PTP_TS_FMT_TOD(PTP_TS_FMT_TOD),
.PTP_TS_W(PTP_TS_W),
.PTP_TD_SDI_PIPELINE(PTP_TD_SDI_PIPELINE),
.PFC_EN(PFC_EN),
.PAUSE_EN(PAUSE_EN),
.STAT_EN(STAT_EN),
@@ -228,8 +242,18 @@ uut (
/*
* PTP
*/
.tx_ptp_ts(tx_ptp_ts),
.rx_ptp_ts(rx_ptp_ts),
.ptp_clk(ptp_clk),
.ptp_rst(ptp_rst),
.ptp_sample_clk(ptp_sample_clk),
.ptp_td_sdi(ptp_td_sdi),
.tx_ptp_ts_in(tx_ptp_ts_in),
.tx_ptp_ts_out(tx_ptp_ts_out),
.tx_ptp_ts_step_out(tx_ptp_ts_step_out),
.tx_ptp_locked(tx_ptp_locked),
.rx_ptp_ts_in(rx_ptp_ts_in),
.rx_ptp_ts_out(rx_ptp_ts_out),
.rx_ptp_ts_step_out(rx_ptp_ts_step_out),
.rx_ptp_locked(rx_ptp_locked),
/*
* Link-level Flow Control (LFC) (IEEE 802.3 annex 31B PAUSE)

View File

@@ -41,8 +41,10 @@ export PARAM_PADDING_EN := 1
export PARAM_DIC_EN := 1
export PARAM_MIN_FRAME_LEN := 64
export PARAM_PTP_TS_EN := 1
export PARAM_PTP_TD_EN := $(PARAM_PTP_TS_EN)
export PARAM_PTP_TS_FMT_TOD := 1
export PARAM_PTP_TS_W := $(if $(filter-out 1,$(PARAM_PTP_TS_FMT_TOD)),64,96)
export PARAM_PTP_TD_SDI_PIPELINE := 2
export PARAM_TX_TAG_W := 16
export PARAM_STAT_EN := 1
export PARAM_STAT_TX_LEVEL := 2

View File

@@ -0,0 +1 @@
../../lib/taxi/src/ptp/tb/ptp_td.py

View File

@@ -12,6 +12,7 @@ Authors:
import itertools
import logging
import os
import sys
import pytest
import cocotb_test.simulator
@@ -25,6 +26,16 @@ from cocotb.regression import TestFactory
from cocotbext.eth import XgmiiFrame, XgmiiSource, XgmiiSink, PtpClockSimTime
from cocotbext.axi import AxiStreamBus, AxiStreamSource, AxiStreamSink, AxiStreamFrame
try:
from ptp_td import PtpTdSource
except ImportError:
# attempt import from current directory
sys.path.insert(0, os.path.join(os.path.dirname(__file__)))
try:
from ptp_td import PtpTdSource
finally:
del sys.path[0]
class TB:
def __init__(self, dut):
@@ -42,7 +53,6 @@ class TB:
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())
cocotb.start_soon(Clock(dut.ptp_sample_clk, 9.9, units="ns").start())
self.xgmii_source = XgmiiSource(dut.xgmii_rxd, dut.xgmii_rxc, dut.rx_clk, dut.rx_rst)
self.xgmii_sink = XgmiiSink(dut.xgmii_txd, dut.xgmii_txc, dut.tx_clk, dut.tx_rst)
@@ -53,9 +63,20 @@ class TB:
self.stat_sink = AxiStreamSink(AxiStreamBus.from_entity(dut.m_axis_stat), dut.stat_clk, dut.stat_rst)
self.ptp_clock = PtpClockSimTime(ts_tod=dut.ptp_ts, clock=dut.logic_clk)
self.ptp_clock = PtpClockSimTime(ts_tod=dut.ptp_ts_in, clock=dut.logic_clk)
dut.ptp_ts_step_in.setimmediatevalue(0)
dut.ptp_ts_step.setimmediatevalue(0)
self.ptp_clk_period = self.clk_period
cocotb.start_soon(Clock(dut.ptp_clk, self.ptp_clk_period, units="ns").start())
cocotb.start_soon(Clock(dut.ptp_sample_clk, 8, units="ns").start())
self.ptp_td_source = PtpTdSource(
data=dut.ptp_td_sdi,
clock=dut.ptp_clk,
reset=dut.ptp_rst,
period_ns=self.ptp_clk_period
)
dut.cfg_tx_max_pkt_len.setimmediatevalue(0)
dut.cfg_tx_ifg.setimmediatevalue(0)
@@ -67,22 +88,28 @@ class TB:
self.dut.logic_rst.setimmediatevalue(0)
self.dut.rx_rst.setimmediatevalue(0)
self.dut.tx_rst.setimmediatevalue(0)
self.dut.ptp_rst.setimmediatevalue(0)
self.dut.stat_rst.setimmediatevalue(0)
await RisingEdge(self.dut.logic_clk)
await RisingEdge(self.dut.logic_clk)
self.dut.logic_rst.value = 1
self.dut.rx_rst.value = 1
self.dut.tx_rst.value = 1
self.dut.ptp_rst.value = 1
self.dut.stat_rst.value = 1
await RisingEdge(self.dut.logic_clk)
await RisingEdge(self.dut.logic_clk)
self.dut.logic_rst.value = 0
self.dut.rx_rst.value = 0
self.dut.tx_rst.value = 0
self.dut.ptp_rst.value = 0
self.dut.stat_rst.value = 0
await RisingEdge(self.dut.logic_clk)
await RisingEdge(self.dut.logic_clk)
self.ptp_td_source.set_ts_tod_sim_time()
self.ptp_td_source.set_ts_rel_sim_time()
async def run_test_rx(dut, payload_lengths=None, payload_data=None, ifg=12):
@@ -96,9 +123,9 @@ async def run_test_rx(dut, payload_lengths=None, payload_data=None, ifg=12):
await tb.reset()
tb.log.info("Wait for PTP CDC lock")
while not int(dut.uut.rx_ptp_locked.value):
while not int(dut.rx_ptp_locked.value):
await RisingEdge(dut.rx_clk)
for k in range(1000):
for k in range(2000):
await RisingEdge(dut.rx_clk)
test_frames = [payload_data(x) for x in payload_lengths()]
@@ -128,7 +155,10 @@ 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) < tb.clk_period*2
if dut.PTP_TD_EN.value:
assert abs(ptp_ts_ns - tx_frame_sfd_ns - tb.clk_period) < tb.clk_period*4
else:
assert abs(ptp_ts_ns - tx_frame_sfd_ns - tb.clk_period) < tb.clk_period*2
assert tb.axis_sink.empty()
@@ -148,9 +178,9 @@ async def run_test_tx(dut, payload_lengths=None, payload_data=None, ifg=12):
await tb.reset()
tb.log.info("Wait for PTP CDC lock")
while not int(dut.uut.tx_ptp_locked.value):
while not int(dut.tx_ptp_locked.value):
await RisingEdge(dut.tx_clk)
for k in range(1000):
for k in range(2000):
await RisingEdge(dut.tx_clk)
test_frames = [payload_data(x) for x in payload_lengths()]
@@ -177,7 +207,10 @@ 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) < tb.clk_period*2
if dut.PTP_TD_EN.value:
assert abs(rx_frame_sfd_ns - ptp_ts_ns - tb.clk_period) < tb.clk_period*4
else:
assert abs(rx_frame_sfd_ns - ptp_ts_ns - tb.clk_period) < tb.clk_period*2
assert tb.xgmii_sink.empty()
@@ -201,9 +234,9 @@ async def run_test_tx_alignment(dut, payload_data=None, ifg=12):
await tb.reset()
tb.log.info("Wait for PTP CDC lock")
while not int(dut.uut.tx_ptp_locked.value):
while not int(dut.tx_ptp_locked.value):
await RisingEdge(dut.tx_clk)
for k in range(1000):
for k in range(2000):
await RisingEdge(dut.tx_clk)
for length in range(60, 92):
@@ -236,7 +269,10 @@ 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) < tb.clk_period*2
if dut.PTP_TD_EN.value:
assert abs(rx_frame_sfd_ns - ptp_ts_ns - tb.clk_period) < tb.clk_period*4
else:
assert abs(rx_frame_sfd_ns - ptp_ts_ns - tb.clk_period) < tb.clk_period*2
start_lane.append(rx_frame.start_lane)
@@ -354,8 +390,10 @@ def test_taxi_eth_mac_10g_fifo(request, data_w, dic_en):
parameters['DIC_EN'] = dic_en
parameters['MIN_FRAME_LEN'] = 64
parameters['PTP_TS_EN'] = 1
parameters['PTP_TD_EN'] = parameters['PTP_TS_EN']
parameters['PTP_TS_FMT_TOD'] = 1
parameters['PTP_TS_W'] = 96 if parameters['PTP_TS_FMT_TOD'] else 64
parameters['PTP_TD_SDI_PIPELINE'] = 2
parameters['TX_TAG_W'] = 16
parameters['STAT_EN'] = 1
parameters['STAT_TX_LEVEL'] = 2

View File

@@ -27,8 +27,10 @@ module test_taxi_eth_mac_10g_fifo #
parameter logic DIC_EN = 1'b1,
parameter MIN_FRAME_LEN = 64,
parameter logic PTP_TS_EN = 1'b0,
parameter logic PTP_TD_EN = PTP_TS_EN,
parameter logic PTP_TS_FMT_TOD = 1'b1,
parameter PTP_TS_W = PTP_TS_FMT_TOD ? 96 : 64,
parameter PTP_TD_SDI_PIPELINE = 2,
parameter TX_TAG_W = 16,
parameter logic STAT_EN = 1'b0,
parameter STAT_TX_LEVEL = 1,
@@ -64,7 +66,6 @@ logic tx_clk;
logic tx_rst;
logic logic_clk;
logic logic_rst;
logic ptp_sample_clk;
taxi_axis_if #(.DATA_W(AXIS_DATA_W), .USER_EN(1), .USER_W(TX_USER_W), .ID_EN(1), .ID_W(TX_TAG_W)) s_axis_tx();
taxi_axis_if #(.DATA_W(96), .KEEP_W(1), .ID_EN(1), .ID_W(TX_TAG_W)) m_axis_tx_cpl();
@@ -80,8 +81,18 @@ logic [GBX_CNT-1:0] tx_gbx_req_sync;
logic tx_gbx_req_stall;
logic [GBX_CNT-1:0] tx_gbx_sync;
logic [PTP_TS_W-1:0] ptp_ts;
logic ptp_ts_step;
logic ptp_clk;
logic ptp_rst;
logic ptp_sample_clk;
logic ptp_td_sdi;
logic [PTP_TS_W-1:0] ptp_ts_in;
logic ptp_ts_step_in;
logic [PTP_TS_W-1:0] tx_ptp_ts_out;
logic tx_ptp_ts_step_out;
logic tx_ptp_locked;
logic [PTP_TS_W-1:0] rx_ptp_ts_out;
logic rx_ptp_ts_step_out;
logic rx_ptp_locked;
logic stat_clk;
logic stat_rst;
@@ -113,8 +124,10 @@ taxi_eth_mac_10g_fifo #(
.DIC_EN(DIC_EN),
.MIN_FRAME_LEN(MIN_FRAME_LEN),
.PTP_TS_EN(PTP_TS_EN),
.PTP_TD_EN(PTP_TD_EN),
.PTP_TS_FMT_TOD(PTP_TS_FMT_TOD),
.PTP_TS_W(PTP_TS_W),
.PTP_TD_SDI_PIPELINE(PTP_TD_SDI_PIPELINE),
.STAT_EN(STAT_EN),
.STAT_TX_LEVEL(STAT_TX_LEVEL),
.STAT_RX_LEVEL(STAT_RX_LEVEL),
@@ -143,7 +156,6 @@ uut (
.tx_rst(tx_rst),
.logic_clk(logic_clk),
.logic_rst(logic_rst),
.ptp_sample_clk(ptp_sample_clk),
/*
* Transmit interface (AXI stream)
@@ -172,8 +184,18 @@ uut (
/*
* PTP clock
*/
.ptp_ts(ptp_ts),
.ptp_ts_step(ptp_ts_step),
.ptp_clk(ptp_clk),
.ptp_rst(ptp_rst),
.ptp_sample_clk(ptp_sample_clk),
.ptp_td_sdi(ptp_td_sdi),
.ptp_ts_in(ptp_ts_in),
.ptp_ts_step_in(ptp_ts_step_in),
.tx_ptp_ts_out(tx_ptp_ts_out),
.tx_ptp_ts_step_out(tx_ptp_ts_step_out),
.tx_ptp_locked(tx_ptp_locked),
.rx_ptp_ts_out(rx_ptp_ts_out),
.rx_ptp_ts_step_out(rx_ptp_ts_step_out),
.rx_ptp_locked(rx_ptp_locked),
/*
* Statistics

View File

@@ -48,8 +48,10 @@ export PARAM_PADDING_EN := 1
export PARAM_DIC_EN := 1
export PARAM_MIN_FRAME_LEN := 64
export PARAM_PTP_TS_EN := 1
export PARAM_PTP_TD_EN := $(PARAM_PTP_TS_EN)
export PARAM_PTP_TS_FMT_TOD := 1
export PARAM_PTP_TS_W := $(if $(filter-out 1,$(PARAM_PTP_TS_FMT_TOD)),64,96)
export PARAM_PTP_TD_SDI_PIPELINE := 2
export PARAM_TX_TAG_W := 16
export PARAM_PRBS31_EN := 1
export PARAM_TX_SERDES_PIPELINE := 2

View File

@@ -0,0 +1 @@
../../lib/taxi/src/ptp/tb/ptp_td.py

View File

@@ -32,11 +32,13 @@ from cocotbext.axi import ApbBus, ApbMaster
try:
from baser import BaseRSerdesSource, BaseRSerdesSink
from ptp_td import PtpTdSource
except ImportError:
# attempt import from current directory
sys.path.insert(0, os.path.join(os.path.dirname(__file__)))
try:
from baser import BaseRSerdesSource, BaseRSerdesSink
from ptp_td import PtpTdSource
finally:
del sys.path[0]
@@ -118,8 +120,20 @@ class TB:
self.tx_ptp_clocks = []
for k in range(4):
self.rx_ptp_clocks.append(PtpClockSimTime(ts_tod=dut.rx_ptp_ts[k], clock=dut.uut.ch[k].ch_inst.gt.gt_inst.rx_clk))
self.tx_ptp_clocks.append(PtpClockSimTime(ts_tod=dut.tx_ptp_ts[k], clock=dut.uut.ch[k].ch_inst.gt.gt_inst.tx_clk))
self.rx_ptp_clocks.append(PtpClockSimTime(ts_tod=dut.rx_ptp_ts_in[k], clock=dut.uut.ch[k].ch_inst.gt.gt_inst.rx_clk))
self.tx_ptp_clocks.append(PtpClockSimTime(ts_tod=dut.tx_ptp_ts_in[k], clock=dut.uut.ch[k].ch_inst.gt.gt_inst.tx_clk))
self.ptp_clk_period = self.clk_period[0]
cocotb.start_soon(Clock(dut.ptp_clk, self.ptp_clk_period, units="ns").start())
cocotb.start_soon(Clock(dut.ptp_sample_clk, 8, units="ns").start())
self.ptp_td_source = PtpTdSource(
data=dut.ptp_td_sdi,
clock=dut.ptp_clk,
reset=dut.ptp_rst,
period_ns=self.ptp_clk_period
)
dut.rx_rst_in.setimmediatevalue([0]*4)
dut.tx_rst_in.setimmediatevalue([0]*4)
@@ -169,18 +183,24 @@ class TB:
async def reset(self):
self.dut.xcvr_ctrl_rst.setimmediatevalue(0)
self.dut.ptp_rst.setimmediatevalue(0)
self.dut.stat_rst.setimmediatevalue(0)
await RisingEdge(self.dut.xcvr_ctrl_clk)
await RisingEdge(self.dut.xcvr_ctrl_clk)
self.dut.xcvr_ctrl_rst.value = 1
self.dut.ptp_rst.value = 1
self.dut.stat_rst.value = 1
await RisingEdge(self.dut.xcvr_ctrl_clk)
await RisingEdge(self.dut.xcvr_ctrl_clk)
self.dut.xcvr_ctrl_rst.value = 0
self.dut.ptp_rst.value = 0
self.dut.stat_rst.value = 0
await RisingEdge(self.dut.xcvr_ctrl_clk)
await RisingEdge(self.dut.xcvr_ctrl_clk)
self.ptp_td_source.set_ts_tod_sim_time()
self.ptp_td_source.set_ts_rel_sim_time()
async def run_test_regs(dut):
tb = TB(dut)
@@ -231,6 +251,12 @@ async def run_test_rx(dut, port=0, payload_lengths=None, payload_data=None, ifg=
while not int(dut.rx_block_lock[port].value):
await RisingEdge(dut.xcvr_ctrl_clk)
tb.log.info("Wait for PTP CDC lock")
while not int(dut.rx_ptp_locked[port].value):
await RisingEdge(dut.xcvr_ctrl_clk)
for k in range(2000):
await RisingEdge(dut.xcvr_ctrl_clk)
tb.dut.cfg_rx_enable[port].value = 1
test_frames = [payload_data(x) for x in payload_lengths()]
@@ -267,7 +293,10 @@ async def run_test_rx(dut, port=0, payload_lengths=None, payload_data=None, ifg=
assert rx_frame.tdata == test_data
assert frame_error == 0
if not tb.serdes_sources[port].gbx_seq_len:
assert abs(ptp_ts_ns - tx_frame_sfd_ns - tb.clk_period[port]*pipe_delay) < 0.01
if dut.PTP_TD_EN.value:
assert abs(ptp_ts_ns - tx_frame_sfd_ns - tb.clk_period[port]*pipe_delay) < tb.clk_period[port]*3
else:
assert abs(ptp_ts_ns - tx_frame_sfd_ns - tb.clk_period[port]*pipe_delay) < 0.01
assert tb.axis_sinks[port].empty()
@@ -300,7 +329,10 @@ async def run_test_tx(dut, port=0, payload_lengths=None, payload_data=None, ifg=
while int(dut.tx_rst_out[port].value):
await RisingEdge(dut.xcvr_ctrl_clk)
for k in range(100):
tb.log.info("Wait for PTP CDC lock")
while not int(dut.tx_ptp_locked[port].value):
await RisingEdge(dut.xcvr_ctrl_clk)
for k in range(2000):
await RisingEdge(dut.xcvr_ctrl_clk)
tb.dut.cfg_tx_enable[port].value = 1
@@ -337,7 +369,10 @@ async def run_test_tx(dut, port=0, payload_lengths=None, payload_data=None, ifg=
assert rx_frame.check_fcs()
assert rx_frame.ctrl is None
if not tb.serdes_sinks[port].gbx_seq_len:
assert abs(rx_frame_sfd_ns - ptp_ts_ns - tb.clk_period[port]*pipe_delay) < 0.01
if dut.PTP_TD_EN.value:
assert abs(rx_frame_sfd_ns - ptp_ts_ns - tb.clk_period[port]*pipe_delay) < tb.clk_period[port]*3
else:
assert abs(rx_frame_sfd_ns - ptp_ts_ns - tb.clk_period[port]*pipe_delay) < 0.01
assert tb.serdes_sinks[port].empty()
@@ -374,7 +409,10 @@ async def run_test_tx_alignment(dut, port=0, payload_data=None, ifg=12):
while int(dut.tx_rst_out[port].value):
await RisingEdge(dut.xcvr_ctrl_clk)
for k in range(100):
tb.log.info("Wait for PTP CDC lock")
while not int(dut.tx_ptp_locked[port].value):
await RisingEdge(dut.xcvr_ctrl_clk)
for k in range(2000):
await RisingEdge(dut.xcvr_ctrl_clk)
tb.dut.cfg_tx_enable[port].value = 1
@@ -416,7 +454,10 @@ async def run_test_tx_alignment(dut, port=0, payload_data=None, ifg=12):
assert rx_frame.check_fcs()
assert rx_frame.ctrl is None
if not tb.serdes_sinks[port].gbx_seq_len:
assert abs(rx_frame_sfd_ns - ptp_ts_ns - tb.clk_period[port]*pipe_delay) < 0.01
if dut.PTP_TD_EN.value:
assert abs(rx_frame_sfd_ns - ptp_ts_ns - tb.clk_period[port]*pipe_delay) < tb.clk_period[port]*3
else:
assert abs(rx_frame_sfd_ns - ptp_ts_ns - tb.clk_period[port]*pipe_delay) < 0.01
start_lane.append(rx_frame.start_lane)
@@ -1024,8 +1065,10 @@ def test_taxi_eth_mac_25g_us(request, data_w, combined_mac_pcs, low_latency, dic
parameters['DIC_EN'] = dic_en
parameters['MIN_FRAME_LEN'] = 64
parameters['PTP_TS_EN'] = 1
parameters['PTP_TD_EN'] = parameters['PTP_TS_EN']
parameters['PTP_TS_FMT_TOD'] = 1
parameters['PTP_TS_W'] = 96 if parameters['PTP_TS_FMT_TOD'] else 64
parameters['PTP_TD_SDI_PIPELINE'] = 2
parameters['TX_TAG_W'] = 16
parameters['PRBS31_EN'] = 1
parameters['TX_SERDES_PIPELINE'] = 2

View File

@@ -47,8 +47,10 @@ module test_taxi_eth_mac_25g_us #
parameter logic DIC_EN = 1'b1,
parameter MIN_FRAME_LEN = 64,
parameter logic PTP_TS_EN = 1'b0,
parameter logic PTP_TD_EN = PTP_TS_EN,
parameter logic PTP_TS_FMT_TOD = 1'b1,
parameter PTP_TS_W = PTP_TS_FMT_TOD ? 96 : 64,
parameter PTP_TD_SDI_PIPELINE = 2,
parameter TX_TAG_W = 16,
parameter logic PRBS31_EN = 1'b0,
parameter TX_SERDES_PIPELINE = 1,
@@ -108,16 +110,23 @@ logic rx_rst_out[CNT];
logic tx_clk[CNT];
logic tx_rst_in[CNT];
logic tx_rst_out[CNT];
logic ptp_sample_clk[CNT];
taxi_axis_if #(.DATA_W(DATA_W), .USER_EN(1), .USER_W(TX_USER_W), .ID_EN(1), .ID_W(TX_TAG_W)) s_axis_tx[CNT]();
taxi_axis_if #(.DATA_W(PTP_TS_W), .KEEP_W(1), .ID_EN(1), .ID_W(TX_TAG_W)) m_axis_tx_cpl[CNT]();
taxi_axis_if #(.DATA_W(DATA_W), .USER_EN(1), .USER_W(RX_USER_W)) m_axis_rx[CNT]();
logic [PTP_TS_W-1:0] tx_ptp_ts[CNT];
logic tx_ptp_ts_step[CNT];
logic [PTP_TS_W-1:0] rx_ptp_ts[CNT];
logic rx_ptp_ts_step[CNT];
logic ptp_clk;
logic ptp_rst;
logic ptp_sample_clk;
logic ptp_td_sdi;
logic [PTP_TS_W-1:0] tx_ptp_ts_in[CNT];
logic [PTP_TS_W-1:0] tx_ptp_ts_out[CNT];
logic tx_ptp_ts_step_out[CNT];
logic tx_ptp_locked[CNT];
logic [PTP_TS_W-1:0] rx_ptp_ts_in[CNT];
logic [PTP_TS_W-1:0] rx_ptp_ts_out[CNT];
logic rx_ptp_ts_step_out[CNT];
logic rx_ptp_locked[CNT];
logic tx_lfc_req[CNT];
logic tx_lfc_resend[CNT];
@@ -260,8 +269,10 @@ taxi_eth_mac_25g_us #(
.DIC_EN(DIC_EN),
.MIN_FRAME_LEN(MIN_FRAME_LEN),
.PTP_TS_EN(PTP_TS_EN),
.PTP_TD_EN(PTP_TD_EN),
.PTP_TS_FMT_TOD(PTP_TS_FMT_TOD),
.PTP_TS_W(PTP_TS_W),
.PTP_TD_SDI_PIPELINE(PTP_TD_SDI_PIPELINE),
.PRBS31_EN(PRBS31_EN),
.TX_SERDES_PIPELINE(TX_SERDES_PIPELINE),
.RX_SERDES_PIPELINE(RX_SERDES_PIPELINE),
@@ -323,7 +334,6 @@ uut (
.tx_clk(tx_clk),
.tx_rst_in(tx_rst_in),
.tx_rst_out(tx_rst_out),
.ptp_sample_clk(ptp_sample_clk),
/*
* Transmit interface (AXI stream)
@@ -339,10 +349,18 @@ uut (
/*
* PTP
*/
.tx_ptp_ts(tx_ptp_ts),
.tx_ptp_ts_step(tx_ptp_ts_step),
.rx_ptp_ts(rx_ptp_ts),
.rx_ptp_ts_step(rx_ptp_ts_step),
.ptp_clk(ptp_clk),
.ptp_rst(ptp_rst),
.ptp_sample_clk(ptp_sample_clk),
.ptp_td_sdi(ptp_td_sdi),
.tx_ptp_ts_in(tx_ptp_ts_in),
.tx_ptp_ts_out(tx_ptp_ts_out),
.tx_ptp_ts_step_out(tx_ptp_ts_step_out),
.tx_ptp_locked(tx_ptp_locked),
.rx_ptp_ts_in(rx_ptp_ts_in),
.rx_ptp_ts_out(rx_ptp_ts_out),
.rx_ptp_ts_step_out(rx_ptp_ts_step_out),
.rx_ptp_locked(rx_ptp_locked),
/*
* Link-level Flow Control (LFC) (IEEE 802.3 annex 31B PAUSE)

View File

@@ -40,8 +40,10 @@ export PARAM_PADDING_EN := 1
export PARAM_DIC_EN := 1
export PARAM_MIN_FRAME_LEN := 64
export PARAM_PTP_TS_EN := 1
export PARAM_PTP_TD_EN := $(PARAM_PTP_TS_EN)
export PARAM_PTP_TS_FMT_TOD := 1
export PARAM_PTP_TS_W := $(if $(filter-out 1,$(PARAM_PTP_TS_FMT_TOD)),64,96)
export PARAM_PTP_TD_SDI_PIPELINE := 2
export PARAM_TX_TAG_W := 16
export PARAM_BIT_REVERSE := 0
export PARAM_SCRAMBLER_DISABLE := 0

View File

@@ -0,0 +1 @@
../../lib/taxi/src/ptp/tb/ptp_td.py

View File

@@ -31,11 +31,13 @@ from cocotbext.axi import AxiStreamBus, AxiStreamSource, AxiStreamSink, AxiStrea
try:
from baser import BaseRSerdesSource, BaseRSerdesSink
from ptp_td import PtpTdSource
except ImportError:
# attempt import from current directory
sys.path.insert(0, os.path.join(os.path.dirname(__file__)))
try:
from baser import BaseRSerdesSource, BaseRSerdesSink
from ptp_td import PtpTdSource
finally:
del sys.path[0]
@@ -89,8 +91,20 @@ class TB:
self.stat_sink = AxiStreamSink(AxiStreamBus.from_entity(dut.m_axis_stat), dut.stat_clk, dut.stat_rst)
self.rx_ptp_clock = PtpClockSimTime(ts_tod=dut.rx_ptp_ts, clock=dut.rx_clk)
self.tx_ptp_clock = PtpClockSimTime(ts_tod=dut.tx_ptp_ts, clock=dut.tx_clk)
self.rx_ptp_clock = PtpClockSimTime(ts_tod=dut.rx_ptp_ts_in, clock=dut.rx_clk)
self.tx_ptp_clock = PtpClockSimTime(ts_tod=dut.tx_ptp_ts_in, clock=dut.tx_clk)
self.ptp_clk_period = self.clk_period
cocotb.start_soon(Clock(dut.ptp_clk, self.ptp_clk_period, units="ns").start())
cocotb.start_soon(Clock(dut.ptp_sample_clk, 8, units="ns").start())
self.ptp_td_source = PtpTdSource(
data=dut.ptp_td_sdi,
clock=dut.ptp_clk,
reset=dut.ptp_rst,
period_ns=self.ptp_clk_period
)
dut.stat_rx_fifo_drop.setimmediatevalue(0)
@@ -136,20 +150,26 @@ class TB:
async def reset(self):
self.dut.rx_rst.setimmediatevalue(0)
self.dut.tx_rst.setimmediatevalue(0)
self.dut.ptp_rst.setimmediatevalue(0)
self.dut.stat_rst.setimmediatevalue(0)
await RisingEdge(self.dut.rx_clk)
await RisingEdge(self.dut.rx_clk)
self.dut.rx_rst.value = 1
self.dut.tx_rst.value = 1
self.dut.ptp_rst.value = 1
self.dut.stat_rst.value = 1
await RisingEdge(self.dut.rx_clk)
await RisingEdge(self.dut.rx_clk)
self.dut.rx_rst.value = 0
self.dut.tx_rst.value = 0
self.dut.ptp_rst.value = 0
self.dut.stat_rst.value = 0
await RisingEdge(self.dut.rx_clk)
await RisingEdge(self.dut.rx_clk)
self.ptp_td_source.set_ts_tod_sim_time()
self.ptp_td_source.set_ts_rel_sim_time()
async def run_test_rx(dut, gbx_cfg=None, payload_lengths=None, payload_data=None, ifg=12):
@@ -172,6 +192,13 @@ async def run_test_rx(dut, gbx_cfg=None, payload_lengths=None, payload_data=None
while not int(dut.rx_block_lock.value):
await RisingEdge(dut.rx_clk)
if dut.PTP_TD_EN.value:
tb.log.info("Wait for PTP CDC lock")
while not int(dut.rx_ptp_locked.value):
await RisingEdge(dut.rx_clk)
for k in range(2000):
await RisingEdge(dut.rx_clk)
tb.dut.cfg_rx_enable.value = 1
test_frames = [payload_data(x) for x in payload_lengths()]
@@ -208,7 +235,10 @@ async def run_test_rx(dut, gbx_cfg=None, payload_lengths=None, payload_data=None
assert rx_frame.tdata == test_data
assert frame_error == 0
if gbx_cfg is None:
assert abs(ptp_ts_ns - tx_frame_sfd_ns - tb.clk_period*pipe_delay) < 0.01
if dut.PTP_TD_EN.value:
assert abs(ptp_ts_ns - tx_frame_sfd_ns - tb.clk_period*pipe_delay) < tb.clk_period*5
else:
assert abs(ptp_ts_ns - tx_frame_sfd_ns - tb.clk_period*pipe_delay) < 0.01
assert tb.axis_sink.empty()
@@ -231,8 +261,15 @@ async def run_test_tx(dut, gbx_cfg=None, payload_lengths=None, payload_data=None
await tb.reset()
for k in range(100):
await RisingEdge(dut.tx_clk)
if dut.PTP_TD_EN.value:
tb.log.info("Wait for PTP CDC lock")
while not int(dut.tx_ptp_locked.value):
await RisingEdge(dut.tx_clk)
for k in range(2000):
await RisingEdge(dut.tx_clk)
else:
for k in range(100):
await RisingEdge(dut.tx_clk)
tb.dut.cfg_tx_enable.value = 1
tb.serdes_sink.clear()
@@ -266,7 +303,10 @@ async def run_test_tx(dut, gbx_cfg=None, payload_lengths=None, payload_data=None
assert rx_frame.check_fcs()
assert rx_frame.ctrl is None
if gbx_cfg is None:
assert abs(rx_frame_sfd_ns - ptp_ts_ns - tb.clk_period*pipe_delay) < 0.01
if dut.PTP_TD_EN.value:
assert abs(rx_frame_sfd_ns - ptp_ts_ns - tb.clk_period*pipe_delay) < tb.clk_period*5
else:
assert abs(rx_frame_sfd_ns - ptp_ts_ns - tb.clk_period*pipe_delay) < 0.01
assert tb.serdes_sink.empty()
@@ -293,8 +333,15 @@ async def run_test_tx_alignment(dut, gbx_cfg=None, payload_data=None, ifg=12):
await tb.reset()
for k in range(100):
await RisingEdge(dut.tx_clk)
if dut.PTP_TD_EN.value:
tb.log.info("Wait for PTP CDC lock")
while not int(dut.tx_ptp_locked.value):
await RisingEdge(dut.tx_clk)
for k in range(2000):
await RisingEdge(dut.tx_clk)
else:
for k in range(100):
await RisingEdge(dut.tx_clk)
tb.dut.cfg_tx_enable.value = 1
tb.serdes_sink.clear()
@@ -333,7 +380,10 @@ async def run_test_tx_alignment(dut, gbx_cfg=None, payload_data=None, ifg=12):
assert rx_frame.check_fcs()
assert rx_frame.ctrl is None
if gbx_cfg is None:
assert abs(rx_frame_sfd_ns - ptp_ts_ns - tb.clk_period*pipe_delay) < 0.01
if dut.PTP_TD_EN.value:
assert abs(rx_frame_sfd_ns - ptp_ts_ns - tb.clk_period*pipe_delay) < tb.clk_period*5
else:
assert abs(rx_frame_sfd_ns - ptp_ts_ns - tb.clk_period*pipe_delay) < 0.01
start_lane.append(rx_frame.start_lane)
@@ -885,8 +935,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("ptp_td_en", [1, 0])
@pytest.mark.parametrize("data_w", [32, 64])
def test_taxi_eth_mac_phy_10g(request, data_w, gbx_en, dic_en, pfc_en):
def test_taxi_eth_mac_phy_10g(request, data_w, ptp_td_en, gbx_en, dic_en, pfc_en):
dut = "taxi_eth_mac_phy_10g"
module = os.path.splitext(os.path.basename(__file__))[0]
toplevel = module
@@ -908,8 +959,10 @@ def test_taxi_eth_mac_phy_10g(request, data_w, gbx_en, dic_en, pfc_en):
parameters['DIC_EN'] = dic_en
parameters['MIN_FRAME_LEN'] = 64
parameters['PTP_TS_EN'] = 1
parameters['PTP_TD_EN'] = ptp_td_en
parameters['PTP_TS_FMT_TOD'] = 1
parameters['PTP_TS_W'] = 96 if parameters['PTP_TS_FMT_TOD'] else 64
parameters['PTP_TD_SDI_PIPELINE'] = 2
parameters['TX_TAG_W'] = 16
parameters['BIT_REVERSE'] = 0
parameters['SCRAMBLER_DISABLE'] = 0

View File

@@ -26,8 +26,10 @@ module test_taxi_eth_mac_phy_10g #
parameter logic DIC_EN = 1'b1,
parameter MIN_FRAME_LEN = 64,
parameter logic PTP_TS_EN = 1'b0,
parameter logic PTP_TD_EN = PTP_TS_EN,
parameter logic PTP_TS_FMT_TOD = 1'b1,
parameter PTP_TS_W = PTP_TS_FMT_TOD ? 96 : 64,
parameter PTP_TD_SDI_PIPELINE = 2,
parameter TX_TAG_W = 16,
parameter logic BIT_REVERSE = 1'b0,
parameter logic SCRAMBLER_DISABLE = 1'b0,
@@ -76,8 +78,18 @@ logic serdes_rx_hdr_valid;
logic serdes_rx_bitslip;
logic serdes_rx_reset_req;
logic [PTP_TS_W-1:0] tx_ptp_ts;
logic [PTP_TS_W-1:0] rx_ptp_ts;
logic ptp_clk;
logic ptp_rst;
logic ptp_sample_clk;
logic ptp_td_sdi;
logic [PTP_TS_W-1:0] tx_ptp_ts_in;
logic [PTP_TS_W-1:0] tx_ptp_ts_out;
logic tx_ptp_ts_step_out;
logic tx_ptp_locked;
logic [PTP_TS_W-1:0] rx_ptp_ts_in;
logic [PTP_TS_W-1:0] rx_ptp_ts_out;
logic rx_ptp_ts_step_out;
logic rx_ptp_locked;
logic tx_lfc_req;
logic tx_lfc_resend;
@@ -199,8 +211,10 @@ taxi_eth_mac_phy_10g #(
.DIC_EN(DIC_EN),
.MIN_FRAME_LEN(MIN_FRAME_LEN),
.PTP_TS_EN(PTP_TS_EN),
.PTP_TD_EN(PTP_TD_EN),
.PTP_TS_FMT_TOD(PTP_TS_FMT_TOD),
.PTP_TS_W(PTP_TS_W),
.PTP_TD_SDI_PIPELINE(PTP_TD_SDI_PIPELINE),
.BIT_REVERSE(BIT_REVERSE),
.SCRAMBLER_DISABLE(SCRAMBLER_DISABLE),
.PRBS31_EN(PRBS31_EN),
@@ -256,8 +270,18 @@ uut (
/*
* PTP
*/
.tx_ptp_ts(tx_ptp_ts),
.rx_ptp_ts(rx_ptp_ts),
.ptp_clk(ptp_clk),
.ptp_rst(ptp_rst),
.ptp_sample_clk(ptp_sample_clk),
.ptp_td_sdi(ptp_td_sdi),
.tx_ptp_ts_in(tx_ptp_ts_in),
.tx_ptp_ts_out(tx_ptp_ts_out),
.tx_ptp_ts_step_out(tx_ptp_ts_step_out),
.tx_ptp_locked(tx_ptp_locked),
.rx_ptp_ts_in(rx_ptp_ts_in),
.rx_ptp_ts_out(rx_ptp_ts_out),
.rx_ptp_ts_step_out(rx_ptp_ts_step_out),
.rx_ptp_locked(rx_ptp_locked),
/*
* Link-level Flow Control (LFC) (IEEE 802.3 annex 31B PAUSE)

View File

@@ -41,8 +41,10 @@ export PARAM_PADDING_EN := 1
export PARAM_DIC_EN := 1
export PARAM_MIN_FRAME_LEN := 64
export PARAM_PTP_TS_EN := 1
export PARAM_PTP_TD_EN := $(PARAM_PTP_TS_EN)
export PARAM_PTP_TS_FMT_TOD := 1
export PARAM_PTP_TS_W := $(if $(filter-out 1,$(PARAM_PTP_TS_FMT_TOD)),64,96)
export PARAM_PTP_TD_SDI_PIPELINE := 2
export PARAM_TX_TAG_W := 16
export PARAM_BIT_REVERSE := 0
export PARAM_SCRAMBLER_DISABLE := 0

View File

@@ -0,0 +1 @@
../../lib/taxi/src/ptp/tb/ptp_td.py

View File

@@ -28,11 +28,13 @@ from cocotbext.axi import AxiStreamBus, AxiStreamSource, AxiStreamSink, AxiStrea
try:
from baser import BaseRSerdesSource, BaseRSerdesSink
from ptp_td import PtpTdSource
except ImportError:
# attempt import from current directory
sys.path.insert(0, os.path.join(os.path.dirname(__file__)))
try:
from baser import BaseRSerdesSource, BaseRSerdesSink
from ptp_td import PtpTdSource
finally:
del sys.path[0]
@@ -59,7 +61,6 @@ class TB:
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())
cocotb.start_soon(Clock(dut.ptp_sample_clk, 9.9, units="ns").start())
self.serdes_source = BaseRSerdesSource(
data=dut.serdes_rx_data,
@@ -88,9 +89,20 @@ class TB:
self.stat_sink = AxiStreamSink(AxiStreamBus.from_entity(dut.m_axis_stat), dut.stat_clk, dut.stat_rst)
self.ptp_clock = PtpClockSimTime(ts_tod=dut.ptp_ts, clock=dut.logic_clk)
self.ptp_clock = PtpClockSimTime(ts_tod=dut.ptp_ts_in, clock=dut.logic_clk)
dut.ptp_ts_step_in.setimmediatevalue(0)
dut.ptp_ts_step.setimmediatevalue(0)
self.ptp_clk_period = self.clk_period
cocotb.start_soon(Clock(dut.ptp_clk, self.ptp_clk_period, units="ns").start())
cocotb.start_soon(Clock(dut.ptp_sample_clk, 8, units="ns").start())
self.ptp_td_source = PtpTdSource(
data=dut.ptp_td_sdi,
clock=dut.ptp_clk,
reset=dut.ptp_rst,
period_ns=self.ptp_clk_period
)
dut.cfg_tx_max_pkt_len.setimmediatevalue(0)
dut.cfg_tx_ifg.setimmediatevalue(0)
@@ -104,22 +116,28 @@ class TB:
self.dut.logic_rst.setimmediatevalue(0)
self.dut.rx_rst.setimmediatevalue(0)
self.dut.tx_rst.setimmediatevalue(0)
self.dut.ptp_rst.setimmediatevalue(0)
self.dut.stat_rst.setimmediatevalue(0)
await RisingEdge(self.dut.logic_clk)
await RisingEdge(self.dut.logic_clk)
self.dut.logic_rst.value = 1
self.dut.rx_rst.value = 1
self.dut.tx_rst.value = 1
self.dut.ptp_rst.value = 1
self.dut.stat_rst.value = 1
await RisingEdge(self.dut.logic_clk)
await RisingEdge(self.dut.logic_clk)
self.dut.logic_rst.value = 0
self.dut.rx_rst.value = 0
self.dut.tx_rst.value = 0
self.dut.ptp_rst.value = 0
self.dut.stat_rst.value = 0
await RisingEdge(self.dut.logic_clk)
await RisingEdge(self.dut.logic_clk)
self.ptp_td_source.set_ts_tod_sim_time()
self.ptp_td_source.set_ts_rel_sim_time()
async def run_test_rx(dut, gbx_cfg=None, payload_lengths=None, payload_data=None, ifg=12):
@@ -142,9 +160,9 @@ async def run_test_rx(dut, gbx_cfg=None, payload_lengths=None, payload_data=None
await RisingEdge(dut.rx_clk)
tb.log.info("Wait for PTP CDC lock")
while not int(dut.uut.rx_ptp_locked.value):
while not int(dut.rx_ptp_locked.value):
await RisingEdge(dut.rx_clk)
for k in range(1000):
for k in range(2000):
await RisingEdge(dut.rx_clk)
# clear out sink buffer
@@ -181,7 +199,10 @@ async def run_test_rx(dut, gbx_cfg=None, payload_lengths=None, payload_data=None
assert rx_frame.tdata == test_data
assert frame_error == 0
if gbx_cfg is None:
assert abs(ptp_ts_ns - tx_frame_sfd_ns - tb.clk_period*pipe_delay) < tb.clk_period*2
if dut.PTP_TD_EN.value:
assert abs(ptp_ts_ns - tx_frame_sfd_ns - tb.clk_period*pipe_delay) < tb.clk_period*5
else:
assert abs(ptp_ts_ns - tx_frame_sfd_ns - tb.clk_period*pipe_delay) < tb.clk_period*2
assert tb.axis_sink.empty()
@@ -205,9 +226,9 @@ async def run_test_tx(dut, gbx_cfg=None, payload_lengths=None, payload_data=None
await tb.reset()
tb.log.info("Wait for PTP CDC lock")
while not int(dut.uut.tx_ptp_locked.value):
while not int(dut.tx_ptp_locked.value):
await RisingEdge(dut.tx_clk)
for k in range(1000):
for k in range(2000):
await RisingEdge(dut.tx_clk)
tb.dut.cfg_tx_enable.value = 1
@@ -241,7 +262,10 @@ async def run_test_tx(dut, gbx_cfg=None, payload_lengths=None, payload_data=None
assert rx_frame.check_fcs()
assert rx_frame.ctrl is None
if gbx_cfg is None:
assert abs(rx_frame_sfd_ns - ptp_ts_ns - tb.clk_period*pipe_delay) < tb.clk_period*2
if dut.PTP_TD_EN.value:
assert abs(rx_frame_sfd_ns - ptp_ts_ns - tb.clk_period*pipe_delay) < tb.clk_period*5
else:
assert abs(rx_frame_sfd_ns - ptp_ts_ns - tb.clk_period*pipe_delay) < tb.clk_period*2
assert tb.serdes_sink.empty()
@@ -269,9 +293,9 @@ async def run_test_tx_alignment(dut, gbx_cfg=None, payload_data=None, ifg=12):
await tb.reset()
tb.log.info("Wait for PTP CDC lock")
while not int(dut.uut.tx_ptp_locked.value):
while not int(dut.tx_ptp_locked.value):
await RisingEdge(dut.tx_clk)
for k in range(1000):
for k in range(2000):
await RisingEdge(dut.tx_clk)
tb.dut.cfg_tx_enable.value = 1
@@ -311,7 +335,10 @@ async def run_test_tx_alignment(dut, gbx_cfg=None, payload_data=None, ifg=12):
assert rx_frame.check_fcs()
assert rx_frame.ctrl is None
if gbx_cfg is None:
assert abs(rx_frame_sfd_ns - ptp_ts_ns - tb.clk_period*pipe_delay) < tb.clk_period*2
if dut.PTP_TD_EN.value:
assert abs(rx_frame_sfd_ns - ptp_ts_ns - tb.clk_period*pipe_delay) < tb.clk_period*5
else:
assert abs(rx_frame_sfd_ns - ptp_ts_ns - tb.clk_period*pipe_delay) < tb.clk_period*2
start_lane.append(rx_frame.start_lane)
@@ -481,8 +508,10 @@ def test_taxi_eth_mac_phy_10g_fifo(request, data_w, gbx_en, dic_en):
parameters['DIC_EN'] = dic_en
parameters['MIN_FRAME_LEN'] = 64
parameters['PTP_TS_EN'] = 1
parameters['PTP_TD_EN'] = parameters['PTP_TS_EN']
parameters['PTP_TS_FMT_TOD'] = 1
parameters['PTP_TS_W'] = 96 if parameters['PTP_TS_FMT_TOD'] else 64
parameters['PTP_TD_SDI_PIPELINE'] = 2
parameters['TX_TAG_W'] = 16
parameters['BIT_REVERSE'] = 0
parameters['SCRAMBLER_DISABLE'] = 0

View File

@@ -27,8 +27,10 @@ module test_taxi_eth_mac_phy_10g_fifo #
parameter logic DIC_EN = 1'b1,
parameter MIN_FRAME_LEN = 64,
parameter logic PTP_TS_EN = 1'b0,
parameter logic PTP_TD_EN = PTP_TS_EN,
parameter logic PTP_TS_FMT_TOD = 1'b1,
parameter PTP_TS_W = PTP_TS_FMT_TOD ? 96 : 64,
parameter PTP_TD_SDI_PIPELINE = 2,
parameter TX_TAG_W = 16,
parameter logic BIT_REVERSE = 1'b0,
parameter logic SCRAMBLER_DISABLE = 1'b0,
@@ -71,7 +73,6 @@ logic tx_clk;
logic tx_rst;
logic logic_clk;
logic logic_rst;
logic ptp_sample_clk;
taxi_axis_if #(.DATA_W(AXIS_DATA_W), .USER_EN(1), .USER_W(TX_USER_W), .ID_EN(1), .ID_W(TX_TAG_W)) s_axis_tx();
taxi_axis_if #(.DATA_W(96), .KEEP_W(1), .ID_EN(1), .ID_W(TX_TAG_W)) m_axis_tx_cpl();
@@ -91,8 +92,18 @@ logic serdes_rx_hdr_valid;
logic serdes_rx_bitslip;
logic serdes_rx_reset_req;
logic [PTP_TS_W-1:0] ptp_ts;
logic ptp_ts_step;
logic ptp_clk;
logic ptp_rst;
logic ptp_sample_clk;
logic ptp_td_sdi;
logic [PTP_TS_W-1:0] ptp_ts_in;
logic ptp_ts_step_in;
logic [PTP_TS_W-1:0] tx_ptp_ts_out;
logic tx_ptp_ts_step_out;
logic tx_ptp_locked;
logic [PTP_TS_W-1:0] rx_ptp_ts_out;
logic rx_ptp_ts_step_out;
logic rx_ptp_locked;
logic stat_clk;
logic stat_rst;
@@ -130,8 +141,10 @@ taxi_eth_mac_phy_10g_fifo #(
.DIC_EN(DIC_EN),
.MIN_FRAME_LEN(MIN_FRAME_LEN),
.PTP_TS_EN(PTP_TS_EN),
.PTP_TD_EN(PTP_TD_EN),
.PTP_TS_FMT_TOD(PTP_TS_FMT_TOD),
.PTP_TS_W(PTP_TS_W),
.PTP_TD_SDI_PIPELINE(PTP_TD_SDI_PIPELINE),
.BIT_REVERSE(BIT_REVERSE),
.SCRAMBLER_DISABLE(SCRAMBLER_DISABLE),
.PRBS31_EN(PRBS31_EN),
@@ -168,7 +181,6 @@ uut (
.tx_rst(tx_rst),
.logic_clk(logic_clk),
.logic_rst(logic_rst),
.ptp_sample_clk(ptp_sample_clk),
/*
* Transmit interface (AXI stream)
@@ -201,8 +213,18 @@ uut (
/*
* PTP clock
*/
.ptp_ts(ptp_ts),
.ptp_ts_step(ptp_ts_step),
.ptp_clk(ptp_clk),
.ptp_rst(ptp_rst),
.ptp_sample_clk(ptp_sample_clk),
.ptp_td_sdi(ptp_td_sdi),
.ptp_ts_in(ptp_ts_in),
.ptp_ts_step_in(ptp_ts_step_in),
.tx_ptp_ts_out(tx_ptp_ts_out),
.tx_ptp_ts_step_out(tx_ptp_ts_step_out),
.tx_ptp_locked(tx_ptp_locked),
.rx_ptp_ts_out(rx_ptp_ts_out),
.rx_ptp_ts_step_out(rx_ptp_ts_step_out),
.rx_ptp_locked(rx_ptp_locked),
/*
* Statistics