mirror of
https://github.com/fpganinja/taxi.git
synced 2025-12-12 18:18:39 -08:00
eth: Add support for synchronous gearbox to PHY, MAC+PHY, and GT wrappers
Signed-off-by: Alex Forencich <alex@alexforencich.com>
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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),
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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),
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user