mirror of
https://github.com/fpganinja/taxi.git
synced 2026-04-08 13:08:42 -07:00
cndm: Copy cndm-micro core logic as cndm-lite
Signed-off-by: Alex Forencich <alex@alexforencich.com>
This commit is contained in:
71
src/cndm/tb/cndm_lite_pcie_us/Makefile
Normal file
71
src/cndm/tb/cndm_lite_pcie_us/Makefile
Normal file
@@ -0,0 +1,71 @@
|
||||
# SPDX-License-Identifier: CERN-OHL-S-2.0
|
||||
#
|
||||
# Copyright (c) 2020-2026 FPGA Ninja, LLC
|
||||
#
|
||||
# Authors:
|
||||
# - Alex Forencich
|
||||
|
||||
TOPLEVEL_LANG = verilog
|
||||
|
||||
SIM ?= verilator
|
||||
WAVES ?= 0
|
||||
|
||||
COCOTB_HDL_TIMEUNIT = 1ns
|
||||
COCOTB_HDL_TIMEPRECISION = 1ps
|
||||
|
||||
RTL_DIR = ../../rtl
|
||||
LIB_DIR = ../../lib
|
||||
TAXI_SRC_DIR = $(LIB_DIR)/taxi/src
|
||||
|
||||
DUT = cndm_lite_pcie_us
|
||||
COCOTB_TEST_MODULES = test_$(DUT)
|
||||
COCOTB_TOPLEVEL = test_$(DUT)
|
||||
MODULE = $(COCOTB_TEST_MODULES)
|
||||
TOPLEVEL = $(COCOTB_TOPLEVEL)
|
||||
VERILOG_SOURCES += $(COCOTB_TOPLEVEL).sv
|
||||
VERILOG_SOURCES += $(RTL_DIR)/$(DUT).f
|
||||
|
||||
# handle file list files
|
||||
process_f_file = $(call process_f_files,$(addprefix $(dir $1),$(shell cat $1)))
|
||||
process_f_files = $(foreach f,$1,$(if $(filter %.f,$f),$(call process_f_file,$f),$f))
|
||||
uniq_base = $(if $1,$(call uniq_base,$(foreach f,$1,$(if $(filter-out $(notdir $(lastword $1)),$(notdir $f)),$f,))) $(lastword $1))
|
||||
VERILOG_SOURCES := $(call uniq_base,$(call process_f_files,$(VERILOG_SOURCES)))
|
||||
|
||||
# module parameters
|
||||
export PARAM_SIM := "1'b1"
|
||||
export PARAM_VENDOR := "\"XILINX\""
|
||||
export PARAM_FAMILY := "\"virtexuplus\""
|
||||
|
||||
# Structural configuration
|
||||
export PARAM_PORTS := 2
|
||||
|
||||
# PTP configuration
|
||||
export PARAM_PTP_TS_EN := 1
|
||||
export PARAM_PTP_TS_FMT_TOD := 0
|
||||
export PARAM_PTP_CLK_PER_NS_NUM := 512
|
||||
export PARAM_PTP_CLK_PER_NS_DENOM := 165
|
||||
|
||||
# PCIe interface configuration
|
||||
export PARAM_AXIS_PCIE_DATA_W := 512
|
||||
|
||||
# AXI lite interface configuration (control)
|
||||
export PARAM_AXIL_CTRL_DATA_W := 32
|
||||
export PARAM_AXIL_CTRL_ADDR_W := 24
|
||||
|
||||
# MAC configuration
|
||||
export PARAM_MAC_DATA_W := 512
|
||||
|
||||
ifeq ($(SIM), icarus)
|
||||
PLUSARGS += -fst
|
||||
|
||||
COMPILE_ARGS += $(foreach v,$(filter PARAM_%,$(.VARIABLES)),-P $(COCOTB_TOPLEVEL).$(subst PARAM_,,$(v))=$($(v)))
|
||||
else ifeq ($(SIM), verilator)
|
||||
COMPILE_ARGS += $(foreach v,$(filter PARAM_%,$(.VARIABLES)),-G$(subst PARAM_,,$(v))=$($(v)))
|
||||
|
||||
ifeq ($(WAVES), 1)
|
||||
COMPILE_ARGS += --trace-fst
|
||||
VERILATOR_TRACE = 1
|
||||
endif
|
||||
endif
|
||||
|
||||
include $(shell cocotb-config --makefiles)/Makefile.sim
|
||||
1
src/cndm/tb/cndm_lite_pcie_us/cndm.py
Symbolic link
1
src/cndm/tb/cndm_lite_pcie_us/cndm.py
Symbolic link
@@ -0,0 +1 @@
|
||||
../cndm.py
|
||||
516
src/cndm/tb/cndm_lite_pcie_us/test_cndm_lite_pcie_us.py
Normal file
516
src/cndm/tb/cndm_lite_pcie_us/test_cndm_lite_pcie_us.py
Normal file
@@ -0,0 +1,516 @@
|
||||
#!/usr/bin/env python
|
||||
# SPDX-License-Identifier: CERN-OHL-S-2.0
|
||||
"""
|
||||
|
||||
Copyright (c) 2020-2026 FPGA Ninja, LLC
|
||||
|
||||
Authors:
|
||||
- Alex Forencich
|
||||
|
||||
"""
|
||||
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
import cocotb_test.simulator
|
||||
|
||||
import cocotb
|
||||
from cocotb.clock import Clock
|
||||
from cocotb.triggers import RisingEdge, FallingEdge, Timer
|
||||
|
||||
from cocotbext.axi import AxiStreamBus
|
||||
from cocotbext.eth import EthMac
|
||||
from cocotbext.pcie.core import RootComplex
|
||||
from cocotbext.pcie.xilinx.us import UltraScalePlusPcieDevice
|
||||
|
||||
try:
|
||||
import cndm
|
||||
except ImportError:
|
||||
# attempt import from current directory
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__)))
|
||||
try:
|
||||
import cndm
|
||||
finally:
|
||||
del sys.path[0]
|
||||
|
||||
|
||||
class TB:
|
||||
def __init__(self, dut):
|
||||
self.dut = dut
|
||||
|
||||
self.log = logging.getLogger("cocotb.tb")
|
||||
self.log.setLevel(logging.DEBUG)
|
||||
|
||||
# PCIe
|
||||
self.rc = RootComplex()
|
||||
|
||||
self.rc.max_payload_size = 0x1 # 256 bytes
|
||||
self.rc.max_read_request_size = 0x2 # 512 bytes
|
||||
|
||||
self.dev = UltraScalePlusPcieDevice(
|
||||
# configuration options
|
||||
pcie_generation=3,
|
||||
#pcie_link_width=16,
|
||||
user_clk_frequency=250e6,
|
||||
alignment="dword",
|
||||
cq_straddle=False,
|
||||
cc_straddle=False,
|
||||
rq_straddle=False,
|
||||
rc_straddle=False,
|
||||
rc_4tlp_straddle=False,
|
||||
pf_count=1,
|
||||
max_payload_size=1024,
|
||||
enable_client_tag=True,
|
||||
enable_extended_tag=True,
|
||||
enable_parity=False,
|
||||
enable_rx_msg_interface=False,
|
||||
enable_sriov=False,
|
||||
enable_extended_configuration=False,
|
||||
|
||||
pf0_msi_enable=True,
|
||||
pf0_msi_count=32,
|
||||
pf1_msi_enable=False,
|
||||
pf1_msi_count=1,
|
||||
pf2_msi_enable=False,
|
||||
pf2_msi_count=1,
|
||||
pf3_msi_enable=False,
|
||||
pf3_msi_count=1,
|
||||
pf0_msix_enable=False,
|
||||
pf0_msix_table_size=31,
|
||||
pf0_msix_table_bir=4,
|
||||
pf0_msix_table_offset=0x00000000,
|
||||
pf0_msix_pba_bir=4,
|
||||
pf0_msix_pba_offset=0x00008000,
|
||||
pf1_msix_enable=False,
|
||||
pf1_msix_table_size=0,
|
||||
pf1_msix_table_bir=0,
|
||||
pf1_msix_table_offset=0x00000000,
|
||||
pf1_msix_pba_bir=0,
|
||||
pf1_msix_pba_offset=0x00000000,
|
||||
pf2_msix_enable=False,
|
||||
pf2_msix_table_size=0,
|
||||
pf2_msix_table_bir=0,
|
||||
pf2_msix_table_offset=0x00000000,
|
||||
pf2_msix_pba_bir=0,
|
||||
pf2_msix_pba_offset=0x00000000,
|
||||
pf3_msix_enable=False,
|
||||
pf3_msix_table_size=0,
|
||||
pf3_msix_table_bir=0,
|
||||
pf3_msix_table_offset=0x00000000,
|
||||
pf3_msix_pba_bir=0,
|
||||
pf3_msix_pba_offset=0x00000000,
|
||||
|
||||
# signals
|
||||
# Clock and Reset Interface
|
||||
user_clk=dut.pcie_clk,
|
||||
user_reset=dut.pcie_rst,
|
||||
# user_lnk_up
|
||||
# sys_clk
|
||||
# sys_clk_gt
|
||||
# sys_reset
|
||||
# phy_rdy_out
|
||||
|
||||
# Requester reQuest Interface
|
||||
rq_bus=AxiStreamBus.from_entity(dut.m_axis_pcie_rq),
|
||||
pcie_rq_seq_num0=dut.pcie_rq_seq_num0,
|
||||
pcie_rq_seq_num_vld0=dut.pcie_rq_seq_num_vld0,
|
||||
pcie_rq_seq_num1=dut.pcie_rq_seq_num1,
|
||||
pcie_rq_seq_num_vld1=dut.pcie_rq_seq_num_vld1,
|
||||
# pcie_rq_tag0
|
||||
# pcie_rq_tag1
|
||||
# pcie_rq_tag_av
|
||||
# pcie_rq_tag_vld0
|
||||
# pcie_rq_tag_vld1
|
||||
|
||||
# Requester Completion Interface
|
||||
rc_bus=AxiStreamBus.from_entity(dut.s_axis_pcie_rc),
|
||||
|
||||
# Completer reQuest Interface
|
||||
cq_bus=AxiStreamBus.from_entity(dut.s_axis_pcie_cq),
|
||||
# pcie_cq_np_req
|
||||
# pcie_cq_np_req_count
|
||||
|
||||
# Completer Completion Interface
|
||||
cc_bus=AxiStreamBus.from_entity(dut.m_axis_pcie_cc),
|
||||
|
||||
# Transmit Flow Control Interface
|
||||
# pcie_tfc_nph_av=dut.pcie_tfc_nph_av,
|
||||
# pcie_tfc_npd_av=dut.pcie_tfc_npd_av,
|
||||
|
||||
# Configuration Management Interface
|
||||
cfg_mgmt_addr=dut.cfg_mgmt_addr,
|
||||
cfg_mgmt_function_number=dut.cfg_mgmt_function_number,
|
||||
cfg_mgmt_write=dut.cfg_mgmt_write,
|
||||
cfg_mgmt_write_data=dut.cfg_mgmt_write_data,
|
||||
cfg_mgmt_byte_enable=dut.cfg_mgmt_byte_enable,
|
||||
cfg_mgmt_read=dut.cfg_mgmt_read,
|
||||
cfg_mgmt_read_data=dut.cfg_mgmt_read_data,
|
||||
cfg_mgmt_read_write_done=dut.cfg_mgmt_read_write_done,
|
||||
# cfg_mgmt_debug_access
|
||||
|
||||
# Configuration Status Interface
|
||||
# cfg_phy_link_down
|
||||
# cfg_phy_link_status
|
||||
# cfg_negotiated_width
|
||||
# cfg_current_speed
|
||||
# cfg_max_payload=dut.cfg_max_payload,
|
||||
# cfg_max_read_req=dut.cfg_max_read_req,
|
||||
# cfg_function_status
|
||||
# cfg_vf_status
|
||||
# cfg_function_power_state
|
||||
# cfg_vf_power_state
|
||||
# cfg_link_power_state
|
||||
# cfg_err_cor_out
|
||||
# cfg_err_nonfatal_out
|
||||
# cfg_err_fatal_out
|
||||
# cfg_local_error_out
|
||||
# cfg_local_error_valid
|
||||
# cfg_rx_pm_state
|
||||
# cfg_tx_pm_state
|
||||
# cfg_ltssm_state
|
||||
# cfg_rcb_status=dut.cfg_rcb_status,
|
||||
# cfg_obff_enable
|
||||
# cfg_pl_status_change
|
||||
# cfg_tph_requester_enable
|
||||
# cfg_tph_st_mode
|
||||
# cfg_vf_tph_requester_enable
|
||||
# cfg_vf_tph_st_mode
|
||||
|
||||
# Configuration Received Message Interface
|
||||
# cfg_msg_received
|
||||
# cfg_msg_received_data
|
||||
# cfg_msg_received_type
|
||||
|
||||
# Configuration Transmit Message Interface
|
||||
# cfg_msg_transmit
|
||||
# cfg_msg_transmit_type
|
||||
# cfg_msg_transmit_data
|
||||
# cfg_msg_transmit_done
|
||||
|
||||
# Configuration Flow Control Interface
|
||||
cfg_fc_ph=dut.cfg_fc_ph,
|
||||
cfg_fc_pd=dut.cfg_fc_pd,
|
||||
cfg_fc_nph=dut.cfg_fc_nph,
|
||||
cfg_fc_npd=dut.cfg_fc_npd,
|
||||
cfg_fc_cplh=dut.cfg_fc_cplh,
|
||||
cfg_fc_cpld=dut.cfg_fc_cpld,
|
||||
cfg_fc_sel=dut.cfg_fc_sel,
|
||||
|
||||
# Configuration Control Interface
|
||||
# cfg_hot_reset_in
|
||||
# cfg_hot_reset_out
|
||||
# cfg_config_space_enable
|
||||
# cfg_dsn
|
||||
# cfg_bus_number
|
||||
# cfg_ds_port_number
|
||||
# cfg_ds_bus_number
|
||||
# cfg_ds_device_number
|
||||
# cfg_ds_function_number
|
||||
# cfg_power_state_change_ack
|
||||
# cfg_power_state_change_interrupt
|
||||
# cfg_err_cor_in=dut.status_error_cor,
|
||||
# cfg_err_uncor_in=dut.status_error_uncor,
|
||||
# cfg_flr_in_process
|
||||
# cfg_flr_done
|
||||
# cfg_vf_flr_in_process
|
||||
# cfg_vf_flr_func_num
|
||||
# cfg_vf_flr_done
|
||||
# cfg_pm_aspm_l1_entry_reject
|
||||
# cfg_pm_aspm_tx_l0s_entry_disable
|
||||
# cfg_req_pm_transition_l23_ready
|
||||
# cfg_link_training_enable
|
||||
|
||||
# Configuration Interrupt Controller Interface
|
||||
# cfg_interrupt_int
|
||||
# cfg_interrupt_sent
|
||||
# cfg_interrupt_pending
|
||||
cfg_interrupt_msi_enable=dut.cfg_interrupt_msi_enable,
|
||||
cfg_interrupt_msi_mmenable=dut.cfg_interrupt_msi_mmenable,
|
||||
cfg_interrupt_msi_mask_update=dut.cfg_interrupt_msi_mask_update,
|
||||
cfg_interrupt_msi_data=dut.cfg_interrupt_msi_data,
|
||||
cfg_interrupt_msi_select=dut.cfg_interrupt_msi_select,
|
||||
cfg_interrupt_msi_int=dut.cfg_interrupt_msi_int,
|
||||
cfg_interrupt_msi_pending_status=dut.cfg_interrupt_msi_pending_status,
|
||||
cfg_interrupt_msi_pending_status_data_enable=dut.cfg_interrupt_msi_pending_status_data_enable,
|
||||
cfg_interrupt_msi_pending_status_function_num=dut.cfg_interrupt_msi_pending_status_function_num,
|
||||
cfg_interrupt_msi_sent=dut.cfg_interrupt_msi_sent,
|
||||
cfg_interrupt_msi_fail=dut.cfg_interrupt_msi_fail,
|
||||
# cfg_interrupt_msix_enable=dut.cfg_interrupt_msix_enable,
|
||||
# cfg_interrupt_msix_mask=dut.cfg_interrupt_msix_mask,
|
||||
# cfg_interrupt_msix_vf_enable=dut.cfg_interrupt_msix_vf_enable,
|
||||
# cfg_interrupt_msix_vf_mask=dut.cfg_interrupt_msix_vf_mask,
|
||||
# cfg_interrupt_msix_address=dut.cfg_interrupt_msix_address,
|
||||
# cfg_interrupt_msix_data=dut.cfg_interrupt_msix_data,
|
||||
# cfg_interrupt_msix_int=dut.cfg_interrupt_msix_int,
|
||||
# cfg_interrupt_msix_vec_pending=dut.cfg_interrupt_msix_vec_pending,
|
||||
# cfg_interrupt_msix_vec_pending_status=dut.cfg_interrupt_msix_vec_pending_status,
|
||||
# cfg_interrupt_msix_sent=dut.cfg_interrupt_msix_sent,
|
||||
# cfg_interrupt_msix_fail=dut.cfg_interrupt_msix_fail,
|
||||
cfg_interrupt_msi_attr=dut.cfg_interrupt_msi_attr,
|
||||
cfg_interrupt_msi_tph_present=dut.cfg_interrupt_msi_tph_present,
|
||||
cfg_interrupt_msi_tph_type=dut.cfg_interrupt_msi_tph_type,
|
||||
cfg_interrupt_msi_tph_st_tag=dut.cfg_interrupt_msi_tph_st_tag,
|
||||
cfg_interrupt_msi_function_number=dut.cfg_interrupt_msi_function_number,
|
||||
|
||||
# Configuration Extend Interface
|
||||
# cfg_ext_read_received
|
||||
# cfg_ext_write_received
|
||||
# cfg_ext_register_number
|
||||
# cfg_ext_function_number
|
||||
# cfg_ext_write_data
|
||||
# cfg_ext_write_byte_enable
|
||||
# cfg_ext_read_data
|
||||
# cfg_ext_read_data_valid
|
||||
)
|
||||
|
||||
# self.dev.log.setLevel(logging.DEBUG)
|
||||
|
||||
self.rc.make_port().connect(self.dev)
|
||||
|
||||
self.dev.functions[0].configure_bar(0, 2**int(dut.uut.axil_ctrl_bar.ADDR_W))
|
||||
|
||||
# PTP
|
||||
cocotb.start_soon(Clock(dut.ptp_clk, 3.102, units="ns").start())
|
||||
cocotb.start_soon(Clock(dut.ptp_sample_clk, 8, units="ns").start())
|
||||
|
||||
# Ethernet
|
||||
self.port_mac = []
|
||||
|
||||
if len(dut.mac_axis_tx[0].tdata) == 512:
|
||||
# assuming US+ 100G CMAC, 512 bits at 322.265625 MHz
|
||||
eth_clock_period = 3.102
|
||||
eth_speed = 100e9
|
||||
elif len(dut.mac_axis_tx[0].tdata) == 64:
|
||||
# assuming 25G MAC in low-latency mode, 64 bits at 402.83203125 MHz
|
||||
eth_clock_period = 2.482
|
||||
eth_speed = 25e9
|
||||
else:
|
||||
# assuming 25G MAC in low-latency mode, 512 bits at 322.265625 MHz
|
||||
eth_clock_period = 3.102
|
||||
eth_speed = 10e9
|
||||
|
||||
for k in range(len(dut.mac_axis_tx)):
|
||||
cocotb.start_soon(Clock(dut.mac_tx_clk[k], eth_clock_period, units="ns").start())
|
||||
cocotb.start_soon(Clock(dut.mac_rx_clk[k], eth_clock_period, units="ns").start())
|
||||
|
||||
dut.mac_tx_rst[k].setimmediatevalue(0)
|
||||
dut.mac_rx_rst[k].setimmediatevalue(0)
|
||||
|
||||
mac = EthMac(
|
||||
tx_clk=dut.mac_tx_clk[k],
|
||||
tx_rst=dut.mac_tx_rst[k],
|
||||
tx_bus=AxiStreamBus.from_entity(dut.mac_axis_tx[k]),
|
||||
rx_clk=dut.mac_rx_clk[k],
|
||||
rx_rst=dut.mac_rx_rst[k],
|
||||
rx_bus=AxiStreamBus.from_entity(dut.mac_axis_rx[k]),
|
||||
tx_ptp_time=dut.mac_axis_tx[k].tid, # TODO
|
||||
tx_ptp_ts=dut.mac_axis_tx_cpl[k].tdata, # TODO
|
||||
tx_ptp_ts_valid=dut.mac_axis_tx_cpl[k].tvalid, # TODO
|
||||
ifg=12, speed=eth_speed
|
||||
)
|
||||
self.port_mac.append(mac)
|
||||
|
||||
self.loopback_enable = False
|
||||
cocotb.start_soon(self._run_loopback())
|
||||
|
||||
async def init(self):
|
||||
|
||||
self.dut.ptp_rst.setimmediatevalue(0)
|
||||
|
||||
for mac in self.port_mac:
|
||||
mac.rx.reset.setimmediatevalue(0)
|
||||
mac.tx.reset.setimmediatevalue(0)
|
||||
|
||||
await FallingEdge(self.dut.pcie_rst)
|
||||
await Timer(100, 'ns')
|
||||
|
||||
for k in range(10):
|
||||
await RisingEdge(self.dut.pcie_clk)
|
||||
|
||||
self.dut.ptp_rst.value = 1
|
||||
|
||||
for mac in self.port_mac:
|
||||
mac.rx.reset.value = 1
|
||||
mac.tx.reset.value = 1
|
||||
|
||||
for k in range(10):
|
||||
await RisingEdge(self.dut.pcie_clk)
|
||||
|
||||
self.dut.ptp_rst.value = 0
|
||||
|
||||
for mac in self.port_mac:
|
||||
mac.rx.reset.value = 0
|
||||
mac.tx.reset.value = 0
|
||||
|
||||
for k in range(10):
|
||||
await RisingEdge(self.dut.pcie_clk)
|
||||
|
||||
await self.rc.enumerate()
|
||||
|
||||
async def _run_loopback(self):
|
||||
while True:
|
||||
await RisingEdge(self.dut.pcie_clk)
|
||||
|
||||
if self.loopback_enable:
|
||||
for mac in self.port_mac:
|
||||
while not mac.tx.empty():
|
||||
await mac.rx.send(await mac.tx.recv())
|
||||
|
||||
@cocotb.test()
|
||||
async def run_test(dut):
|
||||
|
||||
tb = TB(dut)
|
||||
|
||||
await tb.init()
|
||||
|
||||
tb.log.info("Init driver model")
|
||||
driver = cndm.Driver()
|
||||
await driver.init_pcie_dev(tb.rc.find_device(tb.dev.functions[0].pcie_id))
|
||||
|
||||
tb.log.info("Init complete")
|
||||
|
||||
tb.log.info("Send and receive single packet on each port")
|
||||
|
||||
for k in range(len(driver.ports)):
|
||||
data = f"Corundum rocks on port {k}!".encode('ascii')
|
||||
|
||||
await driver.ports[k].start_xmit(data)
|
||||
|
||||
pkt = await tb.port_mac[k].tx.recv()
|
||||
tb.log.info("Got TX packet: %s", pkt)
|
||||
|
||||
assert bytes(pkt) == data
|
||||
|
||||
await tb.port_mac[k].rx.send(pkt)
|
||||
|
||||
pkt = await driver.ports[k].recv()
|
||||
tb.log.info("Got RX packet: %s", pkt)
|
||||
|
||||
assert bytes(pkt) == data
|
||||
|
||||
tb.log.info("Multiple small packets")
|
||||
|
||||
count = 64
|
||||
pkts = [bytearray([(x+k) % 256 for x in range(60)]) for k in range(count)]
|
||||
|
||||
tb.loopback_enable = True
|
||||
|
||||
for p in pkts:
|
||||
await driver.ports[0].start_xmit(p)
|
||||
|
||||
for k in range(count):
|
||||
pkt = await driver.ports[0].recv()
|
||||
|
||||
tb.log.info("Got RX packet: %s", pkt)
|
||||
|
||||
assert bytes(pkt) == pkts[k]
|
||||
|
||||
tb.loopback_enable = False
|
||||
|
||||
tb.log.info("Multiple large packets")
|
||||
|
||||
count = 64
|
||||
pkts = [bytearray([(x+k) % 256 for x in range(1514)]) for k in range(count)]
|
||||
|
||||
tb.loopback_enable = True
|
||||
|
||||
for p in pkts:
|
||||
await driver.ports[0].start_xmit(p)
|
||||
|
||||
for k in range(count):
|
||||
pkt = await driver.ports[0].recv()
|
||||
|
||||
tb.log.info("Got RX packet: %s", pkt)
|
||||
|
||||
assert bytes(pkt) == pkts[k]
|
||||
|
||||
tb.loopback_enable = False
|
||||
|
||||
await RisingEdge(dut.pcie_clk)
|
||||
await RisingEdge(dut.pcie_clk)
|
||||
|
||||
|
||||
# cocotb-test
|
||||
|
||||
tests_dir = os.path.abspath(os.path.dirname(__file__))
|
||||
rtl_dir = os.path.abspath(os.path.join(tests_dir, '..', '..', 'rtl'))
|
||||
lib_dir = os.path.abspath(os.path.join(tests_dir, '..', '..', 'lib'))
|
||||
taxi_src_dir = os.path.abspath(os.path.join(lib_dir, 'taxi', 'src'))
|
||||
|
||||
|
||||
def process_f_files(files):
|
||||
lst = {}
|
||||
for f in files:
|
||||
if f[-2:].lower() == '.f':
|
||||
with open(f, 'r') as fp:
|
||||
l = fp.read().split()
|
||||
for f in process_f_files([os.path.join(os.path.dirname(f), x) for x in l]):
|
||||
lst[os.path.basename(f)] = f
|
||||
else:
|
||||
lst[os.path.basename(f)] = f
|
||||
return list(lst.values())
|
||||
|
||||
|
||||
@pytest.mark.parametrize(("pcie_data_w", "mac_data_w"), [
|
||||
(128, 32),
|
||||
(128, 64),
|
||||
(256, 32),
|
||||
(256, 64),
|
||||
(512, 32),
|
||||
(512, 64),
|
||||
(512, 512),
|
||||
])
|
||||
def test_cndm_lite_pcie_us(request, pcie_data_w, mac_data_w):
|
||||
dut = "cndm_lite_pcie_us"
|
||||
module = os.path.splitext(os.path.basename(__file__))[0]
|
||||
toplevel = module
|
||||
|
||||
verilog_sources = [
|
||||
os.path.join(tests_dir, f"{toplevel}.sv"),
|
||||
os.path.join(rtl_dir, f"{dut}.f"),
|
||||
]
|
||||
|
||||
verilog_sources = process_f_files(verilog_sources)
|
||||
|
||||
parameters = {}
|
||||
|
||||
parameters['SIM'] = "1'b1"
|
||||
parameters['VENDOR'] = "\"XILINX\""
|
||||
parameters['FAMILY'] = "\"virtexuplus\""
|
||||
|
||||
# Structural configuration
|
||||
parameters['PORTS'] = 2
|
||||
|
||||
# PTP configuration
|
||||
parameters['PTP_TS_EN'] = 1
|
||||
parameters['PTP_TS_FMT_TOD'] = 0
|
||||
parameters['PTP_CLK_PER_NS_NUM'] = 512
|
||||
parameters['PTP_CLK_PER_NS_DENOM'] = 165
|
||||
|
||||
# PCIe interface configuration
|
||||
parameters['AXIS_PCIE_DATA_W'] = pcie_data_w
|
||||
|
||||
# AXI lite interface configuration (control)
|
||||
parameters['AXIL_CTRL_DATA_W'] = 32
|
||||
parameters['AXIL_CTRL_ADDR_W'] = 24
|
||||
|
||||
# MAC configuration
|
||||
parameters['MAC_DATA_W'] = mac_data_w
|
||||
|
||||
extra_env = {f'PARAM_{k}': str(v) for k, v in parameters.items()}
|
||||
|
||||
sim_build = os.path.join(tests_dir, "sim_build",
|
||||
request.node.name.replace('[', '-').replace(']', ''))
|
||||
|
||||
cocotb_test.simulator.run(
|
||||
simulator="verilator",
|
||||
python_search=[tests_dir],
|
||||
verilog_sources=verilog_sources,
|
||||
toplevel=toplevel,
|
||||
module=module,
|
||||
parameters=parameters,
|
||||
sim_build=sim_build,
|
||||
extra_env=extra_env,
|
||||
)
|
||||
309
src/cndm/tb/cndm_lite_pcie_us/test_cndm_lite_pcie_us.sv
Normal file
309
src/cndm/tb/cndm_lite_pcie_us/test_cndm_lite_pcie_us.sv
Normal file
@@ -0,0 +1,309 @@
|
||||
// SPDX-License-Identifier: CERN-OHL-S-2.0
|
||||
/*
|
||||
|
||||
Copyright (c) 2025-2026 FPGA Ninja, LLC
|
||||
|
||||
Authors:
|
||||
- Alex Forencich
|
||||
|
||||
*/
|
||||
|
||||
`resetall
|
||||
`timescale 1ns / 1ps
|
||||
`default_nettype none
|
||||
|
||||
/*
|
||||
* FPGA core logic testbench
|
||||
*/
|
||||
module test_cndm_lite_pcie_us #
|
||||
(
|
||||
/* verilator lint_off WIDTHTRUNC */
|
||||
parameter logic SIM = 1'b0,
|
||||
parameter string VENDOR = "XILINX",
|
||||
parameter string FAMILY = "virtexuplus",
|
||||
|
||||
// FW ID
|
||||
parameter FPGA_ID = 32'hDEADBEEF,
|
||||
parameter FW_ID = 32'h0000C002,
|
||||
parameter FW_VER = 32'h000_01_000,
|
||||
parameter BOARD_ID = 32'h1234_0000,
|
||||
parameter BOARD_VER = 32'h001_00_000,
|
||||
parameter BUILD_DATE = 32'd602976000,
|
||||
parameter GIT_HASH = 32'h5f87c2e8,
|
||||
parameter RELEASE_INFO = 32'h00000000,
|
||||
|
||||
// Structural configuration
|
||||
parameter PORTS = 2,
|
||||
|
||||
// PTP configuration
|
||||
parameter logic PTP_TS_EN = 1'b1,
|
||||
parameter logic PTP_TS_FMT_TOD = 1'b0,
|
||||
parameter PTP_CLK_PER_NS_NUM = 512,
|
||||
parameter PTP_CLK_PER_NS_DENOM = 165,
|
||||
|
||||
// PCIe interface configuration
|
||||
parameter AXIS_PCIE_DATA_W = 512,
|
||||
parameter AXIS_PCIE_RC_USER_W = AXIS_PCIE_DATA_W < 512 ? 75 : 161,
|
||||
parameter AXIS_PCIE_RQ_USER_W = AXIS_PCIE_DATA_W < 512 ? 62 : 137,
|
||||
parameter AXIS_PCIE_CQ_USER_W = AXIS_PCIE_DATA_W < 512 ? 85 : 183,
|
||||
parameter AXIS_PCIE_CC_USER_W = AXIS_PCIE_DATA_W < 512 ? 33 : 81,
|
||||
|
||||
// AXI lite interface configuration (control)
|
||||
parameter AXIL_CTRL_DATA_W = 32,
|
||||
parameter AXIL_CTRL_ADDR_W = 24,
|
||||
|
||||
// MAC configuration
|
||||
parameter MAC_DATA_W = 512
|
||||
/* verilator lint_on WIDTHTRUNC */
|
||||
)
|
||||
();
|
||||
|
||||
localparam PTP_TS_W = PTP_TS_FMT_TOD ? 96 : 48;
|
||||
|
||||
localparam AXIS_PCIE_KEEP_W = (AXIS_PCIE_DATA_W/32);
|
||||
localparam RQ_SEQ_NUM_W = AXIS_PCIE_RQ_USER_W == 60 ? 4 : 6;
|
||||
|
||||
logic sfp_mgt_refclk_p;
|
||||
logic sfp_mgt_refclk_n;
|
||||
logic sfp_mgt_refclk_out;
|
||||
|
||||
logic [1:0] sfp_npres;
|
||||
logic [1:0] sfp_tx_fault;
|
||||
logic [1:0] sfp_los;
|
||||
|
||||
logic pcie_clk;
|
||||
logic pcie_rst;
|
||||
|
||||
taxi_axis_if #(
|
||||
.DATA_W(AXIS_PCIE_DATA_W),
|
||||
.KEEP_EN(1),
|
||||
.KEEP_W(AXIS_PCIE_KEEP_W),
|
||||
.USER_EN(1),
|
||||
.USER_W(AXIS_PCIE_CQ_USER_W)
|
||||
) s_axis_pcie_cq();
|
||||
|
||||
taxi_axis_if #(
|
||||
.DATA_W(AXIS_PCIE_DATA_W),
|
||||
.KEEP_EN(1),
|
||||
.KEEP_W(AXIS_PCIE_KEEP_W),
|
||||
.USER_EN(1),
|
||||
.USER_W(AXIS_PCIE_CC_USER_W)
|
||||
) m_axis_pcie_cc();
|
||||
|
||||
taxi_axis_if #(
|
||||
.DATA_W(AXIS_PCIE_DATA_W),
|
||||
.KEEP_EN(1),
|
||||
.KEEP_W(AXIS_PCIE_KEEP_W),
|
||||
.USER_EN(1),
|
||||
.USER_W(AXIS_PCIE_RQ_USER_W)
|
||||
) m_axis_pcie_rq();
|
||||
|
||||
taxi_axis_if #(
|
||||
.DATA_W(AXIS_PCIE_DATA_W),
|
||||
.KEEP_EN(1),
|
||||
.KEEP_W(AXIS_PCIE_KEEP_W),
|
||||
.USER_EN(1),
|
||||
.USER_W(AXIS_PCIE_RC_USER_W)
|
||||
) s_axis_pcie_rc();
|
||||
|
||||
logic [RQ_SEQ_NUM_W-1:0] pcie_rq_seq_num0;
|
||||
logic pcie_rq_seq_num_vld0;
|
||||
logic [RQ_SEQ_NUM_W-1:0] pcie_rq_seq_num1;
|
||||
logic pcie_rq_seq_num_vld1;
|
||||
|
||||
logic [2:0] cfg_max_payload;
|
||||
logic [2:0] cfg_max_read_req;
|
||||
logic [3:0] cfg_rcb_status;
|
||||
|
||||
logic [9:0] cfg_mgmt_addr;
|
||||
logic [7:0] cfg_mgmt_function_number;
|
||||
logic cfg_mgmt_write;
|
||||
logic [31:0] cfg_mgmt_write_data;
|
||||
logic [3:0] cfg_mgmt_byte_enable;
|
||||
logic cfg_mgmt_read;
|
||||
logic [31:0] cfg_mgmt_read_data;
|
||||
logic cfg_mgmt_read_write_done;
|
||||
|
||||
logic [7:0] cfg_fc_ph;
|
||||
logic [11:0] cfg_fc_pd;
|
||||
logic [7:0] cfg_fc_nph;
|
||||
logic [11:0] cfg_fc_npd;
|
||||
logic [7:0] cfg_fc_cplh;
|
||||
logic [11:0] cfg_fc_cpld;
|
||||
logic [2:0] cfg_fc_sel;
|
||||
|
||||
logic [3:0] cfg_interrupt_msi_enable;
|
||||
logic [11:0] cfg_interrupt_msi_mmenable;
|
||||
logic cfg_interrupt_msi_mask_update;
|
||||
logic [31:0] cfg_interrupt_msi_data;
|
||||
logic [1:0] cfg_interrupt_msi_select;
|
||||
logic [31:0] cfg_interrupt_msi_int;
|
||||
logic [31:0] cfg_interrupt_msi_pending_status;
|
||||
logic cfg_interrupt_msi_pending_status_data_enable;
|
||||
logic [1:0] cfg_interrupt_msi_pending_status_function_num;
|
||||
logic cfg_interrupt_msi_sent;
|
||||
logic cfg_interrupt_msi_fail;
|
||||
logic [2:0] cfg_interrupt_msi_attr;
|
||||
logic cfg_interrupt_msi_tph_present;
|
||||
logic [1:0] cfg_interrupt_msi_tph_type;
|
||||
logic [7:0] cfg_interrupt_msi_tph_st_tag;
|
||||
logic [7:0] cfg_interrupt_msi_function_number;
|
||||
|
||||
logic ptp_rst;
|
||||
logic ptp_clk;
|
||||
logic ptp_sample_clk;
|
||||
logic ptp_td_sdo;
|
||||
logic ptp_pps;
|
||||
logic ptp_pps_str;
|
||||
logic ptp_sync_locked;
|
||||
logic [63:0] ptp_sync_ts_rel;
|
||||
logic ptp_sync_ts_rel_step;
|
||||
logic [95:0] ptp_sync_ts_tod;
|
||||
logic ptp_sync_ts_tod_step;
|
||||
logic ptp_sync_pps;
|
||||
logic ptp_sync_pps_str;
|
||||
|
||||
logic mac_tx_clk[PORTS];
|
||||
logic mac_tx_rst[PORTS];
|
||||
|
||||
taxi_axis_if #(
|
||||
.DATA_W(MAC_DATA_W),
|
||||
.ID_W(8),
|
||||
.USER_EN(1),
|
||||
.USER_W(1)
|
||||
) mac_axis_tx[PORTS]();
|
||||
|
||||
logic mac_rx_clk[PORTS];
|
||||
logic mac_rx_rst[PORTS];
|
||||
|
||||
taxi_axis_if #(
|
||||
.DATA_W(PTP_TS_W),
|
||||
.KEEP_W(1),
|
||||
.ID_W(8)
|
||||
) mac_axis_tx_cpl[PORTS]();
|
||||
|
||||
taxi_axis_if #(
|
||||
.DATA_W(MAC_DATA_W),
|
||||
.ID_W(8),
|
||||
.USER_EN(1),
|
||||
.USER_W(PTP_TS_W+1)
|
||||
) mac_axis_rx[PORTS]();
|
||||
|
||||
cndm_lite_pcie_us #(
|
||||
.SIM(SIM),
|
||||
.VENDOR(VENDOR),
|
||||
.FAMILY(FAMILY),
|
||||
|
||||
// FW ID
|
||||
.FPGA_ID(FPGA_ID),
|
||||
.FW_ID(FW_ID),
|
||||
.FW_VER(FW_VER),
|
||||
.BOARD_ID(BOARD_ID),
|
||||
.BOARD_VER(BOARD_VER),
|
||||
.BUILD_DATE(BUILD_DATE),
|
||||
.GIT_HASH(GIT_HASH),
|
||||
.RELEASE_INFO(RELEASE_INFO),
|
||||
|
||||
// Structural configuration
|
||||
.PORTS(PORTS),
|
||||
|
||||
// PTP configuration
|
||||
.PTP_TS_EN(PTP_TS_EN),
|
||||
.PTP_TS_FMT_TOD(PTP_TS_FMT_TOD),
|
||||
.PTP_CLK_PER_NS_NUM(PTP_CLK_PER_NS_NUM),
|
||||
.PTP_CLK_PER_NS_DENOM(PTP_CLK_PER_NS_DENOM),
|
||||
|
||||
// PCIe interface configuration
|
||||
.RQ_SEQ_NUM_W(RQ_SEQ_NUM_W),
|
||||
|
||||
// AXI lite interface configuration (control)
|
||||
.AXIL_CTRL_DATA_W(AXIL_CTRL_DATA_W),
|
||||
.AXIL_CTRL_ADDR_W(AXIL_CTRL_ADDR_W)
|
||||
)
|
||||
uut (
|
||||
/*
|
||||
* PCIe
|
||||
*/
|
||||
.pcie_clk(pcie_clk),
|
||||
.pcie_rst(pcie_rst),
|
||||
.s_axis_pcie_cq(s_axis_pcie_cq),
|
||||
.m_axis_pcie_cc(m_axis_pcie_cc),
|
||||
.m_axis_pcie_rq(m_axis_pcie_rq),
|
||||
.s_axis_pcie_rc(s_axis_pcie_rc),
|
||||
|
||||
.pcie_rq_seq_num0(pcie_rq_seq_num0),
|
||||
.pcie_rq_seq_num_vld0(pcie_rq_seq_num_vld0),
|
||||
.pcie_rq_seq_num1(pcie_rq_seq_num1),
|
||||
.pcie_rq_seq_num_vld1(pcie_rq_seq_num_vld1),
|
||||
|
||||
.cfg_max_payload(cfg_max_payload),
|
||||
.cfg_max_read_req(cfg_max_read_req),
|
||||
.cfg_rcb_status(cfg_rcb_status),
|
||||
|
||||
.cfg_mgmt_addr(cfg_mgmt_addr),
|
||||
.cfg_mgmt_function_number(cfg_mgmt_function_number),
|
||||
.cfg_mgmt_write(cfg_mgmt_write),
|
||||
.cfg_mgmt_write_data(cfg_mgmt_write_data),
|
||||
.cfg_mgmt_byte_enable(cfg_mgmt_byte_enable),
|
||||
.cfg_mgmt_read(cfg_mgmt_read),
|
||||
.cfg_mgmt_read_data(cfg_mgmt_read_data),
|
||||
.cfg_mgmt_read_write_done(cfg_mgmt_read_write_done),
|
||||
|
||||
.cfg_fc_ph(cfg_fc_ph),
|
||||
.cfg_fc_pd(cfg_fc_pd),
|
||||
.cfg_fc_nph(cfg_fc_nph),
|
||||
.cfg_fc_npd(cfg_fc_npd),
|
||||
.cfg_fc_cplh(cfg_fc_cplh),
|
||||
.cfg_fc_cpld(cfg_fc_cpld),
|
||||
.cfg_fc_sel(cfg_fc_sel),
|
||||
|
||||
.cfg_interrupt_msi_enable(cfg_interrupt_msi_enable),
|
||||
.cfg_interrupt_msi_mmenable(cfg_interrupt_msi_mmenable),
|
||||
.cfg_interrupt_msi_mask_update(cfg_interrupt_msi_mask_update),
|
||||
.cfg_interrupt_msi_data(cfg_interrupt_msi_data),
|
||||
.cfg_interrupt_msi_select(cfg_interrupt_msi_select),
|
||||
.cfg_interrupt_msi_int(cfg_interrupt_msi_int),
|
||||
.cfg_interrupt_msi_pending_status(cfg_interrupt_msi_pending_status),
|
||||
.cfg_interrupt_msi_pending_status_data_enable(cfg_interrupt_msi_pending_status_data_enable),
|
||||
.cfg_interrupt_msi_pending_status_function_num(cfg_interrupt_msi_pending_status_function_num),
|
||||
.cfg_interrupt_msi_sent(cfg_interrupt_msi_sent),
|
||||
.cfg_interrupt_msi_fail(cfg_interrupt_msi_fail),
|
||||
.cfg_interrupt_msi_attr(cfg_interrupt_msi_attr),
|
||||
.cfg_interrupt_msi_tph_present(cfg_interrupt_msi_tph_present),
|
||||
.cfg_interrupt_msi_tph_type(cfg_interrupt_msi_tph_type),
|
||||
.cfg_interrupt_msi_tph_st_tag(cfg_interrupt_msi_tph_st_tag),
|
||||
.cfg_interrupt_msi_function_number(cfg_interrupt_msi_function_number),
|
||||
|
||||
/*
|
||||
* PTP
|
||||
*/
|
||||
.ptp_clk(ptp_clk),
|
||||
.ptp_rst(ptp_rst),
|
||||
.ptp_sample_clk(ptp_sample_clk),
|
||||
.ptp_td_sdo(ptp_td_sdo),
|
||||
.ptp_pps(ptp_pps),
|
||||
.ptp_pps_str(ptp_pps_str),
|
||||
.ptp_sync_locked(ptp_sync_locked),
|
||||
.ptp_sync_ts_rel(ptp_sync_ts_rel),
|
||||
.ptp_sync_ts_rel_step(ptp_sync_ts_rel_step),
|
||||
.ptp_sync_ts_tod(ptp_sync_ts_tod),
|
||||
.ptp_sync_ts_tod_step(ptp_sync_ts_tod_step),
|
||||
.ptp_sync_pps(ptp_sync_pps),
|
||||
.ptp_sync_pps_str(ptp_sync_pps_str),
|
||||
|
||||
/*
|
||||
* Ethernet: SFP+
|
||||
*/
|
||||
.mac_tx_clk(mac_tx_clk),
|
||||
.mac_tx_rst(mac_tx_rst),
|
||||
.mac_axis_tx(mac_axis_tx),
|
||||
.mac_axis_tx_cpl(mac_axis_tx_cpl),
|
||||
|
||||
.mac_rx_clk(mac_rx_clk),
|
||||
.mac_rx_rst(mac_rx_rst),
|
||||
.mac_axis_rx(mac_axis_rx)
|
||||
);
|
||||
|
||||
endmodule
|
||||
|
||||
`resetall
|
||||
Reference in New Issue
Block a user