mirror of
https://github.com/corundum/corundum.git
synced 2025-01-16 08:12:53 +08:00
Migrate test infrastructure to cocotb
This commit is contained in:
parent
3003b3228d
commit
b5ee772761
39
fpga/common/tb/Makefile
Normal file
39
fpga/common/tb/Makefile
Normal file
@ -0,0 +1,39 @@
|
||||
# Copyright 2020, The Regents of the University of California.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
#
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
|
||||
# IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
|
||||
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
# OF SUCH DAMAGE.
|
||||
#
|
||||
# The views and conclusions contained in the software and documentation are those
|
||||
# of the authors and should not be interpreted as representing official policies,
|
||||
# either expressed or implied, of The Regents of the University of California.
|
||||
|
||||
TOPTARGETS := all clean
|
||||
|
||||
SUBDIRS := $(wildcard */.)
|
||||
|
||||
$(TOPTARGETS): $(SUBDIRS)
|
||||
$(SUBDIRS):
|
||||
$(MAKE) -C $@ $(MAKECMDGOALS)
|
||||
|
||||
.PHONY: $(TOPTARGETS) $(SUBDIRS)
|
||||
|
@ -1 +0,0 @@
|
||||
../lib/axi/tb/axi.py
|
@ -1 +0,0 @@
|
||||
../lib/axi/tb/axil.py
|
@ -1 +0,0 @@
|
||||
../lib/axis/tb/axis_ep.py
|
117
fpga/common/tb/cpl_queue_manager/Makefile
Normal file
117
fpga/common/tb/cpl_queue_manager/Makefile
Normal file
@ -0,0 +1,117 @@
|
||||
# Copyright 2020, The Regents of the University of California.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
#
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
|
||||
# IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
|
||||
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
# OF SUCH DAMAGE.
|
||||
#
|
||||
# The views and conclusions contained in the software and documentation are those
|
||||
# of the authors and should not be interpreted as representing official policies,
|
||||
# either expressed or implied, of The Regents of the University of California.
|
||||
|
||||
TOPLEVEL_LANG = verilog
|
||||
|
||||
SIM ?= icarus
|
||||
WAVES ?= 0
|
||||
|
||||
COCOTB_HDL_TIMEUNIT = 1ns
|
||||
COCOTB_HDL_TIMEPRECISION = 1ps
|
||||
|
||||
DUT = cpl_queue_manager
|
||||
TOPLEVEL = $(DUT)
|
||||
MODULE = test_$(DUT)
|
||||
VERILOG_SOURCES += ../../rtl/$(DUT).v
|
||||
|
||||
# module parameters
|
||||
export PARAM_ADDR_WIDTH = 64
|
||||
export PARAM_REQ_TAG_WIDTH = 8
|
||||
export PARAM_OP_TABLE_SIZE = 16
|
||||
export PARAM_OP_TAG_WIDTH = 8
|
||||
export PARAM_QUEUE_INDEX_WIDTH = 8
|
||||
export PARAM_EVENT_WIDTH = 8
|
||||
export PARAM_QUEUE_PTR_WIDTH = 16
|
||||
export PARAM_LOG_QUEUE_SIZE_WIDTH = 4
|
||||
export PARAM_CPL_SIZE = 16
|
||||
export PARAM_PIPELINE = 2
|
||||
export PARAM_AXIL_DATA_WIDTH = 32
|
||||
export PARAM_AXIL_ADDR_WIDTH = 16
|
||||
export PARAM_AXIL_STRB_WIDTH = $(shell expr $(PARAM_AXIL_DATA_WIDTH) / 8 )
|
||||
|
||||
SIM_BUILD ?= sim_build_$(MODULE)
|
||||
|
||||
ifeq ($(SIM), icarus)
|
||||
PLUSARGS += -fst
|
||||
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).ADDR_WIDTH=$(PARAM_ADDR_WIDTH)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).REQ_TAG_WIDTH=$(PARAM_REQ_TAG_WIDTH)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).OP_TABLE_SIZE=$(PARAM_OP_TABLE_SIZE)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).OP_TAG_WIDTH=$(PARAM_OP_TAG_WIDTH)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).QUEUE_INDEX_WIDTH=$(PARAM_QUEUE_INDEX_WIDTH)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).EVENT_WIDTH=$(PARAM_EVENT_WIDTH)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).QUEUE_PTR_WIDTH=$(PARAM_QUEUE_PTR_WIDTH)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).LOG_QUEUE_SIZE_WIDTH=$(PARAM_LOG_QUEUE_SIZE_WIDTH)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).CPL_SIZE=$(PARAM_CPL_SIZE)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).PIPELINE=$(PARAM_PIPELINE)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).AXIL_DATA_WIDTH=$(PARAM_AXIL_DATA_WIDTH)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).AXIL_ADDR_WIDTH=$(PARAM_AXIL_ADDR_WIDTH)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).AXIL_STRB_WIDTH=$(PARAM_AXIL_STRB_WIDTH)
|
||||
|
||||
ifeq ($(WAVES), 1)
|
||||
VERILOG_SOURCES += iverilog_dump.v
|
||||
COMPILE_ARGS += -s iverilog_dump
|
||||
endif
|
||||
else ifeq ($(SIM), verilator)
|
||||
COMPILE_ARGS += -Wno-SELRANGE -Wno-WIDTH
|
||||
|
||||
COMPILE_ARGS += -GADDR_WIDTH=$(PARAM_ADDR_WIDTH)
|
||||
COMPILE_ARGS += -GREQ_TAG_WIDTH=$(PARAM_REQ_TAG_WIDTH)
|
||||
COMPILE_ARGS += -GOP_TABLE_SIZE=$(PARAM_OP_TABLE_SIZE)
|
||||
COMPILE_ARGS += -GOP_TAG_WIDTH=$(PARAM_OP_TAG_WIDTH)
|
||||
COMPILE_ARGS += -GQUEUE_INDEX_WIDTH=$(PARAM_QUEUE_INDEX_WIDTH)
|
||||
COMPILE_ARGS += -GEVENT_WIDTH=$(PARAM_EVENT_WIDTH)
|
||||
COMPILE_ARGS += -GQUEUE_PTR_WIDTH=$(PARAM_QUEUE_PTR_WIDTH)
|
||||
COMPILE_ARGS += -GLOG_QUEUE_SIZE_WIDTH=$(PARAM_LOG_QUEUE_SIZE_WIDTH)
|
||||
COMPILE_ARGS += -GCPL_SIZE=$(PARAM_CPL_SIZE)
|
||||
COMPILE_ARGS += -GPIPELINE=$(PARAM_PIPELINE)
|
||||
COMPILE_ARGS += -GAXIL_DATA_WIDTH=$(PARAM_AXIL_DATA_WIDTH)
|
||||
COMPILE_ARGS += -GAXIL_ADDR_WIDTH=$(PARAM_AXIL_ADDR_WIDTH)
|
||||
COMPILE_ARGS += -GAXIL_STRB_WIDTH=$(PARAM_AXIL_STRB_WIDTH)
|
||||
|
||||
ifeq ($(WAVES), 1)
|
||||
COMPILE_ARGS += --trace-fst
|
||||
endif
|
||||
endif
|
||||
|
||||
iverilog_dump.v:
|
||||
echo 'module iverilog_dump();' > $@
|
||||
echo 'initial begin' >> $@
|
||||
echo ' $$dumpfile("$(TOPLEVEL).fst");' >> $@
|
||||
echo ' $$dumpvars(0, $(TOPLEVEL));' >> $@
|
||||
echo 'end' >> $@
|
||||
echo 'endmodule' >> $@
|
||||
|
||||
clean::
|
||||
@rm -rf sim_build_*
|
||||
@rm -rf iverilog_dump.v
|
||||
@rm -rf dump.fst $(TOPLEVEL).fst
|
||||
|
||||
include $(shell cocotb-config --makefiles)/Makefile.sim
|
||||
|
337
fpga/common/tb/cpl_queue_manager/test_cpl_queue_manager.py
Normal file
337
fpga/common/tb/cpl_queue_manager/test_cpl_queue_manager.py
Normal file
@ -0,0 +1,337 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
|
||||
Copyright 2020, The Regents of the University of California.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
|
||||
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of The Regents of the University of California.
|
||||
|
||||
"""
|
||||
|
||||
import logging
|
||||
import os
|
||||
import random
|
||||
|
||||
import cocotb_test.simulator
|
||||
|
||||
import cocotb
|
||||
from cocotb.clock import Clock
|
||||
from cocotb.triggers import RisingEdge, Timer
|
||||
from cocotb.regression import TestFactory
|
||||
|
||||
from cocotbext.axi import AxiLiteMaster
|
||||
from cocotbext.axi.stream import define_stream
|
||||
|
||||
|
||||
EnqueueReqTransaction, EnqueueReqSource, EnqueueReqSink, EnqueueReqMonitor = define_stream("EnqueueReq",
|
||||
signals=["queue", "tag", "valid"],
|
||||
optional_signals=["ready"]
|
||||
)
|
||||
|
||||
EnqueueRespTransaction, EnqueueRespSource, EnqueueRespSink, EnqueueRespMonitor = define_stream("EnqueueResp",
|
||||
signals=["queue", "ptr", "addr", "event", "tag", "op_tag", "full", "error", "valid"],
|
||||
optional_signals=["ready"]
|
||||
)
|
||||
|
||||
EnqueueCommitTransaction, EnqueueCommitSource, EnqueueCommitSink, EnqueueCommitMonitor = define_stream("EnqueueCommit",
|
||||
signals=["op_tag", "valid"],
|
||||
optional_signals=["ready"]
|
||||
)
|
||||
|
||||
EventTransaction, EventSource, EventSink, EventMonitor = define_stream("Event",
|
||||
signals=["event", "event_source", "event_valid"],
|
||||
optional_signals=["event_ready"]
|
||||
)
|
||||
|
||||
|
||||
class TB(object):
|
||||
def __init__(self, dut):
|
||||
self.dut = dut
|
||||
|
||||
self.log = logging.getLogger("cocotb.tb")
|
||||
self.log.setLevel(logging.DEBUG)
|
||||
|
||||
cocotb.fork(Clock(dut.clk, 4, units="ns").start())
|
||||
|
||||
self.axil_master = AxiLiteMaster(dut, "s_axil", dut.clk, dut.rst)
|
||||
|
||||
self.enqueue_req_source = EnqueueReqSource(dut, "s_axis_enqueue_req", dut.clk, dut.rst)
|
||||
self.enqueue_resp_sink = EnqueueRespSink(dut, "m_axis_enqueue_resp", dut.clk, dut.rst)
|
||||
self.enqueue_commit_source = EnqueueCommitSource(dut, "s_axis_enqueue_commit", dut.clk, dut.rst)
|
||||
self.event_sink = EventSink(dut, "m_axis", dut.clk, dut.rst)
|
||||
|
||||
dut.enable.setimmediatevalue(0)
|
||||
|
||||
def set_idle_generator(self, generator=None):
|
||||
if generator:
|
||||
self.source.set_pause_generator(generator())
|
||||
|
||||
def set_backpressure_generator(self, generator=None):
|
||||
if generator:
|
||||
self.sink.set_pause_generator(generator())
|
||||
|
||||
async def reset(self):
|
||||
self.dut.rst.setimmediatevalue(0)
|
||||
await RisingEdge(self.dut.clk)
|
||||
await RisingEdge(self.dut.clk)
|
||||
self.dut.rst <= 1
|
||||
await RisingEdge(self.dut.clk)
|
||||
await RisingEdge(self.dut.clk)
|
||||
self.dut.rst <= 0
|
||||
await RisingEdge(self.dut.clk)
|
||||
await RisingEdge(self.dut.clk)
|
||||
|
||||
|
||||
async def run_test(dut):
|
||||
|
||||
OP_TABLE_SIZE = int(os.getenv("PARAM_OP_TABLE_SIZE"))
|
||||
|
||||
tb = TB(dut)
|
||||
|
||||
await tb.reset()
|
||||
|
||||
dut.enable <= 1
|
||||
|
||||
tb.log.info("Test read and write queue configuration registers")
|
||||
|
||||
await tb.axil_master.write_qword(0*32+0, 0x8877665544332211) # address
|
||||
await tb.axil_master.write_dword(0*32+8, 0x00000004) # active, log size
|
||||
await tb.axil_master.write_dword(0*32+12, 0x80000001) # armed, continuous, event
|
||||
await tb.axil_master.write_dword(0*32+16, 0x00000000) # head pointer
|
||||
await tb.axil_master.write_dword(0*32+24, 0x00000000) # tail pointer
|
||||
await tb.axil_master.write_dword(0*32+8, 0x80000004) # active, log size
|
||||
|
||||
assert await tb.axil_master.read_qword(0*32+0) == 0x8877665544332211
|
||||
assert await tb.axil_master.read_dword(0*32+8) == 0x80000004
|
||||
assert await tb.axil_master.read_dword(0*32+12) == 0x80000001
|
||||
|
||||
tb.log.info("Test enqueue and dequeue")
|
||||
|
||||
# read head pointer
|
||||
head_ptr = await tb.axil_master.read_dword(0*32+16) # head pointer
|
||||
tb.log.info("Head pointer: %d", head_ptr)
|
||||
|
||||
# enqueue request
|
||||
tb.enqueue_req_source.send(EnqueueReqTransaction(queue=0, tag=1))
|
||||
|
||||
await tb.enqueue_resp_sink.wait()
|
||||
resp = tb.enqueue_resp_sink.recv()
|
||||
|
||||
tb.log.info("Enqueue response: %s", resp)
|
||||
|
||||
assert resp.queue == 0
|
||||
assert resp.ptr == head_ptr
|
||||
assert resp.addr == 0x8877665544332211
|
||||
assert resp.event == 1
|
||||
assert resp.tag == 1
|
||||
assert not resp.full
|
||||
assert not resp.error
|
||||
|
||||
# enqueue commit
|
||||
tb.enqueue_commit_source.send(EnqueueCommitTransaction(op_tag=resp.op_tag))
|
||||
|
||||
await Timer(100, 'ns')
|
||||
|
||||
# check for event
|
||||
await tb.event_sink.wait()
|
||||
event = tb.event_sink.recv()
|
||||
tb.log.info("Event: %s", event)
|
||||
|
||||
assert event.event == 1
|
||||
assert event.event_source == 0
|
||||
|
||||
# read head pointer
|
||||
new_head_ptr = await tb.axil_master.read_dword(0*32+16) # head pointer
|
||||
tb.log.info("Head pointer: %d", new_head_ptr)
|
||||
|
||||
assert new_head_ptr - head_ptr == 1
|
||||
|
||||
# increment tail pointer
|
||||
tail_ptr = await tb.axil_master.read_dword(0*32+24) # tail pointer
|
||||
tail_ptr += 1
|
||||
tb.log.info("Tail pointer: %d", tail_ptr)
|
||||
await tb.axil_master.write_dword(0*32+24, tail_ptr) # head pointer
|
||||
|
||||
tb.log.info("Test multiple enqueue and dequeue")
|
||||
|
||||
for k in range(4):
|
||||
await tb.axil_master.write_dword(k*32+8, 0x00000004) # active, log size
|
||||
await tb.axil_master.write_qword(k*32+0, 0x5555555555000000 + 0x10000*k) # address
|
||||
await tb.axil_master.write_dword(k*32+8, 0x00000004) # active, log size
|
||||
await tb.axil_master.write_dword(k*32+12, 0xC0000000 + k) # armed, continuous, event
|
||||
await tb.axil_master.write_dword(k*32+16, 0x0000fff0) # head pointer
|
||||
await tb.axil_master.write_dword(k*32+24, 0x0000fff0) # tail pointer
|
||||
await tb.axil_master.write_dword(k*32+8, 0x80000004) # active, log size
|
||||
|
||||
current_tag = 1
|
||||
|
||||
queue_head_ptr = [0xfff0]*4
|
||||
queue_tail_ptr = [0xfff0]*4
|
||||
queue_depth = [0]*4
|
||||
queue_uncommit_depth = [0]*4
|
||||
|
||||
commit_list = []
|
||||
|
||||
random.seed(123456)
|
||||
|
||||
for i in range(50):
|
||||
# enqueue
|
||||
for k in range(random.randrange(8)):
|
||||
q = random.randrange(4)
|
||||
|
||||
if len(commit_list) < OP_TABLE_SIZE:
|
||||
tb.log.info("Try enqueue into queue %d", q)
|
||||
|
||||
# enqueue request
|
||||
tb.enqueue_req_source.send(EnqueueReqTransaction(queue=q, tag=current_tag))
|
||||
|
||||
await tb.enqueue_resp_sink.wait()
|
||||
resp = tb.enqueue_resp_sink.recv()
|
||||
|
||||
tb.log.info("Enqueue response: %s", resp)
|
||||
|
||||
assert resp.queue == q
|
||||
assert resp.ptr == queue_head_ptr[q]
|
||||
assert (resp.addr >> 16) & 0xf == q
|
||||
assert (resp.addr >> 4) & 0xf == queue_head_ptr[q] & 0xf
|
||||
assert resp.event == q
|
||||
assert resp.tag == current_tag
|
||||
assert not resp.error
|
||||
|
||||
if queue_uncommit_depth[q] < 16:
|
||||
commit_list.append((q, resp.op_tag))
|
||||
queue_head_ptr[q] = (queue_head_ptr[q] + 1) & 0xffff
|
||||
queue_uncommit_depth[q] += 1
|
||||
assert not resp.full
|
||||
else:
|
||||
tb.log.info("Queue was full")
|
||||
assert resp.full
|
||||
|
||||
current_tag = (current_tag + 1) % 256
|
||||
|
||||
# commit
|
||||
#random.shuffle(commit_list)
|
||||
for k in range(random.randrange(8)):
|
||||
if commit_list:
|
||||
q, t = commit_list.pop(0)
|
||||
|
||||
tb.log.info("Commit enqueue into queue %d", q)
|
||||
|
||||
# enqueue commit
|
||||
tb.enqueue_commit_source.send(EnqueueCommitTransaction(op_tag=t))
|
||||
|
||||
queue_depth[q] += 1
|
||||
|
||||
# check event
|
||||
await tb.event_sink.wait()
|
||||
event = tb.event_sink.recv()
|
||||
tb.log.info("Event: %s", event)
|
||||
|
||||
assert event.event == q
|
||||
assert event.event_source == q
|
||||
|
||||
# dequeue
|
||||
for k in range(random.randrange(8)):
|
||||
q = random.randrange(4)
|
||||
|
||||
if queue_depth[q] > 0:
|
||||
tb.log.info("Dequeue from queue %d", q)
|
||||
|
||||
# increment tail pointer
|
||||
tail_ptr = await tb.axil_master.read_dword(q*32+24) # tail pointer
|
||||
|
||||
assert tail_ptr == queue_tail_ptr[q]
|
||||
|
||||
tail_ptr = (tail_ptr + 1) & 0xffff
|
||||
|
||||
queue_tail_ptr[q] = tail_ptr
|
||||
queue_depth[q] -= 1
|
||||
queue_uncommit_depth[q] -= 1
|
||||
|
||||
tb.log.info("Tail pointer: %d", tail_ptr)
|
||||
await tb.axil_master.write_dword(q*32+24, tail_ptr) # tail pointer
|
||||
|
||||
await RisingEdge(dut.clk)
|
||||
await RisingEdge(dut.clk)
|
||||
|
||||
|
||||
if cocotb.SIM_NAME:
|
||||
|
||||
factory = TestFactory(run_test)
|
||||
factory.generate_tests()
|
||||
|
||||
|
||||
# cocotb-test
|
||||
|
||||
tests_dir = os.path.dirname(__file__)
|
||||
rtl_dir = os.path.abspath(os.path.join(tests_dir, '..', '..', 'rtl'))
|
||||
lib_dir = os.path.abspath(os.path.join(rtl_dir, '..', 'lib'))
|
||||
axi_rtl_dir = os.path.abspath(os.path.join(lib_dir, 'axi', 'rtl'))
|
||||
axis_rtl_dir = os.path.abspath(os.path.join(lib_dir, 'axis', 'rtl'))
|
||||
eth_rtl_dir = os.path.abspath(os.path.join(lib_dir, 'eth', 'rtl'))
|
||||
pcie_rtl_dir = os.path.abspath(os.path.join(lib_dir, 'pcie', 'rtl'))
|
||||
|
||||
|
||||
def test_cpl_queue_manager(request):
|
||||
dut = "cpl_queue_manager"
|
||||
module = os.path.splitext(os.path.basename(__file__))[0]
|
||||
toplevel = dut
|
||||
|
||||
verilog_sources = [
|
||||
os.path.join(rtl_dir, f"{dut}.v"),
|
||||
]
|
||||
|
||||
parameters = {}
|
||||
|
||||
parameters['ADDR_WIDTH'] = 64
|
||||
parameters['REQ_TAG_WIDTH'] = 8
|
||||
parameters['OP_TABLE_SIZE'] = 16
|
||||
parameters['OP_TAG_WIDTH'] = 8
|
||||
parameters['QUEUE_INDEX_WIDTH'] = 8
|
||||
parameters['EVENT_WIDTH'] = 8
|
||||
parameters['QUEUE_PTR_WIDTH'] = 16
|
||||
parameters['LOG_QUEUE_SIZE_WIDTH'] = 4
|
||||
parameters['CPL_SIZE'] = 16
|
||||
parameters['PIPELINE'] = 2
|
||||
parameters['AXIL_DATA_WIDTH'] = 32
|
||||
parameters['AXIL_ADDR_WIDTH'] = 16
|
||||
parameters['AXIL_STRB_WIDTH'] = parameters['AXIL_DATA_WIDTH'] // 8
|
||||
|
||||
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(
|
||||
python_search=[tests_dir],
|
||||
verilog_sources=verilog_sources,
|
||||
toplevel=toplevel,
|
||||
module=module,
|
||||
parameters=parameters,
|
||||
sim_build=sim_build,
|
||||
extra_env=extra_env,
|
||||
)
|
@ -1 +0,0 @@
|
||||
../lib/eth/tb/eth_ep.py
|
@ -1 +0,0 @@
|
||||
../lib/eth/tb/ip_ep.py
|
@ -31,9 +31,10 @@ either expressed or implied, of The Regents of the University of California.
|
||||
|
||||
"""
|
||||
|
||||
from myhdl import *
|
||||
from collections import deque
|
||||
|
||||
import pcie
|
||||
from cocotb.log import SimLog
|
||||
from cocotb.triggers import Event
|
||||
|
||||
import struct
|
||||
|
||||
@ -232,19 +233,26 @@ class Packet(object):
|
||||
|
||||
def __repr__(self):
|
||||
return (
|
||||
('Packet(data=%s, ' % repr(self.data)) +
|
||||
('timestamp_s=%d, ' % self.timestamp_s) +
|
||||
('timestamp_ns=%d, ' % self.timestamp_ns) +
|
||||
('rx_checksum=0x%x)' % self.rx_checksum)
|
||||
)
|
||||
f'{type(self).__name__}(data={self.data}, '
|
||||
f'timestamp_s={self.timestamp_s}, '
|
||||
f'timestamp_ns={self.timestamp_ns}, '
|
||||
f'rx_checksum={self.rx_checksum:#06x})'
|
||||
)
|
||||
|
||||
def __iter__(self):
|
||||
return self.data.__iter__()
|
||||
|
||||
def __len__(self):
|
||||
return len(self.data)
|
||||
|
||||
def __bytes__(self):
|
||||
return bytes(self.data)
|
||||
|
||||
|
||||
class EqRing(object):
|
||||
def __init__(self, interface, size, stride, index, hw_addr):
|
||||
self.interface = interface
|
||||
self.log = interface.log
|
||||
self.driver = interface.driver
|
||||
self.rc = interface.driver.rc
|
||||
self.log_size = size.bit_length() - 1
|
||||
@ -262,32 +270,34 @@ class EqRing(object):
|
||||
self.hw_head_ptr = hw_addr+MQNIC_EVENT_QUEUE_HEAD_PTR_REG
|
||||
self.hw_tail_ptr = hw_addr+MQNIC_EVENT_QUEUE_TAIL_PTR_REG
|
||||
|
||||
def init(self):
|
||||
async def init(self):
|
||||
self.log.info("Init EqRing %d (interface %d)", self.index, self.interface.index)
|
||||
|
||||
self.buf_size = self.size*self.stride
|
||||
self.buf_dma, self.buf = self.rc.alloc_region(self.buf_size)
|
||||
|
||||
yield from self.rc.mem_write_dword(self.hw_addr+MQNIC_EVENT_QUEUE_ACTIVE_LOG_SIZE_REG, 0) # active, log size
|
||||
yield from self.rc.mem_write_dword(self.hw_addr+MQNIC_EVENT_QUEUE_BASE_ADDR_REG, self.buf_dma & 0xffffffff) # base address
|
||||
yield from self.rc.mem_write_dword(self.hw_addr+MQNIC_EVENT_QUEUE_BASE_ADDR_REG+4, self.buf_dma >> 32) # base address
|
||||
yield from self.rc.mem_write_dword(self.hw_addr+MQNIC_EVENT_QUEUE_INTERRUPT_INDEX_REG, 0) # interrupt index
|
||||
yield from self.rc.mem_write_dword(self.hw_addr+MQNIC_EVENT_QUEUE_HEAD_PTR_REG, self.head_ptr & self.hw_ptr_mask) # head pointer
|
||||
yield from self.rc.mem_write_dword(self.hw_addr+MQNIC_EVENT_QUEUE_TAIL_PTR_REG, self.tail_ptr & self.hw_ptr_mask) # tail pointer
|
||||
yield from self.rc.mem_write_dword(self.hw_addr+MQNIC_EVENT_QUEUE_ACTIVE_LOG_SIZE_REG, self.log_size) # active, log size
|
||||
await self.rc.mem_write_dword(self.hw_addr+MQNIC_EVENT_QUEUE_ACTIVE_LOG_SIZE_REG, 0) # active, log size
|
||||
await self.rc.mem_write_dword(self.hw_addr+MQNIC_EVENT_QUEUE_BASE_ADDR_REG, self.buf_dma & 0xffffffff) # base address
|
||||
await self.rc.mem_write_dword(self.hw_addr+MQNIC_EVENT_QUEUE_BASE_ADDR_REG+4, self.buf_dma >> 32) # base address
|
||||
await self.rc.mem_write_dword(self.hw_addr+MQNIC_EVENT_QUEUE_INTERRUPT_INDEX_REG, 0) # interrupt index
|
||||
await self.rc.mem_write_dword(self.hw_addr+MQNIC_EVENT_QUEUE_HEAD_PTR_REG, self.head_ptr & self.hw_ptr_mask) # head pointer
|
||||
await self.rc.mem_write_dword(self.hw_addr+MQNIC_EVENT_QUEUE_TAIL_PTR_REG, self.tail_ptr & self.hw_ptr_mask) # tail pointer
|
||||
await self.rc.mem_write_dword(self.hw_addr+MQNIC_EVENT_QUEUE_ACTIVE_LOG_SIZE_REG, self.log_size) # active, log size
|
||||
|
||||
async def activate(self, int_index):
|
||||
self.log.info("Activate EqRing %d (interface %d)", self.index, self.interface.index)
|
||||
|
||||
def activate(self, int_index):
|
||||
self.interrupt_index = int_index
|
||||
|
||||
yield from self.rc.mem_write_dword(self.hw_addr+MQNIC_EVENT_QUEUE_ACTIVE_LOG_SIZE_REG, 0) # active, log size
|
||||
yield from self.rc.mem_write_dword(self.hw_addr+MQNIC_EVENT_QUEUE_BASE_ADDR_REG, self.buf_dma & 0xffffffff) # base address
|
||||
yield from self.rc.mem_write_dword(self.hw_addr+MQNIC_EVENT_QUEUE_BASE_ADDR_REG+4, self.buf_dma >> 32) # base address
|
||||
yield from self.rc.mem_write_dword(self.hw_addr+MQNIC_EVENT_QUEUE_INTERRUPT_INDEX_REG, int_index) # interrupt index
|
||||
yield from self.rc.mem_write_dword(self.hw_addr+MQNIC_EVENT_QUEUE_HEAD_PTR_REG, self.head_ptr & self.hw_ptr_mask) # head pointer
|
||||
yield from self.rc.mem_write_dword(self.hw_addr+MQNIC_EVENT_QUEUE_TAIL_PTR_REG, self.tail_ptr & self.hw_ptr_mask) # tail pointer
|
||||
yield from self.rc.mem_write_dword(self.hw_addr+MQNIC_EVENT_QUEUE_ACTIVE_LOG_SIZE_REG, self.log_size | MQNIC_EVENT_QUEUE_ACTIVE_MASK) # active, log size
|
||||
await self.rc.mem_write_dword(self.hw_addr+MQNIC_EVENT_QUEUE_ACTIVE_LOG_SIZE_REG, 0) # active, log size
|
||||
await self.rc.mem_write_dword(self.hw_addr+MQNIC_EVENT_QUEUE_INTERRUPT_INDEX_REG, int_index) # interrupt index
|
||||
await self.rc.mem_write_dword(self.hw_addr+MQNIC_EVENT_QUEUE_HEAD_PTR_REG, self.head_ptr & self.hw_ptr_mask) # head pointer
|
||||
await self.rc.mem_write_dword(self.hw_addr+MQNIC_EVENT_QUEUE_TAIL_PTR_REG, self.tail_ptr & self.hw_ptr_mask) # tail pointer
|
||||
await self.rc.mem_write_dword(self.hw_addr+MQNIC_EVENT_QUEUE_ACTIVE_LOG_SIZE_REG, self.log_size | MQNIC_EVENT_QUEUE_ACTIVE_MASK) # active, log size
|
||||
|
||||
def deactivate(self):
|
||||
yield from self.rc.mem_write_dword(self.hw_addr+MQNIC_EVENT_QUEUE_ACTIVE_LOG_SIZE_REG, self.log_size) # active, log size
|
||||
yield from self.rc.mem_write_dword(self.hw_addr+MQNIC_EVENT_QUEUE_INTERRUPT_INDEX_REG, self.interrupt_index) # interrupt index
|
||||
async def deactivate(self):
|
||||
await self.rc.mem_write_dword(self.hw_addr+MQNIC_EVENT_QUEUE_ACTIVE_LOG_SIZE_REG, self.log_size) # active, log size
|
||||
await self.rc.mem_write_dword(self.hw_addr+MQNIC_EVENT_QUEUE_INTERRUPT_INDEX_REG, self.interrupt_index) # interrupt index
|
||||
|
||||
def empty(self):
|
||||
return self.head_ptr == self.tail_ptr
|
||||
@ -295,55 +305,56 @@ class EqRing(object):
|
||||
def full(self):
|
||||
return self.head_ptr - self.tail_ptr >= self.size
|
||||
|
||||
def read_head_ptr(self):
|
||||
val = yield from self.rc.mem_read_dword(self.hw_head_ptr)
|
||||
async def read_head_ptr(self):
|
||||
val = await self.rc.mem_read_dword(self.hw_head_ptr)
|
||||
self.head_ptr += (val - self.head_ptr) & self.hw_ptr_mask
|
||||
|
||||
def write_tail_ptr(self):
|
||||
yield from self.rc.mem_write_dword(self.hw_tail_ptr, self.tail_ptr & self.hw_ptr_mask)
|
||||
async def write_tail_ptr(self):
|
||||
await self.rc.mem_write_dword(self.hw_tail_ptr, self.tail_ptr & self.hw_ptr_mask)
|
||||
|
||||
def arm(self):
|
||||
yield from self.rc.mem_write_dword(self.hw_addr+MQNIC_EVENT_QUEUE_INTERRUPT_INDEX_REG, self.interrupt_index | MQNIC_EVENT_QUEUE_ARM_MASK) # interrupt index
|
||||
async def arm(self):
|
||||
await self.rc.mem_write_dword(self.hw_addr+MQNIC_EVENT_QUEUE_INTERRUPT_INDEX_REG, self.interrupt_index | MQNIC_EVENT_QUEUE_ARM_MASK) # interrupt index
|
||||
|
||||
def process(self):
|
||||
async def process(self):
|
||||
if not self.interface.port_up:
|
||||
return
|
||||
|
||||
print("Process event queue")
|
||||
self.log.info("Process event queue")
|
||||
|
||||
yield from self.read_head_ptr()
|
||||
await self.read_head_ptr()
|
||||
|
||||
eq_tail_ptr = self.tail_ptr
|
||||
eq_index = eq_tail_ptr & self.size_mask
|
||||
|
||||
print("%d events in queue" % (self.head_ptr - eq_tail_ptr))
|
||||
self.log.info("%d events in queue", self.head_ptr - eq_tail_ptr)
|
||||
|
||||
while (self.head_ptr != eq_tail_ptr):
|
||||
event_data = struct.unpack_from("<HH", self.buf, eq_index*self.stride)
|
||||
|
||||
print("Event data: "+repr(event_data))
|
||||
self.log.info("Event data: %s", repr(event_data))
|
||||
|
||||
if event_data[0] == 0:
|
||||
# transmit completion
|
||||
cq = self.interface.tx_cpl_queues[event_data[1]]
|
||||
yield from self.interface.process_tx_cq(cq)
|
||||
yield from cq.arm()
|
||||
await self.interface.process_tx_cq(cq)
|
||||
await cq.arm()
|
||||
elif event_data[0] == 1:
|
||||
# receive completion
|
||||
cq = self.interface.rx_cpl_queues[event_data[1]]
|
||||
yield from self.interface.process_rx_cq(cq)
|
||||
yield from cq.arm()
|
||||
await self.interface.process_rx_cq(cq)
|
||||
await cq.arm()
|
||||
|
||||
eq_tail_ptr += 1
|
||||
eq_index = eq_tail_ptr & self.size_mask
|
||||
|
||||
self.tail_ptr = eq_tail_ptr
|
||||
yield from self.write_tail_ptr()
|
||||
await self.write_tail_ptr()
|
||||
|
||||
|
||||
class CqRing(object):
|
||||
def __init__(self, interface, size, stride, index, hw_addr):
|
||||
self.interface = interface
|
||||
self.log = interface.log
|
||||
self.driver = interface.driver
|
||||
self.rc = interface.driver.rc
|
||||
self.log_size = size.bit_length() - 1
|
||||
@ -362,32 +373,34 @@ class CqRing(object):
|
||||
self.hw_head_ptr = hw_addr+MQNIC_CPL_QUEUE_HEAD_PTR_REG
|
||||
self.hw_tail_ptr = hw_addr+MQNIC_CPL_QUEUE_TAIL_PTR_REG
|
||||
|
||||
def init(self):
|
||||
async def init(self):
|
||||
self.log.info("Init CqRing %d (interface %d)", self.index, self.interface.index)
|
||||
|
||||
self.buf_size = self.size*self.stride
|
||||
self.buf_dma, self.buf = self.rc.alloc_region(self.buf_size)
|
||||
|
||||
yield from self.rc.mem_write_dword(self.hw_addr+MQNIC_CPL_QUEUE_ACTIVE_LOG_SIZE_REG, 0) # active, log size
|
||||
yield from self.rc.mem_write_dword(self.hw_addr+MQNIC_CPL_QUEUE_BASE_ADDR_REG, self.buf_dma & 0xffffffff) # base address
|
||||
yield from self.rc.mem_write_dword(self.hw_addr+MQNIC_CPL_QUEUE_BASE_ADDR_REG+4, self.buf_dma >> 32) # base address
|
||||
yield from self.rc.mem_write_dword(self.hw_addr+MQNIC_CPL_QUEUE_INTERRUPT_INDEX_REG, 0) # event index
|
||||
yield from self.rc.mem_write_dword(self.hw_addr+MQNIC_CPL_QUEUE_HEAD_PTR_REG, self.head_ptr & self.hw_ptr_mask) # head pointer
|
||||
yield from self.rc.mem_write_dword(self.hw_addr+MQNIC_CPL_QUEUE_TAIL_PTR_REG, self.tail_ptr & self.hw_ptr_mask) # tail pointer
|
||||
yield from self.rc.mem_write_dword(self.hw_addr+MQNIC_CPL_QUEUE_ACTIVE_LOG_SIZE_REG, self.log_size) # active, log size
|
||||
await self.rc.mem_write_dword(self.hw_addr+MQNIC_CPL_QUEUE_ACTIVE_LOG_SIZE_REG, 0) # active, log size
|
||||
await self.rc.mem_write_dword(self.hw_addr+MQNIC_CPL_QUEUE_BASE_ADDR_REG, self.buf_dma & 0xffffffff) # base address
|
||||
await self.rc.mem_write_dword(self.hw_addr+MQNIC_CPL_QUEUE_BASE_ADDR_REG+4, self.buf_dma >> 32) # base address
|
||||
await self.rc.mem_write_dword(self.hw_addr+MQNIC_CPL_QUEUE_INTERRUPT_INDEX_REG, 0) # event index
|
||||
await self.rc.mem_write_dword(self.hw_addr+MQNIC_CPL_QUEUE_HEAD_PTR_REG, self.head_ptr & self.hw_ptr_mask) # head pointer
|
||||
await self.rc.mem_write_dword(self.hw_addr+MQNIC_CPL_QUEUE_TAIL_PTR_REG, self.tail_ptr & self.hw_ptr_mask) # tail pointer
|
||||
await self.rc.mem_write_dword(self.hw_addr+MQNIC_CPL_QUEUE_ACTIVE_LOG_SIZE_REG, self.log_size) # active, log size
|
||||
|
||||
async def activate(self, int_index):
|
||||
self.log.info("Activate CqRing %d (interface %d)", self.index, self.interface.index)
|
||||
|
||||
def activate(self, int_index):
|
||||
self.interrupt_index = int_index
|
||||
|
||||
yield from self.rc.mem_write_dword(self.hw_addr+MQNIC_CPL_QUEUE_ACTIVE_LOG_SIZE_REG, 0) # active, log size
|
||||
yield from self.rc.mem_write_dword(self.hw_addr+MQNIC_CPL_QUEUE_BASE_ADDR_REG, self.buf_dma & 0xffffffff) # base address
|
||||
yield from self.rc.mem_write_dword(self.hw_addr+MQNIC_CPL_QUEUE_BASE_ADDR_REG+4, self.buf_dma >> 32) # base address
|
||||
yield from self.rc.mem_write_dword(self.hw_addr+MQNIC_CPL_QUEUE_INTERRUPT_INDEX_REG, int_index) # event index
|
||||
yield from self.rc.mem_write_dword(self.hw_addr+MQNIC_CPL_QUEUE_HEAD_PTR_REG, self.head_ptr & self.hw_ptr_mask) # head pointer
|
||||
yield from self.rc.mem_write_dword(self.hw_addr+MQNIC_CPL_QUEUE_TAIL_PTR_REG, self.tail_ptr & self.hw_ptr_mask) # tail pointer
|
||||
yield from self.rc.mem_write_dword(self.hw_addr+MQNIC_CPL_QUEUE_ACTIVE_LOG_SIZE_REG, self.log_size | MQNIC_CPL_QUEUE_ACTIVE_MASK) # active, log size
|
||||
await self.rc.mem_write_dword(self.hw_addr+MQNIC_CPL_QUEUE_ACTIVE_LOG_SIZE_REG, 0) # active, log size
|
||||
await self.rc.mem_write_dword(self.hw_addr+MQNIC_CPL_QUEUE_INTERRUPT_INDEX_REG, int_index) # event index
|
||||
await self.rc.mem_write_dword(self.hw_addr+MQNIC_CPL_QUEUE_HEAD_PTR_REG, self.head_ptr & self.hw_ptr_mask) # head pointer
|
||||
await self.rc.mem_write_dword(self.hw_addr+MQNIC_CPL_QUEUE_TAIL_PTR_REG, self.tail_ptr & self.hw_ptr_mask) # tail pointer
|
||||
await self.rc.mem_write_dword(self.hw_addr+MQNIC_CPL_QUEUE_ACTIVE_LOG_SIZE_REG, self.log_size | MQNIC_CPL_QUEUE_ACTIVE_MASK) # active, log size
|
||||
|
||||
def deactivate(self):
|
||||
yield from self.rc.mem_write_dword(self.hw_addr+MQNIC_CPL_QUEUE_ACTIVE_LOG_SIZE_REG, self.log_size) # active, log size
|
||||
yield from self.rc.mem_write_dword(self.hw_addr+MQNIC_CPL_QUEUE_CPL_QUEUE_INDEX_REG, int_index) # event index
|
||||
async def deactivate(self):
|
||||
await self.rc.mem_write_dword(self.hw_addr+MQNIC_CPL_QUEUE_ACTIVE_LOG_SIZE_REG, self.log_size) # active, log size
|
||||
await self.rc.mem_write_dword(self.hw_addr+MQNIC_CPL_QUEUE_INTERRUPT_INDEX_REG, self.interrupt_index) # event index
|
||||
|
||||
def empty(self):
|
||||
return self.head_ptr == self.tail_ptr
|
||||
@ -395,20 +408,21 @@ class CqRing(object):
|
||||
def full(self):
|
||||
return self.head_ptr - self.tail_ptr >= self.size
|
||||
|
||||
def read_head_ptr(self):
|
||||
val = yield from self.rc.mem_read_dword(self.hw_head_ptr)
|
||||
async def read_head_ptr(self):
|
||||
val = await self.rc.mem_read_dword(self.hw_head_ptr)
|
||||
self.head_ptr += (val - self.head_ptr) & self.hw_ptr_mask
|
||||
|
||||
def write_tail_ptr(self):
|
||||
yield from self.rc.mem_write_dword(self.hw_tail_ptr, self.tail_ptr & self.hw_ptr_mask)
|
||||
async def write_tail_ptr(self):
|
||||
await self.rc.mem_write_dword(self.hw_tail_ptr, self.tail_ptr & self.hw_ptr_mask)
|
||||
|
||||
def arm(self):
|
||||
yield from self.rc.mem_write_dword(self.hw_addr+MQNIC_CPL_QUEUE_INTERRUPT_INDEX_REG, self.interrupt_index | MQNIC_CPL_QUEUE_ARM_MASK) # event index
|
||||
async def arm(self):
|
||||
await self.rc.mem_write_dword(self.hw_addr+MQNIC_CPL_QUEUE_INTERRUPT_INDEX_REG, self.interrupt_index | MQNIC_CPL_QUEUE_ARM_MASK) # event index
|
||||
|
||||
|
||||
class TxRing(object):
|
||||
def __init__(self, interface, size, stride, index, hw_addr):
|
||||
self.interface = interface
|
||||
self.log = interface.log
|
||||
self.driver = interface.driver
|
||||
self.rc = interface.driver.rc
|
||||
self.log_queue_size = size.bit_length() - 1
|
||||
@ -427,39 +441,41 @@ class TxRing(object):
|
||||
|
||||
self.packets = 0
|
||||
self.bytes = 0
|
||||
|
||||
|
||||
self.hw_ptr_mask = 0xffff
|
||||
self.hw_addr = hw_addr
|
||||
self.hw_head_ptr = hw_addr+MQNIC_QUEUE_HEAD_PTR_REG
|
||||
self.hw_tail_ptr = hw_addr+MQNIC_QUEUE_TAIL_PTR_REG
|
||||
|
||||
def init(self):
|
||||
async def init(self):
|
||||
self.log.info("Init TxRing %d (interface %d)", self.index, self.interface.index)
|
||||
|
||||
self.tx_info = [None]*self.size
|
||||
|
||||
self.buf_size = self.size*self.stride
|
||||
self.buf_dma, self.buf = self.rc.alloc_region(self.buf_size)
|
||||
|
||||
yield from self.rc.mem_write_dword(self.hw_addr+MQNIC_QUEUE_ACTIVE_LOG_SIZE_REG, 0) # active, log size
|
||||
yield from self.rc.mem_write_dword(self.hw_addr+MQNIC_QUEUE_BASE_ADDR_REG, self.buf_dma & 0xffffffff) # base address
|
||||
yield from self.rc.mem_write_dword(self.hw_addr+MQNIC_QUEUE_BASE_ADDR_REG+4, self.buf_dma >> 32) # base address
|
||||
yield from self.rc.mem_write_dword(self.hw_addr+MQNIC_QUEUE_CPL_QUEUE_INDEX_REG, 0) # completion queue index
|
||||
yield from self.rc.mem_write_dword(self.hw_addr+MQNIC_QUEUE_HEAD_PTR_REG, self.head_ptr & self.hw_ptr_mask) # head pointer
|
||||
yield from self.rc.mem_write_dword(self.hw_addr+MQNIC_QUEUE_TAIL_PTR_REG, self.tail_ptr & self.hw_ptr_mask) # tail pointer
|
||||
yield from self.rc.mem_write_dword(self.hw_addr+MQNIC_QUEUE_ACTIVE_LOG_SIZE_REG, self.log_queue_size | (self.log_desc_block_size << 8)) # active, log desc block size, log queue size
|
||||
await self.rc.mem_write_dword(self.hw_addr+MQNIC_QUEUE_ACTIVE_LOG_SIZE_REG, 0) # active, log size
|
||||
await self.rc.mem_write_dword(self.hw_addr+MQNIC_QUEUE_BASE_ADDR_REG, self.buf_dma & 0xffffffff) # base address
|
||||
await self.rc.mem_write_dword(self.hw_addr+MQNIC_QUEUE_BASE_ADDR_REG+4, self.buf_dma >> 32) # base address
|
||||
await self.rc.mem_write_dword(self.hw_addr+MQNIC_QUEUE_CPL_QUEUE_INDEX_REG, 0) # completion queue index
|
||||
await self.rc.mem_write_dword(self.hw_addr+MQNIC_QUEUE_HEAD_PTR_REG, self.head_ptr & self.hw_ptr_mask) # head pointer
|
||||
await self.rc.mem_write_dword(self.hw_addr+MQNIC_QUEUE_TAIL_PTR_REG, self.tail_ptr & self.hw_ptr_mask) # tail pointer
|
||||
await self.rc.mem_write_dword(self.hw_addr+MQNIC_QUEUE_ACTIVE_LOG_SIZE_REG, self.log_queue_size | (self.log_desc_block_size << 8)) # active, log desc block size, log queue size
|
||||
|
||||
async def activate(self, cpl_index):
|
||||
self.log.info("Activate TxRing %d (interface %d)", self.index, self.interface.index)
|
||||
|
||||
def activate(self, cpl_index):
|
||||
self.cpl_index = cpl_index
|
||||
|
||||
yield from self.rc.mem_write_dword(self.hw_addr+MQNIC_QUEUE_ACTIVE_LOG_SIZE_REG, 0) # active, log size
|
||||
yield from self.rc.mem_write_dword(self.hw_addr+MQNIC_QUEUE_BASE_ADDR_REG, self.buf_dma & 0xffffffff) # base address
|
||||
yield from self.rc.mem_write_dword(self.hw_addr+MQNIC_QUEUE_BASE_ADDR_REG+4, self.buf_dma >> 32) # base address
|
||||
yield from self.rc.mem_write_dword(self.hw_addr+MQNIC_QUEUE_CPL_QUEUE_INDEX_REG, cpl_index) # completion queue index
|
||||
yield from self.rc.mem_write_dword(self.hw_addr+MQNIC_QUEUE_HEAD_PTR_REG, self.head_ptr & self.hw_ptr_mask) # head pointer
|
||||
yield from self.rc.mem_write_dword(self.hw_addr+MQNIC_QUEUE_TAIL_PTR_REG, self.tail_ptr & self.hw_ptr_mask) # tail pointer
|
||||
yield from self.rc.mem_write_dword(self.hw_addr+MQNIC_QUEUE_ACTIVE_LOG_SIZE_REG, self.log_queue_size | (self.log_desc_block_size << 8) | MQNIC_QUEUE_ACTIVE_MASK) # active, log desc block size, log queue size
|
||||
await self.rc.mem_write_dword(self.hw_addr+MQNIC_QUEUE_ACTIVE_LOG_SIZE_REG, 0) # active, log size
|
||||
await self.rc.mem_write_dword(self.hw_addr+MQNIC_QUEUE_CPL_QUEUE_INDEX_REG, cpl_index) # completion queue index
|
||||
await self.rc.mem_write_dword(self.hw_addr+MQNIC_QUEUE_HEAD_PTR_REG, self.head_ptr & self.hw_ptr_mask) # head pointer
|
||||
await self.rc.mem_write_dword(self.hw_addr+MQNIC_QUEUE_TAIL_PTR_REG, self.tail_ptr & self.hw_ptr_mask) # tail pointer
|
||||
await self.rc.mem_write_dword(self.hw_addr+MQNIC_QUEUE_ACTIVE_LOG_SIZE_REG, self.log_queue_size | (self.log_desc_block_size << 8) | MQNIC_QUEUE_ACTIVE_MASK) # active, log desc block size, log queue size
|
||||
|
||||
def deactivate(self):
|
||||
yield from self.rc.mem_write_dword(self.hw_addr+MQNIC_QUEUE_ACTIVE_LOG_SIZE_REG, self.log_queue_size | (self.log_desc_block_size << 8)) # active, log desc block size, log queue size
|
||||
async def deactivate(self):
|
||||
await self.rc.mem_write_dword(self.hw_addr+MQNIC_QUEUE_ACTIVE_LOG_SIZE_REG, self.log_queue_size | (self.log_desc_block_size << 8)) # active, log desc block size, log queue size
|
||||
|
||||
def empty(self):
|
||||
return self.head_ptr == self.clean_tail_ptr
|
||||
@ -467,12 +483,12 @@ class TxRing(object):
|
||||
def full(self):
|
||||
return self.head_ptr - self.clean_tail_ptr >= self.full_size
|
||||
|
||||
def read_tail_ptr(self):
|
||||
val = yield from self.rc.mem_read_dword(self.hw_tail_ptr)
|
||||
async def read_tail_ptr(self):
|
||||
val = await self.rc.mem_read_dword(self.hw_tail_ptr)
|
||||
self.tail_ptr += (val - self.tail_ptr) & self.hw_ptr_mask
|
||||
|
||||
def write_head_ptr(self):
|
||||
yield from self.rc.mem_write_dword(self.hw_head_ptr, self.head_ptr & self.hw_ptr_mask)
|
||||
async def write_head_ptr(self):
|
||||
await self.rc.mem_write_dword(self.hw_head_ptr, self.head_ptr & self.hw_ptr_mask)
|
||||
|
||||
def free_desc(self, index):
|
||||
pkt = self.tx_info[index]
|
||||
@ -489,6 +505,7 @@ class TxRing(object):
|
||||
class RxRing(object):
|
||||
def __init__(self, interface, size, stride, index, hw_addr):
|
||||
self.interface = interface
|
||||
self.log = interface.log
|
||||
self.driver = interface.driver
|
||||
self.rc = interface.driver.rc
|
||||
self.log_queue_size = size.bit_length() - 1
|
||||
@ -507,41 +524,43 @@ class RxRing(object):
|
||||
|
||||
self.packets = 0
|
||||
self.bytes = 0
|
||||
|
||||
|
||||
self.hw_ptr_mask = 0xffff
|
||||
self.hw_addr = hw_addr
|
||||
self.hw_head_ptr = hw_addr+MQNIC_QUEUE_HEAD_PTR_REG
|
||||
self.hw_tail_ptr = hw_addr+MQNIC_QUEUE_TAIL_PTR_REG
|
||||
|
||||
def init(self):
|
||||
async def init(self):
|
||||
self.log.info("Init RxRing %d (interface %d)", self.index, self.interface.index)
|
||||
|
||||
self.rx_info = [None]*self.size
|
||||
|
||||
self.buf_size = self.size*self.stride
|
||||
self.buf_dma, self.buf = self.rc.alloc_region(self.buf_size)
|
||||
|
||||
yield from self.rc.mem_write_dword(self.hw_addr+MQNIC_QUEUE_ACTIVE_LOG_SIZE_REG, 0) # active, log size
|
||||
yield from self.rc.mem_write_dword(self.hw_addr+MQNIC_QUEUE_BASE_ADDR_REG, self.buf_dma & 0xffffffff) # base address
|
||||
yield from self.rc.mem_write_dword(self.hw_addr+MQNIC_QUEUE_BASE_ADDR_REG+4, self.buf_dma >> 32) # base address
|
||||
yield from self.rc.mem_write_dword(self.hw_addr+MQNIC_QUEUE_CPL_QUEUE_INDEX_REG, 0) # completion queue index
|
||||
yield from self.rc.mem_write_dword(self.hw_addr+MQNIC_QUEUE_HEAD_PTR_REG, self.head_ptr & self.hw_ptr_mask) # head pointer
|
||||
yield from self.rc.mem_write_dword(self.hw_addr+MQNIC_QUEUE_TAIL_PTR_REG, self.tail_ptr & self.hw_ptr_mask) # tail pointer
|
||||
yield from self.rc.mem_write_dword(self.hw_addr+MQNIC_QUEUE_ACTIVE_LOG_SIZE_REG, self.log_queue_size | (self.log_desc_block_size << 8)) # active, log desc block size, log queue size
|
||||
await self.rc.mem_write_dword(self.hw_addr+MQNIC_QUEUE_ACTIVE_LOG_SIZE_REG, 0) # active, log size
|
||||
await self.rc.mem_write_dword(self.hw_addr+MQNIC_QUEUE_BASE_ADDR_REG, self.buf_dma & 0xffffffff) # base address
|
||||
await self.rc.mem_write_dword(self.hw_addr+MQNIC_QUEUE_BASE_ADDR_REG+4, self.buf_dma >> 32) # base address
|
||||
await self.rc.mem_write_dword(self.hw_addr+MQNIC_QUEUE_CPL_QUEUE_INDEX_REG, 0) # completion queue index
|
||||
await self.rc.mem_write_dword(self.hw_addr+MQNIC_QUEUE_HEAD_PTR_REG, self.head_ptr & self.hw_ptr_mask) # head pointer
|
||||
await self.rc.mem_write_dword(self.hw_addr+MQNIC_QUEUE_TAIL_PTR_REG, self.tail_ptr & self.hw_ptr_mask) # tail pointer
|
||||
await self.rc.mem_write_dword(self.hw_addr+MQNIC_QUEUE_ACTIVE_LOG_SIZE_REG, self.log_queue_size | (self.log_desc_block_size << 8)) # active, log desc block size, log queue size
|
||||
|
||||
async def activate(self, cpl_index):
|
||||
self.log.info("Activate RxRing %d (interface %d)", self.index, self.interface.index)
|
||||
|
||||
def activate(self, cpl_index):
|
||||
self.cpl_index = cpl_index
|
||||
|
||||
yield from self.rc.mem_write_dword(self.hw_addr+MQNIC_QUEUE_ACTIVE_LOG_SIZE_REG, 0) # active, log size
|
||||
yield from self.rc.mem_write_dword(self.hw_addr+MQNIC_QUEUE_BASE_ADDR_REG, self.buf_dma & 0xffffffff) # base address
|
||||
yield from self.rc.mem_write_dword(self.hw_addr+MQNIC_QUEUE_BASE_ADDR_REG+4, self.buf_dma >> 32) # base address
|
||||
yield from self.rc.mem_write_dword(self.hw_addr+MQNIC_QUEUE_CPL_QUEUE_INDEX_REG, cpl_index) # completion queue index
|
||||
yield from self.rc.mem_write_dword(self.hw_addr+MQNIC_QUEUE_HEAD_PTR_REG, self.head_ptr & self.hw_ptr_mask) # head pointer
|
||||
yield from self.rc.mem_write_dword(self.hw_addr+MQNIC_QUEUE_TAIL_PTR_REG, self.tail_ptr & self.hw_ptr_mask) # tail pointer
|
||||
yield from self.rc.mem_write_dword(self.hw_addr+MQNIC_QUEUE_ACTIVE_LOG_SIZE_REG, self.log_queue_size | (self.log_desc_block_size << 8) | MQNIC_QUEUE_ACTIVE_MASK) # active, log desc block size, log queue size
|
||||
await self.rc.mem_write_dword(self.hw_addr+MQNIC_QUEUE_ACTIVE_LOG_SIZE_REG, 0) # active, log size
|
||||
await self.rc.mem_write_dword(self.hw_addr+MQNIC_QUEUE_CPL_QUEUE_INDEX_REG, cpl_index) # completion queue index
|
||||
await self.rc.mem_write_dword(self.hw_addr+MQNIC_QUEUE_HEAD_PTR_REG, self.head_ptr & self.hw_ptr_mask) # head pointer
|
||||
await self.rc.mem_write_dword(self.hw_addr+MQNIC_QUEUE_TAIL_PTR_REG, self.tail_ptr & self.hw_ptr_mask) # tail pointer
|
||||
await self.rc.mem_write_dword(self.hw_addr+MQNIC_QUEUE_ACTIVE_LOG_SIZE_REG, self.log_queue_size | (self.log_desc_block_size << 8) | MQNIC_QUEUE_ACTIVE_MASK) # active, log desc block size, log queue size
|
||||
|
||||
yield from self.refill_buffers()
|
||||
await self.refill_buffers()
|
||||
|
||||
def deactivate(self):
|
||||
yield from self.rc.mem_write_dword(self.hw_addr+MQNIC_QUEUE_ACTIVE_LOG_SIZE_REG, self.log_queue_size | (self.log_desc_block_size << 8)) # active, log desc block size, log queue size
|
||||
async def deactivate(self):
|
||||
await self.rc.mem_write_dword(self.hw_addr+MQNIC_QUEUE_ACTIVE_LOG_SIZE_REG, self.log_queue_size | (self.log_desc_block_size << 8)) # active, log desc block size, log queue size
|
||||
|
||||
def empty(self):
|
||||
return self.head_ptr == self.clean_tail_ptr
|
||||
@ -549,12 +568,12 @@ class RxRing(object):
|
||||
def full(self):
|
||||
return self.head_ptr - self.clean_tail_ptr >= self.full_size
|
||||
|
||||
def read_tail_ptr(self):
|
||||
val = yield from self.rc.mem_read_dword(self.hw_tail_ptr)
|
||||
async def read_tail_ptr(self):
|
||||
val = await self.rc.mem_read_dword(self.hw_tail_ptr)
|
||||
self.tail_ptr += (val - self.tail_ptr) & self.hw_ptr_mask
|
||||
|
||||
def write_head_ptr(self):
|
||||
yield from self.rc.mem_write_dword(self.hw_head_ptr, self.head_ptr & self.hw_ptr_mask)
|
||||
async def write_head_ptr(self):
|
||||
await self.rc.mem_write_dword(self.hw_head_ptr, self.head_ptr & self.hw_ptr_mask)
|
||||
|
||||
def free_desc(self, index):
|
||||
pkt = self.rx_info[index]
|
||||
@ -577,11 +596,11 @@ class RxRing(object):
|
||||
|
||||
# write descriptors
|
||||
for k in range(0, self.desc_block_size):
|
||||
l = min(length-offset, 4096) if k < self.desc_block_size-1 else length-offset
|
||||
struct.pack_into("<LLQ", self.buf, index*self.stride+k*MQNIC_DESC_SIZE, 0, l, ptr+offset if l else 0)
|
||||
offset += l
|
||||
seg = min(length-offset, 4096) if k < self.desc_block_size-1 else length-offset
|
||||
struct.pack_into("<LLQ", self.buf, index*self.stride+k*MQNIC_DESC_SIZE, 0, seg, ptr+offset if seg else 0)
|
||||
offset += seg
|
||||
|
||||
def refill_buffers(self):
|
||||
async def refill_buffers(self):
|
||||
missing = self.size - (self.head_ptr - self.clean_tail_ptr)
|
||||
|
||||
if missing < 8:
|
||||
@ -591,12 +610,13 @@ class RxRing(object):
|
||||
self.prepare_desc(self.head_ptr & self.size_mask)
|
||||
self.head_ptr += 1
|
||||
|
||||
yield from self.write_head_ptr()
|
||||
await self.write_head_ptr()
|
||||
|
||||
|
||||
class Scheduler(object):
|
||||
def __init__(self, port, index, hw_addr):
|
||||
self.port = port
|
||||
self.log = port.log
|
||||
self.interface = port.interface
|
||||
self.driver = port.interface.driver
|
||||
self.rc = port.interface.driver.rc
|
||||
@ -607,6 +627,7 @@ class Scheduler(object):
|
||||
class Port(object):
|
||||
def __init__(self, interface, index, hw_addr):
|
||||
self.interface = interface
|
||||
self.log = interface.log
|
||||
self.driver = interface.driver
|
||||
self.rc = interface.driver.rc
|
||||
self.index = index
|
||||
@ -620,40 +641,41 @@ class Port(object):
|
||||
self.sched_stride = None
|
||||
self.sched_type = None
|
||||
|
||||
def init(self):
|
||||
async def init(self):
|
||||
# Read ID registers
|
||||
self.port_id = yield from self.driver.rc.mem_read_dword(self.hw_addr+MQNIC_PORT_REG_PORT_ID)
|
||||
print("Port ID: {:#010x}".format(self.port_id))
|
||||
self.port_features = yield from self.driver.rc.mem_read_dword(self.hw_addr+MQNIC_PORT_REG_PORT_FEATURES)
|
||||
print("Port features: {:#010x}".format(self.port_features))
|
||||
self.port_mtu = yield from self.driver.rc.mem_read_dword(self.hw_addr+MQNIC_PORT_REG_PORT_MTU)
|
||||
print("Port MTU: {}".format(self.port_mtu))
|
||||
self.port_id = await self.driver.rc.mem_read_dword(self.hw_addr+MQNIC_PORT_REG_PORT_ID)
|
||||
self.log.info("Port ID: 0x%08x", self.port_id)
|
||||
self.port_features = await self.driver.rc.mem_read_dword(self.hw_addr+MQNIC_PORT_REG_PORT_FEATURES)
|
||||
self.log.info("Port features: 0x%08x", self.port_features)
|
||||
self.port_mtu = await self.driver.rc.mem_read_dword(self.hw_addr+MQNIC_PORT_REG_PORT_MTU)
|
||||
self.log.info("Port MTU: %d", self.port_mtu)
|
||||
|
||||
self.sched_count = yield from self.driver.rc.mem_read_dword(self.hw_addr+MQNIC_PORT_REG_SCHED_COUNT)
|
||||
print("Scheduler count: {}".format(self.sched_count))
|
||||
self.sched_offset = yield from self.driver.rc.mem_read_dword(self.hw_addr+MQNIC_PORT_REG_SCHED_OFFSET)
|
||||
print("Scheduler offset: {:#010x}".format(self.sched_offset))
|
||||
self.sched_stride = yield from self.driver.rc.mem_read_dword(self.hw_addr+MQNIC_PORT_REG_SCHED_STRIDE)
|
||||
print("Scheduler stride: {:#010x}".format(self.sched_stride))
|
||||
self.sched_type = yield from self.driver.rc.mem_read_dword(self.hw_addr+MQNIC_PORT_REG_SCHED_TYPE)
|
||||
print("Scheduler type: {:#010x}".format(self.sched_type))
|
||||
self.sched_count = await self.driver.rc.mem_read_dword(self.hw_addr+MQNIC_PORT_REG_SCHED_COUNT)
|
||||
self.log.info("Scheduler count: %d", self.sched_count)
|
||||
self.sched_offset = await self.driver.rc.mem_read_dword(self.hw_addr+MQNIC_PORT_REG_SCHED_OFFSET)
|
||||
self.log.info("Scheduler offset: 0x%08x", self.sched_offset)
|
||||
self.sched_stride = await self.driver.rc.mem_read_dword(self.hw_addr+MQNIC_PORT_REG_SCHED_STRIDE)
|
||||
self.log.info("Scheduler stride: 0x%08x", self.sched_stride)
|
||||
self.sched_type = await self.driver.rc.mem_read_dword(self.hw_addr+MQNIC_PORT_REG_SCHED_TYPE)
|
||||
self.log.info("Scheduler type: 0x%08x", self.sched_type)
|
||||
|
||||
self.schedulers = []
|
||||
|
||||
yield from self.set_mtu(min(self.port_mtu, 9214))
|
||||
await self.set_mtu(min(self.port_mtu, 9214))
|
||||
|
||||
for k in range(self.sched_count):
|
||||
p = Scheduler(self, k, self.hw_addr + self.sched_offset + k*self.sched_stride)
|
||||
self.schedulers.append(p)
|
||||
|
||||
def set_mtu(self, mtu):
|
||||
yield from self.driver.rc.mem_write_dword(self.hw_addr+MQNIC_PORT_REG_TX_MTU, mtu)
|
||||
yield from self.driver.rc.mem_write_dword(self.hw_addr+MQNIC_PORT_REG_RX_MTU, mtu)
|
||||
async def set_mtu(self, mtu):
|
||||
await self.driver.rc.mem_write_dword(self.hw_addr+MQNIC_PORT_REG_TX_MTU, mtu)
|
||||
await self.driver.rc.mem_write_dword(self.hw_addr+MQNIC_PORT_REG_RX_MTU, mtu)
|
||||
|
||||
|
||||
class Interface(object):
|
||||
def __init__(self, driver, index, hw_addr):
|
||||
self.driver = driver
|
||||
self.log = driver.log
|
||||
self.index = index
|
||||
self.hw_addr = hw_addr
|
||||
self.csr_hw_addr = hw_addr+driver.if_csr_offset
|
||||
@ -677,44 +699,44 @@ class Interface(object):
|
||||
self.interrupt_running = False
|
||||
self.interrupt_pending = 0
|
||||
|
||||
self.pkt_rx_queue = []
|
||||
self.pkt_rx_sync = Signal(bool(0))
|
||||
self.pkt_rx_queue = deque()
|
||||
self.pkt_rx_sync = Event()
|
||||
|
||||
def init(self):
|
||||
async def init(self):
|
||||
self.driver.rc.msi_register_callback(self.driver.dev_id, self.interrupt, self.index)
|
||||
|
||||
# Read ID registers
|
||||
self.if_id = yield from self.driver.rc.mem_read_dword(self.csr_hw_addr+MQNIC_IF_REG_IF_ID)
|
||||
print("IF ID: {:#010x}".format(self.if_id))
|
||||
self.if_features = yield from self.driver.rc.mem_read_dword(self.csr_hw_addr+MQNIC_IF_REG_IF_FEATURES)
|
||||
print("IF features: {:#010x}".format(self.if_features))
|
||||
self.if_id = await self.driver.rc.mem_read_dword(self.csr_hw_addr+MQNIC_IF_REG_IF_ID)
|
||||
self.log.info("IF ID: 0x%08x", self.if_id)
|
||||
self.if_features = await self.driver.rc.mem_read_dword(self.csr_hw_addr+MQNIC_IF_REG_IF_FEATURES)
|
||||
self.log.info("IF features: 0x%08x", self.if_features)
|
||||
|
||||
self.event_queue_count = yield from self.driver.rc.mem_read_dword(self.csr_hw_addr+MQNIC_IF_REG_EVENT_QUEUE_COUNT)
|
||||
print("Event queue count: {}".format(self.event_queue_count))
|
||||
self.event_queue_offset = yield from self.driver.rc.mem_read_dword(self.csr_hw_addr+MQNIC_IF_REG_EVENT_QUEUE_OFFSET)
|
||||
print("Event queue offset: {:#010x}".format(self.event_queue_offset))
|
||||
self.tx_queue_count = yield from self.driver.rc.mem_read_dword(self.csr_hw_addr+MQNIC_IF_REG_TX_QUEUE_COUNT)
|
||||
print("TX queue count: {}".format(self.tx_queue_count))
|
||||
self.tx_queue_offset = yield from self.driver.rc.mem_read_dword(self.csr_hw_addr+MQNIC_IF_REG_TX_QUEUE_OFFSET)
|
||||
print("TX queue offset: {:#010x}".format(self.tx_queue_offset))
|
||||
self.tx_cpl_queue_count = yield from self.driver.rc.mem_read_dword(self.csr_hw_addr+MQNIC_IF_REG_TX_CPL_QUEUE_COUNT)
|
||||
print("TX completion queue count: {}".format(self.tx_cpl_queue_count))
|
||||
self.tx_cpl_queue_offset = yield from self.driver.rc.mem_read_dword(self.csr_hw_addr+MQNIC_IF_REG_TX_CPL_QUEUE_OFFSET)
|
||||
print("TX completion queue offset: {:#010x}".format(self.tx_cpl_queue_offset))
|
||||
self.rx_queue_count = yield from self.driver.rc.mem_read_dword(self.csr_hw_addr+MQNIC_IF_REG_RX_QUEUE_COUNT)
|
||||
print("RX queue count: {}".format(self.rx_queue_count))
|
||||
self.rx_queue_offset = yield from self.driver.rc.mem_read_dword(self.csr_hw_addr+MQNIC_IF_REG_RX_QUEUE_OFFSET)
|
||||
print("RX queue offset: {:#010x}".format(self.rx_queue_offset))
|
||||
self.rx_cpl_queue_count = yield from self.driver.rc.mem_read_dword(self.csr_hw_addr+MQNIC_IF_REG_RX_CPL_QUEUE_COUNT)
|
||||
print("RX completion queue count: {}".format(self.rx_cpl_queue_count))
|
||||
self.rx_cpl_queue_offset = yield from self.driver.rc.mem_read_dword(self.csr_hw_addr+MQNIC_IF_REG_RX_CPL_QUEUE_OFFSET)
|
||||
print("RX completion queue offset: {:#010x}".format(self.rx_cpl_queue_offset))
|
||||
self.port_count = yield from self.driver.rc.mem_read_dword(self.csr_hw_addr+MQNIC_IF_REG_PORT_COUNT)
|
||||
print("Port count: {}".format(self.port_count))
|
||||
self.port_offset = yield from self.driver.rc.mem_read_dword(self.csr_hw_addr+MQNIC_IF_REG_PORT_OFFSET)
|
||||
print("Port offset: {:#010x}".format(self.port_offset))
|
||||
self.port_stride = yield from self.driver.rc.mem_read_dword(self.csr_hw_addr+MQNIC_IF_REG_PORT_STRIDE)
|
||||
print("Port stride: {:#010x}".format(self.port_stride))
|
||||
self.event_queue_count = await self.driver.rc.mem_read_dword(self.csr_hw_addr+MQNIC_IF_REG_EVENT_QUEUE_COUNT)
|
||||
self.log.info("Event queue count: %d", self.event_queue_count)
|
||||
self.event_queue_offset = await self.driver.rc.mem_read_dword(self.csr_hw_addr+MQNIC_IF_REG_EVENT_QUEUE_OFFSET)
|
||||
self.log.info("Event queue offset: 0x%08x", self.event_queue_offset)
|
||||
self.tx_queue_count = await self.driver.rc.mem_read_dword(self.csr_hw_addr+MQNIC_IF_REG_TX_QUEUE_COUNT)
|
||||
self.log.info("TX queue count: %d", self.tx_queue_count)
|
||||
self.tx_queue_offset = await self.driver.rc.mem_read_dword(self.csr_hw_addr+MQNIC_IF_REG_TX_QUEUE_OFFSET)
|
||||
self.log.info("TX queue offset: 0x%08x", self.tx_queue_offset)
|
||||
self.tx_cpl_queue_count = await self.driver.rc.mem_read_dword(self.csr_hw_addr+MQNIC_IF_REG_TX_CPL_QUEUE_COUNT)
|
||||
self.log.info("TX completion queue count: %d", self.tx_cpl_queue_count)
|
||||
self.tx_cpl_queue_offset = await self.driver.rc.mem_read_dword(self.csr_hw_addr+MQNIC_IF_REG_TX_CPL_QUEUE_OFFSET)
|
||||
self.log.info("TX completion queue offset: 0x%08x", self.tx_cpl_queue_offset)
|
||||
self.rx_queue_count = await self.driver.rc.mem_read_dword(self.csr_hw_addr+MQNIC_IF_REG_RX_QUEUE_COUNT)
|
||||
self.log.info("RX queue count: %d", self.rx_queue_count)
|
||||
self.rx_queue_offset = await self.driver.rc.mem_read_dword(self.csr_hw_addr+MQNIC_IF_REG_RX_QUEUE_OFFSET)
|
||||
self.log.info("RX queue offset: 0x%08x", self.rx_queue_offset)
|
||||
self.rx_cpl_queue_count = await self.driver.rc.mem_read_dword(self.csr_hw_addr+MQNIC_IF_REG_RX_CPL_QUEUE_COUNT)
|
||||
self.log.info("RX completion queue count: %d", self.rx_cpl_queue_count)
|
||||
self.rx_cpl_queue_offset = await self.driver.rc.mem_read_dword(self.csr_hw_addr+MQNIC_IF_REG_RX_CPL_QUEUE_OFFSET)
|
||||
self.log.info("RX completion queue offset: 0x%08x", self.rx_cpl_queue_offset)
|
||||
self.port_count = await self.driver.rc.mem_read_dword(self.csr_hw_addr+MQNIC_IF_REG_PORT_COUNT)
|
||||
self.log.info("Port count: %d", self.port_count)
|
||||
self.port_offset = await self.driver.rc.mem_read_dword(self.csr_hw_addr+MQNIC_IF_REG_PORT_OFFSET)
|
||||
self.log.info("Port offset: 0x%08x", self.port_offset)
|
||||
self.port_stride = await self.driver.rc.mem_read_dword(self.csr_hw_addr+MQNIC_IF_REG_PORT_STRIDE)
|
||||
self.log.info("Port stride: 0x%08x", self.port_stride)
|
||||
|
||||
self.event_queue_count = min(self.event_queue_count, MQNIC_MAX_EVENT_RINGS)
|
||||
self.tx_queue_count = min(self.tx_queue_count, MQNIC_MAX_TX_RINGS)
|
||||
@ -731,111 +753,120 @@ class Interface(object):
|
||||
|
||||
for k in range(self.event_queue_count):
|
||||
q = EqRing(self, 1024, MQNIC_EVENT_SIZE, self.index, self.hw_addr + self.event_queue_offset + k*MQNIC_EVENT_QUEUE_STRIDE)
|
||||
yield from q.init()
|
||||
await q.init()
|
||||
self.event_queues.append(q)
|
||||
|
||||
for k in range(self.tx_queue_count):
|
||||
q = TxRing(self, 1024, MQNIC_DESC_SIZE*4, k, self.hw_addr + self.tx_queue_offset + k*MQNIC_QUEUE_STRIDE)
|
||||
yield from q.init()
|
||||
await q.init()
|
||||
self.tx_queues.append(q)
|
||||
|
||||
for k in range(self.tx_cpl_queue_count):
|
||||
q = CqRing(self, 1024, MQNIC_CPL_SIZE, k, self.hw_addr + self.tx_cpl_queue_offset + k*MQNIC_CPL_QUEUE_STRIDE)
|
||||
yield from q.init()
|
||||
await q.init()
|
||||
self.tx_cpl_queues.append(q)
|
||||
|
||||
for k in range(self.rx_queue_count):
|
||||
q = RxRing(self, 1024, MQNIC_DESC_SIZE*4, k, self.hw_addr + self.rx_queue_offset + k*MQNIC_QUEUE_STRIDE)
|
||||
yield from q.init()
|
||||
await q.init()
|
||||
self.rx_queues.append(q)
|
||||
|
||||
for k in range(self.rx_cpl_queue_count):
|
||||
q = CqRing(self, 1024, MQNIC_CPL_SIZE, k, self.hw_addr + self.rx_cpl_queue_offset + k*MQNIC_CPL_QUEUE_STRIDE)
|
||||
yield from q.init()
|
||||
await q.init()
|
||||
self.rx_cpl_queues.append(q)
|
||||
|
||||
for k in range(self.port_count):
|
||||
p = Port(self, k, self.hw_addr + self.port_offset + k*self.port_stride)
|
||||
yield from p.init()
|
||||
await p.init()
|
||||
self.ports.append(p)
|
||||
|
||||
def open(self):
|
||||
# wait for all writes to complete
|
||||
await self.driver.rc.mem_read(self.hw_addr, 4)
|
||||
|
||||
async def open(self):
|
||||
for q in self.event_queues:
|
||||
yield from q.activate(self.index) # TODO?
|
||||
q.handler = None # TODO
|
||||
yield from q.arm()
|
||||
await q.activate(self.index) # TODO?
|
||||
q.handler = None # TODO
|
||||
await q.arm()
|
||||
|
||||
for q in self.rx_cpl_queues:
|
||||
yield from q.activate(q.index % self.event_queue_count)
|
||||
await q.activate(q.index % self.event_queue_count)
|
||||
q.ring_index = q.index
|
||||
q.handler = None # TODO
|
||||
yield from q.arm()
|
||||
q.handler = None # TODO
|
||||
await q.arm()
|
||||
|
||||
for q in self.rx_queues:
|
||||
yield from q.activate(q.index)
|
||||
await q.activate(q.index)
|
||||
|
||||
for q in self.tx_cpl_queues:
|
||||
yield from q.activate(q.index % self.event_queue_count)
|
||||
await q.activate(q.index % self.event_queue_count)
|
||||
q.ring_index = q.index
|
||||
q.handler = None # TODO
|
||||
yield from q.arm()
|
||||
q.handler = None # TODO
|
||||
await q.arm()
|
||||
|
||||
for q in self.tx_queues:
|
||||
yield from q.activate(q.index)
|
||||
await q.activate(q.index)
|
||||
|
||||
# wait for all writes to complete
|
||||
await self.driver.rc.mem_read(self.hw_addr, 4)
|
||||
|
||||
self.port_up = True
|
||||
|
||||
def close(self):
|
||||
async def close(self):
|
||||
self.port_up = False
|
||||
|
||||
for q in self.tx_queues:
|
||||
yield from q.deactivate()
|
||||
await q.deactivate()
|
||||
|
||||
for q in self.tx_cpl_queues:
|
||||
yield from q.deactivate()
|
||||
await q.deactivate()
|
||||
|
||||
for q in self.rx_queues:
|
||||
yield from q.deactivate()
|
||||
await q.deactivate()
|
||||
|
||||
for q in self.rx_cpl_queues:
|
||||
yield from q.deactivate()
|
||||
await q.deactivate()
|
||||
|
||||
for q in self.event_queues:
|
||||
yield from q.deactivate()
|
||||
await q.deactivate()
|
||||
|
||||
yield delay(10000)
|
||||
# wait for all writes to complete
|
||||
await self.driver.rc.mem_read(self.hw_addr, 4)
|
||||
|
||||
for q in self.tx_queues:
|
||||
yield from q.free_buf()
|
||||
await q.free_buf()
|
||||
|
||||
for q in self.rx_queues:
|
||||
yield from q.free_buf()
|
||||
await q.free_buf()
|
||||
|
||||
def interrupt(self):
|
||||
print("Interface interrupt")
|
||||
async def interrupt(self):
|
||||
self.log.info("Interface interrupt (interface %d)", self.index)
|
||||
if self.interrupt_running:
|
||||
self.interrupt_pending += 1
|
||||
print("************************ interrupt was running")
|
||||
self.log.info("************************ interrupt was running")
|
||||
return
|
||||
self.interrupt_running = True
|
||||
for eq in self.event_queues:
|
||||
yield from eq.process()
|
||||
yield from eq.arm()
|
||||
await eq.process()
|
||||
await eq.arm()
|
||||
self.interrupt_running = False
|
||||
print("Device interrupt done")
|
||||
self.log.info("Interface interrupt done (interface %d)", self.index)
|
||||
|
||||
while self.interrupt_pending:
|
||||
self.interrupt_pending -= 1
|
||||
yield from self.interrupt()
|
||||
await self.interrupt()
|
||||
|
||||
async def process_tx_cq(self, cq_ring):
|
||||
self.log.info("Process TX CQ %d (interface %d)", cq_ring.ring_index, self.index)
|
||||
|
||||
def process_tx_cq(self, cq_ring):
|
||||
ring = self.tx_queues[cq_ring.ring_index]
|
||||
|
||||
if not self.port_up:
|
||||
return
|
||||
|
||||
# process completion queue
|
||||
yield from cq_ring.read_head_ptr()
|
||||
await cq_ring.read_head_ptr()
|
||||
|
||||
cq_tail_ptr = cq_ring.tail_ptr
|
||||
cq_index = cq_tail_ptr & cq_ring.size_mask
|
||||
@ -844,9 +875,9 @@ class Interface(object):
|
||||
cpl_data = struct.unpack_from("<HHHxxQ", cq_ring.buf, cq_index*cq_ring.stride)
|
||||
ring_index = cpl_data[1]
|
||||
|
||||
print(cpl_data)
|
||||
self.log.info("CPL data: %s", cpl_data)
|
||||
|
||||
print("Ring index %d" % ring_index)
|
||||
self.log.info("Ring index: %d", ring_index)
|
||||
|
||||
ring.free_desc(ring_index)
|
||||
|
||||
@ -854,10 +885,10 @@ class Interface(object):
|
||||
cq_index = cq_tail_ptr & cq_ring.size_mask
|
||||
|
||||
cq_ring.tail_ptr = cq_tail_ptr
|
||||
yield from cq_ring.write_tail_ptr()
|
||||
await cq_ring.write_tail_ptr()
|
||||
|
||||
# process ring
|
||||
yield from ring.read_tail_ptr()
|
||||
await ring.read_tail_ptr()
|
||||
|
||||
ring_clean_tail_ptr = ring.clean_tail_ptr
|
||||
ring_index = ring_clean_tail_ptr & ring.size_mask
|
||||
@ -871,14 +902,16 @@ class Interface(object):
|
||||
|
||||
ring.clean_tail_ptr = ring_clean_tail_ptr
|
||||
|
||||
def process_rx_cq(self, cq_ring):
|
||||
async def process_rx_cq(self, cq_ring):
|
||||
self.log.info("Process RX CQ %d (interface %d)", cq_ring.ring_index, self.index)
|
||||
|
||||
ring = self.rx_queues[cq_ring.ring_index]
|
||||
|
||||
if not self.port_up:
|
||||
return
|
||||
|
||||
# process completion queue
|
||||
yield from cq_ring.read_head_ptr()
|
||||
await cq_ring.read_head_ptr()
|
||||
|
||||
cq_tail_ptr = cq_ring.tail_ptr
|
||||
cq_index = cq_tail_ptr & cq_ring.size_mask
|
||||
@ -887,9 +920,9 @@ class Interface(object):
|
||||
cpl_data = struct.unpack_from("<HHHxxLHH", cq_ring.buf, cq_index*cq_ring.stride)
|
||||
ring_index = cpl_data[1]
|
||||
|
||||
print(cpl_data)
|
||||
self.log.info("CPL data: %s", cpl_data)
|
||||
|
||||
print("Ring index %d" % ring_index)
|
||||
self.log.info("Ring index: %d", ring_index)
|
||||
pkt = ring.rx_info[ring_index]
|
||||
|
||||
length = cpl_data[2]
|
||||
@ -900,10 +933,10 @@ class Interface(object):
|
||||
skb.timestamp_s = cpl_data[4]
|
||||
skb.rx_checksum = cpl_data[5]
|
||||
|
||||
print(skb)
|
||||
self.log.info("Packet: %s", skb)
|
||||
|
||||
self.pkt_rx_queue.append(skb)
|
||||
self.pkt_rx_sync.next = not self.pkt_rx_sync
|
||||
self.pkt_rx_sync.set()
|
||||
|
||||
ring.free_desc(ring_index)
|
||||
|
||||
@ -911,10 +944,10 @@ class Interface(object):
|
||||
cq_index = cq_tail_ptr & cq_ring.size_mask
|
||||
|
||||
cq_ring.tail_ptr = cq_tail_ptr
|
||||
yield from cq_ring.write_tail_ptr()
|
||||
await cq_ring.write_tail_ptr()
|
||||
|
||||
# process ring
|
||||
yield from ring.read_tail_ptr()
|
||||
await ring.read_tail_ptr()
|
||||
|
||||
ring_clean_tail_ptr = ring.clean_tail_ptr
|
||||
ring_index = ring_clean_tail_ptr & ring.size_mask
|
||||
@ -929,9 +962,9 @@ class Interface(object):
|
||||
ring.clean_tail_ptr = ring_clean_tail_ptr
|
||||
|
||||
# replenish buffers
|
||||
yield from ring.refill_buffers()
|
||||
await ring.refill_buffers()
|
||||
|
||||
def start_xmit(self, skb, tx_ring=None, csum_start=None, csum_offset=None):
|
||||
async def start_xmit(self, skb, tx_ring=None, csum_start=None, csum_offset=None):
|
||||
if not self.port_up:
|
||||
return
|
||||
|
||||
@ -940,10 +973,10 @@ class Interface(object):
|
||||
else:
|
||||
data = skb
|
||||
|
||||
data = data[:16384] # TODO
|
||||
ring_index = tx_ring # TODO!
|
||||
data = data[:16384] # TODO
|
||||
ring_index = tx_ring # TODO!
|
||||
|
||||
ring = self.tx_queues[ring_index];
|
||||
ring = self.tx_queues[ring_index]
|
||||
|
||||
tail_ptr = ring.tail_ptr
|
||||
|
||||
@ -969,34 +1002,39 @@ class Interface(object):
|
||||
offset = 0
|
||||
|
||||
# write descriptors
|
||||
l = min(length-offset, 42) if ring.desc_block_size > 1 else length-offset
|
||||
struct.pack_into("<HHLQ", ring.buf, index*ring.stride, 0, csum_cmd, l, ptr+offset if l else 0)
|
||||
offset += l
|
||||
seg = min(length-offset, 42) if ring.desc_block_size > 1 else length-offset
|
||||
struct.pack_into("<HHLQ", ring.buf, index*ring.stride, 0, csum_cmd, seg, ptr+offset if seg else 0)
|
||||
offset += seg
|
||||
for k in range(1, ring.desc_block_size):
|
||||
l = min(length-offset, 4096) if k < ring.desc_block_size-1 else length-offset
|
||||
struct.pack_into("<4xLQ", ring.buf, index*ring.stride+k*MQNIC_DESC_SIZE, l, ptr+offset if l else 0)
|
||||
offset += l
|
||||
seg = min(length-offset, 4096) if k < ring.desc_block_size-1 else length-offset
|
||||
struct.pack_into("<4xLQ", ring.buf, index*ring.stride+k*MQNIC_DESC_SIZE, seg, ptr+offset if seg else 0)
|
||||
offset += seg
|
||||
|
||||
ring.head_ptr += 1;
|
||||
ring.head_ptr += 1
|
||||
|
||||
yield from ring.write_head_ptr()
|
||||
await ring.write_head_ptr()
|
||||
|
||||
def set_mtu(self, mtu):
|
||||
async def set_mtu(self, mtu):
|
||||
for p in self.ports:
|
||||
yield from p.set_mtu(mtu)
|
||||
await p.set_mtu(mtu)
|
||||
|
||||
def recv(self):
|
||||
if self.pkt_rx_queue:
|
||||
return self.pkt_rx_queue.pop(0)
|
||||
return self.pkt_rx_queue.popleft()
|
||||
return None
|
||||
|
||||
def wait(self):
|
||||
yield self.pkt_rx_sync
|
||||
async def wait(self):
|
||||
if not self.pkt_rx_queue:
|
||||
self.pkt_rx_sync.clear()
|
||||
await self.pkt_rx_sync.wait()
|
||||
|
||||
|
||||
class Driver(object):
|
||||
def __init__(self, rc):
|
||||
self.rc = rc
|
||||
|
||||
self.log = SimLog("cocotb.mqnic")
|
||||
|
||||
self.dev_id = None
|
||||
self.rc_tree_ent = None
|
||||
self.hw_addr = None
|
||||
@ -1020,55 +1058,48 @@ class Driver(object):
|
||||
|
||||
self.pkt_buf_size = 16384
|
||||
self.allocated_packets = []
|
||||
self.free_packets = []
|
||||
self.free_packets = deque()
|
||||
|
||||
def init_dev(self, dev_id):
|
||||
async def init_dev(self, dev_id):
|
||||
assert not self.initialized
|
||||
self.initialized = True
|
||||
|
||||
self.dev_id = dev_id
|
||||
self.rc_tree_ent = self.rc.tree.find_dev(dev_id)
|
||||
self.hw_addr = self.rc_tree_ent.bar[0] & ~0xf
|
||||
self.rc_tree_ent = self.rc.tree.find_child_dev(dev_id)
|
||||
self.hw_addr = self.rc_tree_ent.bar_addr[0]
|
||||
|
||||
# Read ID registers
|
||||
self.fw_id = yield from self.rc.mem_read_dword(self.hw_addr+MQNIC_REG_FW_ID)
|
||||
print("FW ID: {:#010x}".format(self.fw_id))
|
||||
self.fw_ver = yield from self.rc.mem_read_dword(self.hw_addr+MQNIC_REG_FW_VER)
|
||||
print("FW version: {}.{}".format(self.fw_ver >> 16, self.fw_ver & 0xffff))
|
||||
self.board_id = yield from self.rc.mem_read_dword(self.hw_addr+MQNIC_REG_BOARD_ID)
|
||||
print("Board ID: {:#010x}".format(self.board_id))
|
||||
self.board_ver = yield from self.rc.mem_read_dword(self.hw_addr+MQNIC_REG_BOARD_VER)
|
||||
print("Board version: {}.{}".format(self.board_ver >> 16, self.board_ver & 0xffff))
|
||||
self.fw_id = await self.rc.mem_read_dword(self.hw_addr+MQNIC_REG_FW_ID)
|
||||
self.log.info("FW ID: 0x%08x", self.fw_id)
|
||||
self.fw_ver = await self.rc.mem_read_dword(self.hw_addr+MQNIC_REG_FW_VER)
|
||||
self.log.info("FW version: %d.%d", self.fw_ver >> 16, self.fw_ver & 0xffff)
|
||||
self.board_id = await self.rc.mem_read_dword(self.hw_addr+MQNIC_REG_BOARD_ID)
|
||||
self.log.info("Board ID: 0x%08x", self.board_id)
|
||||
self.board_ver = await self.rc.mem_read_dword(self.hw_addr+MQNIC_REG_BOARD_VER)
|
||||
self.log.info("Board version: %d.%d", self.board_ver >> 16, self.board_ver & 0xffff)
|
||||
|
||||
self.phc_count = yield from self.rc.mem_read_dword(self.hw_addr+MQNIC_REG_PHC_COUNT)
|
||||
print("PHC count: {}".format(self.phc_count))
|
||||
self.phc_offset = yield from self.rc.mem_read_dword(self.hw_addr+MQNIC_REG_PHC_OFFSET)
|
||||
print("PHC offset: {:#010x}".format(self.phc_offset))
|
||||
self.phc_count = await self.rc.mem_read_dword(self.hw_addr+MQNIC_REG_PHC_COUNT)
|
||||
self.log.info("PHC count: %d", self.phc_count)
|
||||
self.phc_offset = await self.rc.mem_read_dword(self.hw_addr+MQNIC_REG_PHC_OFFSET)
|
||||
self.log.info("PHC offset: 0x%08x", self.phc_offset)
|
||||
|
||||
self.if_count = yield from self.rc.mem_read_dword(self.hw_addr+MQNIC_REG_IF_COUNT)
|
||||
print("IF count: {}".format(self.if_count))
|
||||
self.if_stride = yield from self.rc.mem_read_dword(self.hw_addr+MQNIC_REG_IF_STRIDE)
|
||||
print("IF stride: {:#010x}".format(self.if_stride))
|
||||
self.if_csr_offset = yield from self.rc.mem_read_dword(self.hw_addr+MQNIC_REG_IF_CSR_OFFSET)
|
||||
print("IF CSR offset: {:#010x}".format(self.if_csr_offset))
|
||||
|
||||
# enable bus mastering
|
||||
val = yield from self.rc.config_read_word(self.dev_id, 0x04)
|
||||
yield from self.rc.config_write_word(self.dev_id, 0x04, val | 4)
|
||||
|
||||
# configure MSI
|
||||
yield from self.rc.configure_msi(self.dev_id)
|
||||
self.if_count = await self.rc.mem_read_dword(self.hw_addr+MQNIC_REG_IF_COUNT)
|
||||
self.log.info("IF count: %d", self.if_count)
|
||||
self.if_stride = await self.rc.mem_read_dword(self.hw_addr+MQNIC_REG_IF_STRIDE)
|
||||
self.log.info("IF stride: 0x%08x", self.if_stride)
|
||||
self.if_csr_offset = await self.rc.mem_read_dword(self.hw_addr+MQNIC_REG_IF_CSR_OFFSET)
|
||||
self.log.info("IF CSR offset: 0x%08x", self.if_csr_offset)
|
||||
|
||||
self.interfaces = []
|
||||
|
||||
for k in range(self.if_count):
|
||||
i = Interface(self, k, self.hw_addr+k*self.if_stride)
|
||||
yield from i.init()
|
||||
await i.init()
|
||||
self.interfaces.append(i)
|
||||
|
||||
def alloc_pkt(self):
|
||||
if self.free_packets:
|
||||
return self.free_packets.pop()
|
||||
return self.free_packets.popleft()
|
||||
|
||||
pkt = self.rc.alloc_region(self.pkt_buf_size)
|
||||
self.allocated_packets.append(pkt)
|
||||
@ -1078,5 +1109,3 @@ class Driver(object):
|
||||
assert pkt is not None
|
||||
assert pkt in self.allocated_packets
|
||||
self.free_packets.append(pkt)
|
||||
|
||||
|
||||
|
@ -1 +0,0 @@
|
||||
../lib/pcie/tb/pcie.py
|
@ -1 +0,0 @@
|
||||
../lib/pcie/tb/pcie_us.py
|
@ -1 +0,0 @@
|
||||
../lib/pcie/tb/pcie_usp.py
|
@ -1 +0,0 @@
|
||||
../lib/eth/tb/ptp.py
|
120
fpga/common/tb/queue_manager/Makefile
Normal file
120
fpga/common/tb/queue_manager/Makefile
Normal file
@ -0,0 +1,120 @@
|
||||
# Copyright 2020, The Regents of the University of California.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
#
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
|
||||
# IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
|
||||
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
# OF SUCH DAMAGE.
|
||||
#
|
||||
# The views and conclusions contained in the software and documentation are those
|
||||
# of the authors and should not be interpreted as representing official policies,
|
||||
# either expressed or implied, of The Regents of the University of California.
|
||||
|
||||
TOPLEVEL_LANG = verilog
|
||||
|
||||
SIM ?= icarus
|
||||
WAVES ?= 0
|
||||
|
||||
COCOTB_HDL_TIMEUNIT = 1ns
|
||||
COCOTB_HDL_TIMEPRECISION = 1ps
|
||||
|
||||
DUT = queue_manager
|
||||
TOPLEVEL = $(DUT)
|
||||
MODULE = test_$(DUT)
|
||||
VERILOG_SOURCES += ../../rtl/$(DUT).v
|
||||
|
||||
# module parameters
|
||||
export PARAM_ADDR_WIDTH = 64
|
||||
export PARAM_REQ_TAG_WIDTH = 8
|
||||
export PARAM_OP_TABLE_SIZE = 16
|
||||
export PARAM_OP_TAG_WIDTH = 8
|
||||
export PARAM_QUEUE_INDEX_WIDTH = 8
|
||||
export PARAM_CPL_INDEX_WIDTH = 8
|
||||
export PARAM_QUEUE_PTR_WIDTH = 16
|
||||
export PARAM_LOG_QUEUE_SIZE_WIDTH = 4
|
||||
export PARAM_DESC_SIZE = 16
|
||||
export PARAM_LOG_BLOCK_SIZE_WIDTH = 2
|
||||
export PARAM_PIPELINE = 2
|
||||
export PARAM_AXIL_DATA_WIDTH = 32
|
||||
export PARAM_AXIL_ADDR_WIDTH = 16
|
||||
export PARAM_AXIL_STRB_WIDTH = $(shell expr $(PARAM_AXIL_DATA_WIDTH) / 8 )
|
||||
|
||||
SIM_BUILD ?= sim_build_$(MODULE)
|
||||
|
||||
ifeq ($(SIM), icarus)
|
||||
PLUSARGS += -fst
|
||||
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).ADDR_WIDTH=$(PARAM_ADDR_WIDTH)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).REQ_TAG_WIDTH=$(PARAM_REQ_TAG_WIDTH)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).OP_TABLE_SIZE=$(PARAM_OP_TABLE_SIZE)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).OP_TAG_WIDTH=$(PARAM_OP_TAG_WIDTH)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).QUEUE_INDEX_WIDTH=$(PARAM_QUEUE_INDEX_WIDTH)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).CPL_INDEX_WIDTH=$(PARAM_CPL_INDEX_WIDTH)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).QUEUE_PTR_WIDTH=$(PARAM_QUEUE_PTR_WIDTH)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).LOG_QUEUE_SIZE_WIDTH=$(PARAM_LOG_QUEUE_SIZE_WIDTH)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).DESC_SIZE=$(PARAM_DESC_SIZE)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).LOG_BLOCK_SIZE_WIDTH=$(PARAM_LOG_BLOCK_SIZE_WIDTH)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).PIPELINE=$(PARAM_PIPELINE)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).AXIL_DATA_WIDTH=$(PARAM_AXIL_DATA_WIDTH)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).AXIL_ADDR_WIDTH=$(PARAM_AXIL_ADDR_WIDTH)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).AXIL_STRB_WIDTH=$(PARAM_AXIL_STRB_WIDTH)
|
||||
|
||||
ifeq ($(WAVES), 1)
|
||||
VERILOG_SOURCES += iverilog_dump.v
|
||||
COMPILE_ARGS += -s iverilog_dump
|
||||
endif
|
||||
else ifeq ($(SIM), verilator)
|
||||
COMPILE_ARGS += -Wno-SELRANGE -Wno-WIDTH
|
||||
|
||||
COMPILE_ARGS += -GADDR_WIDTH=$(PARAM_ADDR_WIDTH)
|
||||
COMPILE_ARGS += -GREQ_TAG_WIDTH=$(PARAM_REQ_TAG_WIDTH)
|
||||
COMPILE_ARGS += -GOP_TABLE_SIZE=$(PARAM_OP_TABLE_SIZE)
|
||||
COMPILE_ARGS += -GOP_TAG_WIDTH=$(PARAM_OP_TAG_WIDTH)
|
||||
COMPILE_ARGS += -GQUEUE_INDEX_WIDTH=$(PARAM_QUEUE_INDEX_WIDTH)
|
||||
COMPILE_ARGS += -GCPL_INDEX_WIDTH=$(PARAM_CPL_INDEX_WIDTH)
|
||||
COMPILE_ARGS += -GQUEUE_PTR_WIDTH=$(PARAM_QUEUE_PTR_WIDTH)
|
||||
COMPILE_ARGS += -GLOG_QUEUE_SIZE_WIDTH=$(PARAM_LOG_QUEUE_SIZE_WIDTH)
|
||||
COMPILE_ARGS += -GDESC_SIZE=$(PARAM_DESC_SIZE)
|
||||
COMPILE_ARGS += -GLOG_BLOCK_SIZE_WIDTH=$(PARAM_LOG_BLOCK_SIZE_WIDTH)
|
||||
COMPILE_ARGS += -GPIPELINE=$(PARAM_PIPELINE)
|
||||
COMPILE_ARGS += -GAXIL_DATA_WIDTH=$(PARAM_AXIL_DATA_WIDTH)
|
||||
COMPILE_ARGS += -GAXIL_ADDR_WIDTH=$(PARAM_AXIL_ADDR_WIDTH)
|
||||
COMPILE_ARGS += -GAXIL_STRB_WIDTH=$(PARAM_AXIL_STRB_WIDTH)
|
||||
|
||||
ifeq ($(WAVES), 1)
|
||||
COMPILE_ARGS += --trace-fst
|
||||
endif
|
||||
endif
|
||||
|
||||
iverilog_dump.v:
|
||||
echo 'module iverilog_dump();' > $@
|
||||
echo 'initial begin' >> $@
|
||||
echo ' $$dumpfile("$(TOPLEVEL).fst");' >> $@
|
||||
echo ' $$dumpvars(0, $(TOPLEVEL));' >> $@
|
||||
echo 'end' >> $@
|
||||
echo 'endmodule' >> $@
|
||||
|
||||
clean::
|
||||
@rm -rf sim_build_*
|
||||
@rm -rf iverilog_dump.v
|
||||
@rm -rf dump.fst $(TOPLEVEL).fst
|
||||
|
||||
include $(shell cocotb-config --makefiles)/Makefile.sim
|
||||
|
338
fpga/common/tb/queue_manager/test_queue_manager.py
Normal file
338
fpga/common/tb/queue_manager/test_queue_manager.py
Normal file
@ -0,0 +1,338 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
|
||||
Copyright 2020, The Regents of the University of California.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
|
||||
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of The Regents of the University of California.
|
||||
|
||||
"""
|
||||
|
||||
import logging
|
||||
import os
|
||||
import random
|
||||
|
||||
import cocotb_test.simulator
|
||||
|
||||
import cocotb
|
||||
from cocotb.clock import Clock
|
||||
from cocotb.triggers import RisingEdge, Timer
|
||||
from cocotb.regression import TestFactory
|
||||
|
||||
from cocotbext.axi import AxiLiteMaster
|
||||
from cocotbext.axi.stream import define_stream
|
||||
|
||||
|
||||
DequeueReqTransaction, DequeueReqSource, DequeueReqSink, DequeueReqMonitor = define_stream("DequeueReq",
|
||||
signals=["queue", "tag", "valid"],
|
||||
optional_signals=["ready"]
|
||||
)
|
||||
|
||||
DequeueRespTransaction, DequeueRespSource, DequeueRespSink, DequeueRespMonitor = define_stream("DequeueResp",
|
||||
signals=["queue", "ptr", "addr", "block_size", "cpl", "tag", "op_tag", "empty", "error", "valid"],
|
||||
optional_signals=["ready"]
|
||||
)
|
||||
|
||||
DequeueCommitTransaction, DequeueCommitSource, DequeueCommitSink, DequeueCommitMonitor = define_stream("DequeueCommit",
|
||||
signals=["op_tag", "valid"],
|
||||
optional_signals=["ready"]
|
||||
)
|
||||
|
||||
DoorbellTransaction, DoorbellSource, DoorbellSink, DoorbellMonitor = define_stream("Doorbell",
|
||||
signals=["queue", "valid"],
|
||||
optional_signals=["ready"]
|
||||
)
|
||||
|
||||
|
||||
class TB(object):
|
||||
def __init__(self, dut):
|
||||
self.dut = dut
|
||||
|
||||
self.log = logging.getLogger("cocotb.tb")
|
||||
self.log.setLevel(logging.DEBUG)
|
||||
|
||||
cocotb.fork(Clock(dut.clk, 4, units="ns").start())
|
||||
|
||||
self.axil_master = AxiLiteMaster(dut, "s_axil", dut.clk, dut.rst)
|
||||
|
||||
self.dequeue_req_source = DequeueReqSource(dut, "s_axis_dequeue_req", dut.clk, dut.rst)
|
||||
self.dequeue_resp_sink = DequeueRespSink(dut, "m_axis_dequeue_resp", dut.clk, dut.rst)
|
||||
self.dequeue_commit_source = DequeueCommitSource(dut, "s_axis_dequeue_commit", dut.clk, dut.rst)
|
||||
self.doorbell_sink = DoorbellSink(dut, "m_axis_doorbell", dut.clk, dut.rst)
|
||||
|
||||
dut.enable.setimmediatevalue(0)
|
||||
|
||||
def set_idle_generator(self, generator=None):
|
||||
if generator:
|
||||
self.source.set_pause_generator(generator())
|
||||
|
||||
def set_backpressure_generator(self, generator=None):
|
||||
if generator:
|
||||
self.sink.set_pause_generator(generator())
|
||||
|
||||
async def reset(self):
|
||||
self.dut.rst.setimmediatevalue(0)
|
||||
await RisingEdge(self.dut.clk)
|
||||
await RisingEdge(self.dut.clk)
|
||||
self.dut.rst <= 1
|
||||
await RisingEdge(self.dut.clk)
|
||||
await RisingEdge(self.dut.clk)
|
||||
self.dut.rst <= 0
|
||||
await RisingEdge(self.dut.clk)
|
||||
await RisingEdge(self.dut.clk)
|
||||
|
||||
|
||||
async def run_test(dut):
|
||||
|
||||
OP_TABLE_SIZE = int(os.getenv("PARAM_OP_TABLE_SIZE"))
|
||||
|
||||
tb = TB(dut)
|
||||
|
||||
await tb.reset()
|
||||
|
||||
dut.enable <= 1
|
||||
|
||||
tb.log.info("Test read and write queue configuration registers")
|
||||
|
||||
await tb.axil_master.write_qword(0*32+0, 0x8877665544332211) # address
|
||||
await tb.axil_master.write_dword(0*32+8, 0x00000004) # active, log size
|
||||
await tb.axil_master.write_dword(0*32+12, 0x00000001) # completion queue index
|
||||
await tb.axil_master.write_dword(0*32+16, 0x00000000) # head pointer
|
||||
await tb.axil_master.write_dword(0*32+24, 0x00000000) # tail pointer
|
||||
await tb.axil_master.write_dword(0*32+8, 0x80000004) # active, log size
|
||||
|
||||
assert await tb.axil_master.read_qword(0*32+0) == 0x8877665544332211
|
||||
assert await tb.axil_master.read_dword(0*32+8) == 0x80000004
|
||||
assert await tb.axil_master.read_dword(0*32+12) == 0x00000001
|
||||
|
||||
tb.log.info("Test enqueue and dequeue")
|
||||
|
||||
# increment head pointer
|
||||
head_ptr = await tb.axil_master.read_dword(0*32+16) # head pointer
|
||||
head_ptr += 1
|
||||
tb.log.info("Head pointer: %d", head_ptr)
|
||||
await tb.axil_master.write_dword(0*32+16, head_ptr) # head pointer
|
||||
|
||||
# check for doorbell
|
||||
await tb.doorbell_sink.wait()
|
||||
db = tb.doorbell_sink.recv()
|
||||
tb.log.info("Doorbell: %s", db)
|
||||
|
||||
assert db.queue == 0
|
||||
|
||||
# read tail pointer
|
||||
tail_ptr = await tb.axil_master.read_dword(0*32+24) # tail pointer
|
||||
tb.log.info("Tail pointer: %d", tail_ptr)
|
||||
|
||||
# dequeue request
|
||||
tb.dequeue_req_source.send(DequeueReqTransaction(queue=0, tag=1))
|
||||
|
||||
await tb.dequeue_resp_sink.wait()
|
||||
resp = tb.dequeue_resp_sink.recv()
|
||||
|
||||
tb.log.info("Dequeue response: %s", resp)
|
||||
|
||||
assert resp.queue == 0
|
||||
assert resp.ptr == tail_ptr
|
||||
assert resp.addr == 0x8877665544332211
|
||||
assert resp.block_size == 0
|
||||
assert resp.cpl == 1
|
||||
assert resp.tag == 1
|
||||
assert not resp.empty
|
||||
assert not resp.error
|
||||
|
||||
# dequeue commit
|
||||
tb.dequeue_commit_source.send(DequeueCommitTransaction(op_tag=resp.op_tag))
|
||||
|
||||
await Timer(100, 'ns')
|
||||
|
||||
# read tail pointer
|
||||
new_tail_ptr = await tb.axil_master.read_dword(0*32+24) # tail pointer
|
||||
tb.log.info("Tail pointer: %d", new_tail_ptr)
|
||||
|
||||
assert new_tail_ptr - tail_ptr == 1
|
||||
|
||||
tb.log.info("Test multiple enqueue and dequeue")
|
||||
|
||||
for k in range(4):
|
||||
await tb.axil_master.write_dword(k*32+8, 0x00000004) # active, log size
|
||||
await tb.axil_master.write_qword(k*32+0, 0x5555555555000000 + 0x10000*k) # address
|
||||
await tb.axil_master.write_dword(k*32+8, 0x00000004) # active, log size
|
||||
await tb.axil_master.write_dword(k*32+12, 0x00000000 + k) # completion queue index
|
||||
await tb.axil_master.write_dword(k*32+16, 0x0000fff0) # head pointer
|
||||
await tb.axil_master.write_dword(k*32+24, 0x0000fff0) # tail pointer
|
||||
await tb.axil_master.write_dword(k*32+8, 0x80000004) # active, log size
|
||||
|
||||
current_tag = 1
|
||||
|
||||
queue_head_ptr = [0xfff0]*4
|
||||
queue_tail_ptr = [0xfff0]*4
|
||||
queue_depth = [0]*4
|
||||
queue_uncommit_depth = [0]*4
|
||||
|
||||
commit_list = []
|
||||
|
||||
random.seed(123456)
|
||||
|
||||
for i in range(50):
|
||||
# enqueue
|
||||
for k in range(random.randrange(8)):
|
||||
q = random.randrange(4)
|
||||
|
||||
if queue_depth[q] < 16:
|
||||
tb.log.info("Enqueue into queue %d", q)
|
||||
|
||||
# increment head pointer
|
||||
head_ptr = await tb.axil_master.read_dword(q*32+16) # head pointer
|
||||
|
||||
assert head_ptr == queue_head_ptr[q]
|
||||
|
||||
head_ptr = (head_ptr + 1) & 0xffff
|
||||
|
||||
queue_head_ptr[q] = head_ptr
|
||||
queue_depth[q] += 1
|
||||
queue_uncommit_depth[q] += 1
|
||||
|
||||
tb.log.info("Head pointer: %d", head_ptr)
|
||||
await tb.axil_master.write_dword(q*32+16, head_ptr) # head pointer
|
||||
|
||||
# check doorbell event
|
||||
await tb.doorbell_sink.wait()
|
||||
db = tb.doorbell_sink.recv()
|
||||
tb.log.info("Doorbell: %s", db)
|
||||
|
||||
assert db.queue == q
|
||||
|
||||
# dequeue
|
||||
for k in range(random.randrange(8)):
|
||||
q = random.randrange(4)
|
||||
|
||||
if len(commit_list) < OP_TABLE_SIZE:
|
||||
tb.log.info("Try dequeue from queue %d", q)
|
||||
|
||||
# dequeue request
|
||||
tb.dequeue_req_source.send(DequeueReqTransaction(queue=q, tag=current_tag))
|
||||
|
||||
await tb.dequeue_resp_sink.wait()
|
||||
resp = tb.dequeue_resp_sink.recv()
|
||||
|
||||
tb.log.info("Dequeue response: %s", resp)
|
||||
|
||||
assert resp.queue == q
|
||||
assert resp.ptr == queue_tail_ptr[q]
|
||||
assert (resp.addr >> 16) & 0xf == q
|
||||
assert (resp.addr >> 4) & 0xf == queue_tail_ptr[q] & 0xf
|
||||
assert resp.block_size == 0
|
||||
assert resp.cpl == q
|
||||
assert resp.tag == current_tag
|
||||
assert not resp.error
|
||||
|
||||
if queue_uncommit_depth[q]:
|
||||
commit_list.append((q, resp.op_tag))
|
||||
queue_tail_ptr[q] = (queue_tail_ptr[q] + 1) & 0xffff
|
||||
queue_uncommit_depth[q] -= 1
|
||||
assert not resp.empty
|
||||
else:
|
||||
tb.log.info("Queue was empty")
|
||||
assert resp.empty
|
||||
|
||||
current_tag = (current_tag + 1) % 256
|
||||
|
||||
# commit
|
||||
#random.shuffle(commit_list)
|
||||
for k in range(random.randrange(8)):
|
||||
if commit_list:
|
||||
q, t = commit_list.pop(0)
|
||||
|
||||
tb.log.info("Commit dequeue from queue %d", q)
|
||||
|
||||
# dequeue commit
|
||||
tb.dequeue_commit_source.send(DequeueCommitTransaction(op_tag=t))
|
||||
|
||||
queue_depth[q] -= 1
|
||||
|
||||
await RisingEdge(dut.clk)
|
||||
await RisingEdge(dut.clk)
|
||||
|
||||
|
||||
if cocotb.SIM_NAME:
|
||||
|
||||
factory = TestFactory(run_test)
|
||||
factory.generate_tests()
|
||||
|
||||
|
||||
# cocotb-test
|
||||
|
||||
tests_dir = os.path.dirname(__file__)
|
||||
rtl_dir = os.path.abspath(os.path.join(tests_dir, '..', '..', 'rtl'))
|
||||
lib_dir = os.path.abspath(os.path.join(rtl_dir, '..', 'lib'))
|
||||
axi_rtl_dir = os.path.abspath(os.path.join(lib_dir, 'axi', 'rtl'))
|
||||
axis_rtl_dir = os.path.abspath(os.path.join(lib_dir, 'axis', 'rtl'))
|
||||
eth_rtl_dir = os.path.abspath(os.path.join(lib_dir, 'eth', 'rtl'))
|
||||
pcie_rtl_dir = os.path.abspath(os.path.join(lib_dir, 'pcie', 'rtl'))
|
||||
|
||||
|
||||
def test_queue_manager(request):
|
||||
dut = "queue_manager"
|
||||
module = os.path.splitext(os.path.basename(__file__))[0]
|
||||
toplevel = dut
|
||||
|
||||
verilog_sources = [
|
||||
os.path.join(rtl_dir, f"{dut}.v"),
|
||||
]
|
||||
|
||||
parameters = {}
|
||||
|
||||
parameters['ADDR_WIDTH'] = 64
|
||||
parameters['REQ_TAG_WIDTH'] = 8
|
||||
parameters['OP_TABLE_SIZE'] = 16
|
||||
parameters['OP_TAG_WIDTH'] = 8
|
||||
parameters['QUEUE_INDEX_WIDTH'] = 8
|
||||
parameters['CPL_INDEX_WIDTH'] = 8
|
||||
parameters['QUEUE_PTR_WIDTH'] = 16
|
||||
parameters['LOG_QUEUE_SIZE_WIDTH'] = 4
|
||||
parameters['DESC_SIZE'] = 16
|
||||
parameters['LOG_BLOCK_SIZE_WIDTH'] = 2
|
||||
parameters['PIPELINE'] = 2
|
||||
parameters['AXIL_DATA_WIDTH'] = 32
|
||||
parameters['AXIL_ADDR_WIDTH'] = 16
|
||||
parameters['AXIL_STRB_WIDTH'] = parameters['AXIL_DATA_WIDTH'] // 8
|
||||
|
||||
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(
|
||||
python_search=[tests_dir],
|
||||
verilog_sources=verilog_sources,
|
||||
toplevel=toplevel,
|
||||
module=module,
|
||||
parameters=parameters,
|
||||
sim_build=sim_build,
|
||||
extra_env=extra_env,
|
||||
)
|
84
fpga/common/tb/rx_checksum/Makefile
Normal file
84
fpga/common/tb/rx_checksum/Makefile
Normal file
@ -0,0 +1,84 @@
|
||||
# Copyright 2020, The Regents of the University of California.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
#
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
|
||||
# IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
|
||||
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
# OF SUCH DAMAGE.
|
||||
#
|
||||
# The views and conclusions contained in the software and documentation are those
|
||||
# of the authors and should not be interpreted as representing official policies,
|
||||
# either expressed or implied, of The Regents of the University of California.
|
||||
|
||||
TOPLEVEL_LANG = verilog
|
||||
|
||||
SIM ?= icarus
|
||||
WAVES ?= 0
|
||||
|
||||
COCOTB_HDL_TIMEUNIT = 1ns
|
||||
COCOTB_HDL_TIMEPRECISION = 1ps
|
||||
|
||||
DUT = rx_checksum
|
||||
TOPLEVEL = $(DUT)
|
||||
MODULE = test_$(DUT)
|
||||
VERILOG_SOURCES += ../../rtl/$(DUT).v
|
||||
|
||||
# module parameters
|
||||
export PARAM_DATA_WIDTH ?= 64
|
||||
export PARAM_KEEP_WIDTH ?= $(shell expr $(PARAM_DATA_WIDTH) / 8 )
|
||||
|
||||
SIM_BUILD ?= sim_build_$(MODULE)-$(PARAM_DATA_WIDTH)
|
||||
|
||||
ifeq ($(SIM), icarus)
|
||||
PLUSARGS += -fst
|
||||
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).DATA_WIDTH=$(PARAM_DATA_WIDTH)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).KEEP_WIDTH=$(PARAM_KEEP_WIDTH)
|
||||
|
||||
ifeq ($(WAVES), 1)
|
||||
VERILOG_SOURCES += iverilog_dump.v
|
||||
COMPILE_ARGS += -s iverilog_dump
|
||||
endif
|
||||
else ifeq ($(SIM), verilator)
|
||||
COMPILE_ARGS += -Wno-SELRANGE -Wno-WIDTH
|
||||
|
||||
COMPILE_ARGS += -GDATA_WIDTH=$(PARAM_DATA_WIDTH)
|
||||
COMPILE_ARGS += -GKEEP_WIDTH=$(PARAM_KEEP_WIDTH)
|
||||
|
||||
ifeq ($(WAVES), 1)
|
||||
COMPILE_ARGS += --trace-fst
|
||||
endif
|
||||
endif
|
||||
|
||||
iverilog_dump.v:
|
||||
echo 'module iverilog_dump();' > $@
|
||||
echo 'initial begin' >> $@
|
||||
echo ' $$dumpfile("$(TOPLEVEL).fst");' >> $@
|
||||
echo ' $$dumpvars(0, $(TOPLEVEL));' >> $@
|
||||
echo 'end' >> $@
|
||||
echo 'endmodule' >> $@
|
||||
|
||||
clean::
|
||||
@rm -rf sim_build_*
|
||||
@rm -rf iverilog_dump.v
|
||||
@rm -rf dump.fst $(TOPLEVEL).fst
|
||||
|
||||
include $(shell cocotb-config --makefiles)/Makefile.sim
|
||||
|
201
fpga/common/tb/rx_checksum/test_rx_checksum.py
Normal file
201
fpga/common/tb/rx_checksum/test_rx_checksum.py
Normal file
@ -0,0 +1,201 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
|
||||
Copyright 2020, The Regents of the University of California.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
|
||||
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of The Regents of the University of California.
|
||||
|
||||
"""
|
||||
|
||||
import itertools
|
||||
import logging
|
||||
import os
|
||||
|
||||
import scapy.utils
|
||||
from scapy.layers.l2 import Ether
|
||||
from scapy.layers.inet import IP, UDP, TCP
|
||||
|
||||
import cocotb_test.simulator
|
||||
import pytest
|
||||
|
||||
import cocotb
|
||||
from cocotb.clock import Clock
|
||||
from cocotb.triggers import RisingEdge
|
||||
from cocotb.regression import TestFactory
|
||||
|
||||
from cocotbext.axi import AxiStreamFrame, AxiStreamSource
|
||||
from cocotbext.axi.stream import define_stream
|
||||
|
||||
|
||||
CsumTransaction, CsumSource, CsumSink, CsumMonitor = define_stream("Csum",
|
||||
signals=["csum", "csum_valid"]
|
||||
)
|
||||
|
||||
|
||||
class TB(object):
|
||||
def __init__(self, dut):
|
||||
self.dut = dut
|
||||
|
||||
self.log = logging.getLogger("cocotb.tb")
|
||||
self.log.setLevel(logging.DEBUG)
|
||||
|
||||
cocotb.fork(Clock(dut.clk, 4, units="ns").start())
|
||||
|
||||
self.source = AxiStreamSource(dut, "s_axis", dut.clk, dut.rst)
|
||||
self.sink = CsumSink(dut, "m_axis", dut.clk, dut.rst)
|
||||
|
||||
def set_idle_generator(self, generator=None):
|
||||
if generator:
|
||||
self.source.set_pause_generator(generator())
|
||||
|
||||
async def reset(self):
|
||||
self.dut.rst.setimmediatevalue(0)
|
||||
await RisingEdge(self.dut.clk)
|
||||
await RisingEdge(self.dut.clk)
|
||||
self.dut.rst <= 1
|
||||
await RisingEdge(self.dut.clk)
|
||||
await RisingEdge(self.dut.clk)
|
||||
self.dut.rst <= 0
|
||||
await RisingEdge(self.dut.clk)
|
||||
await RisingEdge(self.dut.clk)
|
||||
|
||||
|
||||
async def run_test(dut, payload_lengths=None, payload_data=None, idle_inserter=None, pkt_type=Ether):
|
||||
|
||||
tb = TB(dut)
|
||||
|
||||
await tb.reset()
|
||||
|
||||
tb.set_idle_generator(idle_inserter)
|
||||
|
||||
test_pkts = []
|
||||
test_frames = []
|
||||
|
||||
ip_id = 0
|
||||
|
||||
for payload in [payload_data(x) for x in payload_lengths()]:
|
||||
eth = Ether(src='5A:51:52:53:54:55', dst='DA:D1:D2:D3:D4:D5')
|
||||
if pkt_type == Ether:
|
||||
test_pkt = eth / payload
|
||||
else:
|
||||
ip = IP(src=f'10.1.0.{ip_id}', dst=f'10.2.0.{ip_id}', id=ip_id)
|
||||
if pkt_type == IP:
|
||||
test_pkt = eth / ip / payload
|
||||
elif pkt_type == UDP:
|
||||
udp = UDP(sport=ip_id, dport=0x1000+ip_id)
|
||||
test_pkt = eth / ip / udp / payload
|
||||
elif pkt_type == TCP:
|
||||
tcp = TCP(sport=ip_id, dport=0x1000+ip_id)
|
||||
test_pkt = eth / ip / tcp / payload
|
||||
|
||||
test_pkts.append(test_pkt)
|
||||
|
||||
test_frame = AxiStreamFrame(test_pkt.build())
|
||||
test_frames.append(test_frame)
|
||||
tb.source.send(test_frame)
|
||||
|
||||
ip_id = (ip_id + 1) & 0xffff
|
||||
|
||||
for test_pkt, test_frame in zip(test_pkts, test_frames):
|
||||
await tb.sink.wait()
|
||||
rx_csum = tb.sink.recv()
|
||||
|
||||
csum = ~scapy.utils.checksum(bytes(test_pkt.payload)) & 0xffff
|
||||
|
||||
tb.log.info("Output checksum: 0x%04x (expected 0x%04x)", rx_csum.csum.integer, csum)
|
||||
|
||||
assert rx_csum.csum == csum
|
||||
|
||||
assert tb.sink.empty()
|
||||
|
||||
await RisingEdge(dut.clk)
|
||||
await RisingEdge(dut.clk)
|
||||
|
||||
|
||||
def cycle_pause():
|
||||
return itertools.cycle([1, 1, 1, 0])
|
||||
|
||||
|
||||
def size_list():
|
||||
return list(range(1, 128)) + [512, 1500, 9200] + [46]*10
|
||||
|
||||
|
||||
def incrementing_payload(length):
|
||||
return bytes(itertools.islice(itertools.cycle(range(256)), length))
|
||||
|
||||
|
||||
if cocotb.SIM_NAME:
|
||||
|
||||
factory = TestFactory(run_test)
|
||||
factory.add_option("pkt_type", [Ether, IP, UDP, TCP])
|
||||
factory.add_option("payload_lengths", [size_list])
|
||||
factory.add_option("payload_data", [incrementing_payload])
|
||||
factory.add_option("idle_inserter", [None, cycle_pause])
|
||||
factory.generate_tests()
|
||||
|
||||
|
||||
# cocotb-test
|
||||
|
||||
tests_dir = os.path.dirname(__file__)
|
||||
rtl_dir = os.path.abspath(os.path.join(tests_dir, '..', '..', 'rtl'))
|
||||
lib_dir = os.path.abspath(os.path.join(rtl_dir, '..', 'lib'))
|
||||
axi_rtl_dir = os.path.abspath(os.path.join(lib_dir, 'axi', 'rtl'))
|
||||
axis_rtl_dir = os.path.abspath(os.path.join(lib_dir, 'axis', 'rtl'))
|
||||
eth_rtl_dir = os.path.abspath(os.path.join(lib_dir, 'eth', 'rtl'))
|
||||
pcie_rtl_dir = os.path.abspath(os.path.join(lib_dir, 'pcie', 'rtl'))
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data_width", [64, 256])
|
||||
def test_rx_checksum(request, data_width):
|
||||
dut = "rx_checksum"
|
||||
module = os.path.splitext(os.path.basename(__file__))[0]
|
||||
toplevel = dut
|
||||
|
||||
verilog_sources = [
|
||||
os.path.join(rtl_dir, f"{dut}.v"),
|
||||
]
|
||||
|
||||
parameters = {}
|
||||
|
||||
parameters['DATA_WIDTH'] = data_width
|
||||
parameters['KEEP_WIDTH'] = parameters['DATA_WIDTH'] // 8
|
||||
|
||||
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(
|
||||
python_search=[tests_dir],
|
||||
verilog_sources=verilog_sources,
|
||||
toplevel=toplevel,
|
||||
module=module,
|
||||
parameters=parameters,
|
||||
sim_build=sim_build,
|
||||
extra_env=extra_env,
|
||||
)
|
84
fpga/common/tb/rx_hash/Makefile
Normal file
84
fpga/common/tb/rx_hash/Makefile
Normal file
@ -0,0 +1,84 @@
|
||||
# Copyright 2020, The Regents of the University of California.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
#
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
|
||||
# IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
|
||||
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
# OF SUCH DAMAGE.
|
||||
#
|
||||
# The views and conclusions contained in the software and documentation are those
|
||||
# of the authors and should not be interpreted as representing official policies,
|
||||
# either expressed or implied, of The Regents of the University of California.
|
||||
|
||||
TOPLEVEL_LANG = verilog
|
||||
|
||||
SIM ?= icarus
|
||||
WAVES ?= 0
|
||||
|
||||
COCOTB_HDL_TIMEUNIT = 1ns
|
||||
COCOTB_HDL_TIMEPRECISION = 1ps
|
||||
|
||||
DUT = rx_hash
|
||||
TOPLEVEL = $(DUT)
|
||||
MODULE = test_$(DUT)
|
||||
VERILOG_SOURCES += ../../rtl/$(DUT).v
|
||||
|
||||
# module parameters
|
||||
export PARAM_DATA_WIDTH ?= 64
|
||||
export PARAM_KEEP_WIDTH ?= $(shell expr $(PARAM_DATA_WIDTH) / 8 )
|
||||
|
||||
SIM_BUILD ?= sim_build_$(MODULE)-$(PARAM_DATA_WIDTH)
|
||||
|
||||
ifeq ($(SIM), icarus)
|
||||
PLUSARGS += -fst
|
||||
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).DATA_WIDTH=$(PARAM_DATA_WIDTH)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).KEEP_WIDTH=$(PARAM_KEEP_WIDTH)
|
||||
|
||||
ifeq ($(WAVES), 1)
|
||||
VERILOG_SOURCES += iverilog_dump.v
|
||||
COMPILE_ARGS += -s iverilog_dump
|
||||
endif
|
||||
else ifeq ($(SIM), verilator)
|
||||
COMPILE_ARGS += -Wno-SELRANGE -Wno-WIDTH
|
||||
|
||||
COMPILE_ARGS += -GDATA_WIDTH=$(PARAM_DATA_WIDTH)
|
||||
COMPILE_ARGS += -GKEEP_WIDTH=$(PARAM_KEEP_WIDTH)
|
||||
|
||||
ifeq ($(WAVES), 1)
|
||||
COMPILE_ARGS += --trace-fst
|
||||
endif
|
||||
endif
|
||||
|
||||
iverilog_dump.v:
|
||||
echo 'module iverilog_dump();' > $@
|
||||
echo 'initial begin' >> $@
|
||||
echo ' $$dumpfile("$(TOPLEVEL).fst");' >> $@
|
||||
echo ' $$dumpvars(0, $(TOPLEVEL));' >> $@
|
||||
echo 'end' >> $@
|
||||
echo 'endmodule' >> $@
|
||||
|
||||
clean::
|
||||
@rm -rf sim_build_*
|
||||
@rm -rf iverilog_dump.v
|
||||
@rm -rf dump.fst $(TOPLEVEL).fst
|
||||
|
||||
include $(shell cocotb-config --makefiles)/Makefile.sim
|
||||
|
265
fpga/common/tb/rx_hash/test_rx_hash.py
Normal file
265
fpga/common/tb/rx_hash/test_rx_hash.py
Normal file
@ -0,0 +1,265 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
|
||||
Copyright 2020, The Regents of the University of California.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
|
||||
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of The Regents of the University of California.
|
||||
|
||||
"""
|
||||
|
||||
import enum
|
||||
import ipaddress
|
||||
import itertools
|
||||
import logging
|
||||
import os
|
||||
|
||||
from scapy.layers.l2 import Ether
|
||||
from scapy.layers.inet import IP, UDP, TCP
|
||||
|
||||
import cocotb_test.simulator
|
||||
import pytest
|
||||
|
||||
import cocotb
|
||||
from cocotb.clock import Clock
|
||||
from cocotb.triggers import RisingEdge
|
||||
from cocotb.regression import TestFactory
|
||||
|
||||
from cocotbext.axi import AxiStreamFrame, AxiStreamSource
|
||||
from cocotbext.axi.stream import define_stream
|
||||
|
||||
|
||||
HashTransaction, HashSource, HashSink, HashMonitor = define_stream("Hash",
|
||||
signals=["hash", "hash_type", "hash_valid"]
|
||||
)
|
||||
|
||||
|
||||
class HashType(enum.IntFlag):
|
||||
IPV4 = 1
|
||||
IPV6 = 2
|
||||
TCP = 4
|
||||
UDP = 8
|
||||
|
||||
|
||||
def hash_toep(data, key):
|
||||
k = len(key)*8-32
|
||||
key = int.from_bytes(key, 'big')
|
||||
|
||||
h = 0
|
||||
|
||||
for b in data:
|
||||
for i in range(8):
|
||||
if b & 0x80 >> i:
|
||||
h ^= (key >> k) & 0xffffffff
|
||||
k -= 1
|
||||
|
||||
return h
|
||||
|
||||
|
||||
def tuple_pack(src_ip, dest_ip, src_port=None, dest_port=None):
|
||||
src_ip = ipaddress.ip_address(src_ip)
|
||||
dest_ip = ipaddress.ip_address(dest_ip)
|
||||
data = b''
|
||||
if src_ip.version == 6 or dest_ip.version == 6:
|
||||
data += src_ip.packed
|
||||
data += dest_ip.packed
|
||||
else:
|
||||
data += src_ip.packed
|
||||
data += dest_ip.packed
|
||||
if src_port is not None and dest_port is not None:
|
||||
data += src_port.to_bytes(2, 'big') + dest_port.to_bytes(2, 'big')
|
||||
return data
|
||||
|
||||
|
||||
class TB(object):
|
||||
def __init__(self, dut):
|
||||
self.dut = dut
|
||||
|
||||
self.log = logging.getLogger("cocotb.tb")
|
||||
self.log.setLevel(logging.DEBUG)
|
||||
|
||||
cocotb.fork(Clock(dut.clk, 4, units="ns").start())
|
||||
|
||||
self.source = AxiStreamSource(dut, "s_axis", dut.clk, dut.rst)
|
||||
self.sink = HashSink(dut, "m_axis", dut.clk, dut.rst)
|
||||
|
||||
hash_key = [
|
||||
0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2,
|
||||
0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0,
|
||||
0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4,
|
||||
0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c,
|
||||
0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa
|
||||
]
|
||||
|
||||
self.set_hash_key(hash_key)
|
||||
|
||||
def set_idle_generator(self, generator=None):
|
||||
if generator:
|
||||
self.source.set_pause_generator(generator())
|
||||
|
||||
def set_hash_key(self, key):
|
||||
self.hash_key = key
|
||||
self.dut.hash_key <= int.from_bytes(key, 'big')
|
||||
|
||||
async def reset(self):
|
||||
self.dut.rst.setimmediatevalue(0)
|
||||
await RisingEdge(self.dut.clk)
|
||||
await RisingEdge(self.dut.clk)
|
||||
self.dut.rst <= 1
|
||||
await RisingEdge(self.dut.clk)
|
||||
await RisingEdge(self.dut.clk)
|
||||
self.dut.rst <= 0
|
||||
await RisingEdge(self.dut.clk)
|
||||
await RisingEdge(self.dut.clk)
|
||||
|
||||
|
||||
async def run_test(dut, payload_lengths=None, payload_data=None, idle_inserter=None, pkt_type=Ether):
|
||||
|
||||
tb = TB(dut)
|
||||
|
||||
await tb.reset()
|
||||
|
||||
tb.set_idle_generator(idle_inserter)
|
||||
|
||||
test_pkts = []
|
||||
hash_info = []
|
||||
test_frames = []
|
||||
|
||||
ip_id = 1
|
||||
|
||||
for payload in [payload_data(x) for x in payload_lengths()]:
|
||||
eth = Ether(src='5A:51:52:53:54:55', dst='DA:D1:D2:D3:D4:D5')
|
||||
if pkt_type == Ether:
|
||||
test_pkt = eth / payload
|
||||
hash_type = HashType(0)
|
||||
hash_val = 0
|
||||
else:
|
||||
ip = IP(src=f'10.1.0.{ip_id}', dst=f'10.2.0.{ip_id}', id=ip_id)
|
||||
if pkt_type == IP:
|
||||
test_pkt = eth / ip / payload
|
||||
hash_type = HashType.IPV4
|
||||
hash_val = hash_toep(tuple_pack(ip.src, ip.dst), tb.hash_key)
|
||||
elif pkt_type == UDP:
|
||||
udp = UDP(sport=ip_id, dport=0x1000+ip_id)
|
||||
test_pkt = eth / ip / udp / payload
|
||||
hash_type = HashType.IPV4 | HashType.UDP
|
||||
hash_val = hash_toep(tuple_pack(ip.src, ip.dst, udp.sport, udp.dport), tb.hash_key)
|
||||
elif pkt_type == TCP:
|
||||
tcp = TCP(sport=ip_id, dport=0x1000+ip_id)
|
||||
test_pkt = eth / ip / tcp / payload
|
||||
hash_type = HashType.IPV4 | HashType.TCP
|
||||
hash_val = hash_toep(tuple_pack(ip.src, ip.dst, tcp.sport, tcp.dport), tb.hash_key)
|
||||
|
||||
test_pkts.append(test_pkt)
|
||||
hash_info.append((hash_type, hash_val))
|
||||
|
||||
test_frame = AxiStreamFrame(test_pkt.build())
|
||||
test_frames.append(test_frame)
|
||||
tb.source.send(test_frame)
|
||||
|
||||
ip_id = (ip_id + 1) & 0xffff
|
||||
|
||||
for test_pkt, info, test_frame in zip(test_pkts, hash_info, test_frames):
|
||||
hash_type, hash_val = info
|
||||
|
||||
await tb.sink.wait()
|
||||
rx_hash = tb.sink.recv()
|
||||
|
||||
tb.log.info("RX hash: 0x%08x (expected: 0x%08x) type: %s (expected: %s)",
|
||||
rx_hash.hash, hash_val, HashType(rx_hash.hash_type.integer), hash_type)
|
||||
|
||||
assert rx_hash.hash_type == hash_type
|
||||
assert rx_hash.hash == hash_val
|
||||
|
||||
assert tb.sink.empty()
|
||||
|
||||
await RisingEdge(dut.clk)
|
||||
await RisingEdge(dut.clk)
|
||||
|
||||
|
||||
def cycle_pause():
|
||||
return itertools.cycle([1, 1, 1, 0])
|
||||
|
||||
|
||||
def size_list():
|
||||
return list(range(1, 128)) + [512, 1500, 9200] + [46]*10
|
||||
|
||||
|
||||
def incrementing_payload(length):
|
||||
return bytes(itertools.islice(itertools.cycle(range(256)), length))
|
||||
|
||||
|
||||
if cocotb.SIM_NAME:
|
||||
|
||||
factory = TestFactory(run_test)
|
||||
factory.add_option("pkt_type", [Ether, IP, UDP, TCP])
|
||||
factory.add_option("payload_lengths", [size_list])
|
||||
factory.add_option("payload_data", [incrementing_payload])
|
||||
factory.add_option("idle_inserter", [None, cycle_pause])
|
||||
factory.generate_tests()
|
||||
|
||||
|
||||
# cocotb-test
|
||||
|
||||
tests_dir = os.path.dirname(__file__)
|
||||
rtl_dir = os.path.abspath(os.path.join(tests_dir, '..', '..', 'rtl'))
|
||||
lib_dir = os.path.abspath(os.path.join(rtl_dir, '..', 'lib'))
|
||||
axi_rtl_dir = os.path.abspath(os.path.join(lib_dir, 'axi', 'rtl'))
|
||||
axis_rtl_dir = os.path.abspath(os.path.join(lib_dir, 'axis', 'rtl'))
|
||||
eth_rtl_dir = os.path.abspath(os.path.join(lib_dir, 'eth', 'rtl'))
|
||||
pcie_rtl_dir = os.path.abspath(os.path.join(lib_dir, 'pcie', 'rtl'))
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data_width", [64, 256])
|
||||
def test_rx_hash(request, data_width):
|
||||
dut = "rx_hash"
|
||||
module = os.path.splitext(os.path.basename(__file__))[0]
|
||||
toplevel = dut
|
||||
|
||||
verilog_sources = [
|
||||
os.path.join(rtl_dir, f"{dut}.v"),
|
||||
]
|
||||
|
||||
parameters = {}
|
||||
|
||||
parameters['DATA_WIDTH'] = data_width
|
||||
parameters['KEEP_WIDTH'] = parameters['DATA_WIDTH'] // 8
|
||||
|
||||
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(
|
||||
python_search=[tests_dir],
|
||||
verilog_sources=verilog_sources,
|
||||
toplevel=toplevel,
|
||||
module=module,
|
||||
parameters=parameters,
|
||||
sim_build=sim_build,
|
||||
extra_env=extra_env,
|
||||
)
|
125
fpga/common/tb/tdma_ber/Makefile
Normal file
125
fpga/common/tb/tdma_ber/Makefile
Normal file
@ -0,0 +1,125 @@
|
||||
# Copyright 2020, The Regents of the University of California.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
#
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
|
||||
# IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
|
||||
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
# OF SUCH DAMAGE.
|
||||
#
|
||||
# The views and conclusions contained in the software and documentation are those
|
||||
# of the authors and should not be interpreted as representing official policies,
|
||||
# either expressed or implied, of The Regents of the University of California.
|
||||
|
||||
TOPLEVEL_LANG = verilog
|
||||
|
||||
SIM ?= icarus
|
||||
WAVES ?= 0
|
||||
|
||||
COCOTB_HDL_TIMEUNIT = 1ns
|
||||
COCOTB_HDL_TIMEPRECISION = 1ps
|
||||
|
||||
DUT = tdma_ber
|
||||
TOPLEVEL = $(DUT)
|
||||
MODULE = test_$(DUT)
|
||||
VERILOG_SOURCES += ../../rtl/$(DUT).v
|
||||
VERILOG_SOURCES += ../../rtl/tdma_ber_ch.v
|
||||
VERILOG_SOURCES += ../../rtl/tdma_scheduler.v
|
||||
VERILOG_SOURCES += ../../lib/axi/rtl/axil_interconnect.v
|
||||
VERILOG_SOURCES += ../../lib/axi/rtl/arbiter.v
|
||||
VERILOG_SOURCES += ../../lib/axi/rtl/priority_encoder.v
|
||||
|
||||
# module parameters
|
||||
export PARAM_COUNT = 2
|
||||
export PARAM_INDEX_WIDTH = 6
|
||||
export PARAM_SLICE_WIDTH = 5
|
||||
export PARAM_AXIL_DATA_WIDTH = 32
|
||||
export PARAM_AXIL_ADDR_WIDTH = $(shell python -c "print($(PARAM_INDEX_WIDTH)+4+1+($(PARAM_COUNT)-1).bit_length())")
|
||||
export PARAM_AXIL_STRB_WIDTH = $(shell expr $(PARAM_AXIL_DATA_WIDTH) / 8 )
|
||||
export PARAM_SCHEDULE_START_S = 0
|
||||
export PARAM_SCHEDULE_START_NS = 0
|
||||
export PARAM_SCHEDULE_PERIOD_S = 0
|
||||
export PARAM_SCHEDULE_PERIOD_NS = 1000000
|
||||
export PARAM_TIMESLOT_PERIOD_S = 0
|
||||
export PARAM_TIMESLOT_PERIOD_NS = 100000
|
||||
export PARAM_ACTIVE_PERIOD_S = 0
|
||||
export PARAM_ACTIVE_PERIOD_NS = 100000
|
||||
|
||||
SIM_BUILD ?= sim_build_$(MODULE)
|
||||
|
||||
ifeq ($(SIM), icarus)
|
||||
PLUSARGS += -fst
|
||||
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).COUNT=$(PARAM_COUNT)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).INDEX_WIDTH=$(PARAM_INDEX_WIDTH)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).SLICE_WIDTH=$(PARAM_SLICE_WIDTH)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).AXIL_DATA_WIDTH=$(PARAM_AXIL_DATA_WIDTH)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).AXIL_ADDR_WIDTH=$(PARAM_AXIL_ADDR_WIDTH)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).AXIL_STRB_WIDTH=$(PARAM_AXIL_STRB_WIDTH)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).SCHEDULE_START_S=$(PARAM_SCHEDULE_START_S)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).SCHEDULE_START_NS=$(PARAM_SCHEDULE_START_NS)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).SCHEDULE_PERIOD_S=$(PARAM_SCHEDULE_PERIOD_S)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).SCHEDULE_PERIOD_NS=$(PARAM_SCHEDULE_PERIOD_NS)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).TIMESLOT_PERIOD_S=$(PARAM_TIMESLOT_PERIOD_S)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).TIMESLOT_PERIOD_NS=$(PARAM_TIMESLOT_PERIOD_NS)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).ACTIVE_PERIOD_S=$(PARAM_ACTIVE_PERIOD_S)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).ACTIVE_PERIOD_NS=$(PARAM_ACTIVE_PERIOD_NS)
|
||||
|
||||
ifeq ($(WAVES), 1)
|
||||
VERILOG_SOURCES += iverilog_dump.v
|
||||
COMPILE_ARGS += -s iverilog_dump
|
||||
endif
|
||||
else ifeq ($(SIM), verilator)
|
||||
COMPILE_ARGS += -Wno-SELRANGE -Wno-WIDTH
|
||||
|
||||
COMPILE_ARGS += -GCOUNT=$(PARAM_COUNT)
|
||||
COMPILE_ARGS += -GINDEX_WIDTH=$(PARAM_INDEX_WIDTH)
|
||||
COMPILE_ARGS += -GSLICE_WIDTH=$(PARAM_SLICE_WIDTH)
|
||||
COMPILE_ARGS += -GAXIL_DATA_WIDTH=$(PARAM_AXIL_DATA_WIDTH)
|
||||
COMPILE_ARGS += -GAXIL_ADDR_WIDTH=$(PARAM_AXIL_ADDR_WIDTH)
|
||||
COMPILE_ARGS += -GAXIL_STRB_WIDTH=$(PARAM_AXIL_STRB_WIDTH)
|
||||
COMPILE_ARGS += -GSCHEDULE_START_S=$(PARAM_SCHEDULE_START_S)
|
||||
COMPILE_ARGS += -GSCHEDULE_START_NS=$(PARAM_SCHEDULE_START_NS)
|
||||
COMPILE_ARGS += -GSCHEDULE_PERIOD_S=$(PARAM_SCHEDULE_PERIOD_S)
|
||||
COMPILE_ARGS += -GSCHEDULE_PERIOD_NS=$(PARAM_SCHEDULE_PERIOD_NS)
|
||||
COMPILE_ARGS += -GTIMESLOT_PERIOD_S=$(PARAM_TIMESLOT_PERIOD_S)
|
||||
COMPILE_ARGS += -GTIMESLOT_PERIOD_NS=$(PARAM_TIMESLOT_PERIOD_NS)
|
||||
COMPILE_ARGS += -GACTIVE_PERIOD_S=$(PARAM_ACTIVE_PERIOD_S)
|
||||
COMPILE_ARGS += -GACTIVE_PERIOD_NS=$(PARAM_ACTIVE_PERIOD_NS)
|
||||
|
||||
ifeq ($(WAVES), 1)
|
||||
COMPILE_ARGS += --trace-fst
|
||||
endif
|
||||
endif
|
||||
|
||||
iverilog_dump.v:
|
||||
echo 'module iverilog_dump();' > $@
|
||||
echo 'initial begin' >> $@
|
||||
echo ' $$dumpfile("$(TOPLEVEL).fst");' >> $@
|
||||
echo ' $$dumpvars(0, $(TOPLEVEL));' >> $@
|
||||
echo 'end' >> $@
|
||||
echo 'endmodule' >> $@
|
||||
|
||||
clean::
|
||||
@rm -rf sim_build_*
|
||||
@rm -rf iverilog_dump.v
|
||||
@rm -rf dump.fst $(TOPLEVEL).fst
|
||||
|
||||
include $(shell cocotb-config --makefiles)/Makefile.sim
|
||||
|
165
fpga/common/tb/tdma_ber/test_tdma_ber.py
Normal file
165
fpga/common/tb/tdma_ber/test_tdma_ber.py
Normal file
@ -0,0 +1,165 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
|
||||
Copyright 2020, The Regents of the University of California.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
|
||||
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of The Regents of the University of California.
|
||||
|
||||
"""
|
||||
|
||||
import logging
|
||||
import os
|
||||
|
||||
import cocotb_test.simulator
|
||||
|
||||
import cocotb
|
||||
from cocotb.clock import Clock
|
||||
from cocotb.triggers import RisingEdge, Timer
|
||||
from cocotb.regression import TestFactory
|
||||
|
||||
from cocotbext.axi import AxiLiteMaster
|
||||
from cocotbext.eth import PtpClock
|
||||
|
||||
|
||||
class TB(object):
|
||||
def __init__(self, dut):
|
||||
self.dut = dut
|
||||
|
||||
self.log = logging.getLogger("cocotb.tb")
|
||||
self.log.setLevel(logging.DEBUG)
|
||||
|
||||
cocotb.fork(Clock(dut.clk, 4, units="ns").start())
|
||||
cocotb.fork(Clock(dut.phy_tx_clk, 6.4, units="ns").start())
|
||||
cocotb.fork(Clock(dut.phy_rx_clk, 6.4, units="ns").start())
|
||||
|
||||
self.axil_master = AxiLiteMaster(dut, "s_axil", dut.clk, dut.rst)
|
||||
|
||||
self.ptp_clock = PtpClock(
|
||||
ts_96=dut.ptp_ts_96,
|
||||
ts_step=dut.ptp_ts_step,
|
||||
clock=dut.clk,
|
||||
reset=dut.rst,
|
||||
period_ns=6.4
|
||||
)
|
||||
|
||||
dut.phy_rx_error_count.setimmediatevalue(0)
|
||||
|
||||
async def reset(self):
|
||||
self.dut.rst.setimmediatevalue(0)
|
||||
await RisingEdge(self.dut.clk)
|
||||
await RisingEdge(self.dut.clk)
|
||||
self.dut.rst <= 1
|
||||
await RisingEdge(self.dut.clk)
|
||||
await RisingEdge(self.dut.clk)
|
||||
self.dut.rst <= 0
|
||||
await RisingEdge(self.dut.clk)
|
||||
await RisingEdge(self.dut.clk)
|
||||
|
||||
|
||||
async def run_test(dut):
|
||||
|
||||
tb = TB(dut)
|
||||
|
||||
await tb.reset()
|
||||
|
||||
tb.log.info("Test scheduler")
|
||||
|
||||
await tb.axil_master.write_dwords(0x0110, [0, 500, 0, 0])
|
||||
await tb.axil_master.write_dwords(0x0120, [0, 2000, 0, 0])
|
||||
await tb.axil_master.write_dwords(0x0130, [0, 400, 0, 0])
|
||||
await tb.axil_master.write_dwords(0x0140, [0, 300, 0, 0])
|
||||
await tb.axil_master.write_dword(0x0100, 0x00000001)
|
||||
|
||||
await Timer(10000, 'ns')
|
||||
|
||||
await RisingEdge(dut.clk)
|
||||
await RisingEdge(dut.clk)
|
||||
|
||||
|
||||
if cocotb.SIM_NAME:
|
||||
|
||||
factory = TestFactory(run_test)
|
||||
factory.generate_tests()
|
||||
|
||||
|
||||
# cocotb-test
|
||||
|
||||
tests_dir = os.path.dirname(__file__)
|
||||
rtl_dir = os.path.abspath(os.path.join(tests_dir, '..', '..', 'rtl'))
|
||||
lib_dir = os.path.abspath(os.path.join(rtl_dir, '..', 'lib'))
|
||||
axi_rtl_dir = os.path.abspath(os.path.join(lib_dir, 'axi', 'rtl'))
|
||||
axis_rtl_dir = os.path.abspath(os.path.join(lib_dir, 'axis', 'rtl'))
|
||||
eth_rtl_dir = os.path.abspath(os.path.join(lib_dir, 'eth', 'rtl'))
|
||||
pcie_rtl_dir = os.path.abspath(os.path.join(lib_dir, 'pcie', 'rtl'))
|
||||
|
||||
|
||||
def test_tdma_ber(request):
|
||||
dut = "tdma_ber"
|
||||
module = os.path.splitext(os.path.basename(__file__))[0]
|
||||
toplevel = dut
|
||||
|
||||
verilog_sources = [
|
||||
os.path.join(rtl_dir, f"{dut}.v"),
|
||||
os.path.join(rtl_dir, f"{dut}_ch.v"),
|
||||
os.path.join(rtl_dir, "tdma_scheduler.v"),
|
||||
os.path.join(axi_rtl_dir, "axil_interconnect.v"),
|
||||
os.path.join(axi_rtl_dir, "arbiter.v"),
|
||||
os.path.join(axi_rtl_dir, "priority_encoder.v"),
|
||||
]
|
||||
|
||||
parameters = {}
|
||||
|
||||
parameters['COUNT'] = 2
|
||||
parameters['INDEX_WIDTH'] = 6
|
||||
parameters['SLICE_WIDTH'] = 5
|
||||
parameters['AXIL_DATA_WIDTH'] = 32
|
||||
parameters['AXIL_ADDR_WIDTH'] = parameters['INDEX_WIDTH']+4+1+(parameters['COUNT']-1).bit_length()
|
||||
parameters['AXIL_STRB_WIDTH'] = parameters['AXIL_DATA_WIDTH'] // 8
|
||||
parameters['SCHEDULE_START_S'] = 0
|
||||
parameters['SCHEDULE_START_NS'] = 0
|
||||
parameters['SCHEDULE_PERIOD_S'] = 0
|
||||
parameters['SCHEDULE_PERIOD_NS'] = 1000000
|
||||
parameters['TIMESLOT_PERIOD_S'] = 0
|
||||
parameters['TIMESLOT_PERIOD_NS'] = 100000
|
||||
parameters['ACTIVE_PERIOD_S'] = 0
|
||||
parameters['ACTIVE_PERIOD_NS'] = 100000
|
||||
|
||||
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(
|
||||
python_search=[tests_dir],
|
||||
verilog_sources=verilog_sources,
|
||||
toplevel=toplevel,
|
||||
module=module,
|
||||
parameters=parameters,
|
||||
sim_build=sim_build,
|
||||
extra_env=extra_env,
|
||||
)
|
93
fpga/common/tb/tdma_ber_ch/Makefile
Normal file
93
fpga/common/tb/tdma_ber_ch/Makefile
Normal file
@ -0,0 +1,93 @@
|
||||
# Copyright 2020, The Regents of the University of California.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
#
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
|
||||
# IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
|
||||
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
# OF SUCH DAMAGE.
|
||||
#
|
||||
# The views and conclusions contained in the software and documentation are those
|
||||
# of the authors and should not be interpreted as representing official policies,
|
||||
# either expressed or implied, of The Regents of the University of California.
|
||||
|
||||
TOPLEVEL_LANG = verilog
|
||||
|
||||
SIM ?= icarus
|
||||
WAVES ?= 0
|
||||
|
||||
COCOTB_HDL_TIMEUNIT = 1ns
|
||||
COCOTB_HDL_TIMEPRECISION = 1ps
|
||||
|
||||
DUT = tdma_ber_ch
|
||||
TOPLEVEL = $(DUT)
|
||||
MODULE = test_$(DUT)
|
||||
VERILOG_SOURCES += ../../rtl/$(DUT).v
|
||||
|
||||
# module parameters
|
||||
export PARAM_INDEX_WIDTH = 6
|
||||
export PARAM_SLICE_WIDTH = 5
|
||||
export PARAM_AXIL_DATA_WIDTH = 32
|
||||
export PARAM_AXIL_ADDR_WIDTH = $(shell expr $(PARAM_INDEX_WIDTH) + 4 )
|
||||
export PARAM_AXIL_STRB_WIDTH = $(shell expr $(PARAM_AXIL_DATA_WIDTH) / 8 )
|
||||
|
||||
SIM_BUILD ?= sim_build_$(MODULE)
|
||||
|
||||
ifeq ($(SIM), icarus)
|
||||
PLUSARGS += -fst
|
||||
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).INDEX_WIDTH=$(PARAM_INDEX_WIDTH)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).SLICE_WIDTH=$(PARAM_SLICE_WIDTH)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).AXIL_DATA_WIDTH=$(PARAM_AXIL_DATA_WIDTH)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).AXIL_ADDR_WIDTH=$(PARAM_AXIL_ADDR_WIDTH)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).AXIL_STRB_WIDTH=$(PARAM_AXIL_STRB_WIDTH)
|
||||
|
||||
ifeq ($(WAVES), 1)
|
||||
VERILOG_SOURCES += iverilog_dump.v
|
||||
COMPILE_ARGS += -s iverilog_dump
|
||||
endif
|
||||
else ifeq ($(SIM), verilator)
|
||||
COMPILE_ARGS += -Wno-SELRANGE -Wno-WIDTH
|
||||
|
||||
COMPILE_ARGS += -GINDEX_WIDTH=$(PARAM_INDEX_WIDTH)
|
||||
COMPILE_ARGS += -GSLICE_WIDTH=$(PARAM_SLICE_WIDTH)
|
||||
COMPILE_ARGS += -GAXIL_DATA_WIDTH=$(PARAM_AXIL_DATA_WIDTH)
|
||||
COMPILE_ARGS += -GAXIL_ADDR_WIDTH=$(PARAM_AXIL_ADDR_WIDTH)
|
||||
COMPILE_ARGS += -GAXIL_STRB_WIDTH=$(PARAM_AXIL_STRB_WIDTH)
|
||||
|
||||
ifeq ($(WAVES), 1)
|
||||
COMPILE_ARGS += --trace-fst
|
||||
endif
|
||||
endif
|
||||
|
||||
iverilog_dump.v:
|
||||
echo 'module iverilog_dump();' > $@
|
||||
echo 'initial begin' >> $@
|
||||
echo ' $$dumpfile("$(TOPLEVEL).fst");' >> $@
|
||||
echo ' $$dumpvars(0, $(TOPLEVEL));' >> $@
|
||||
echo 'end' >> $@
|
||||
echo 'endmodule' >> $@
|
||||
|
||||
clean::
|
||||
@rm -rf sim_build_*
|
||||
@rm -rf iverilog_dump.v
|
||||
@rm -rf dump.fst $(TOPLEVEL).fst
|
||||
|
||||
include $(shell cocotb-config --makefiles)/Makefile.sim
|
||||
|
261
fpga/common/tb/tdma_ber_ch/test_tdma_ber_ch.py
Normal file
261
fpga/common/tb/tdma_ber_ch/test_tdma_ber_ch.py
Normal file
@ -0,0 +1,261 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
|
||||
Copyright 2020, The Regents of the University of California.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
|
||||
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of The Regents of the University of California.
|
||||
|
||||
"""
|
||||
|
||||
import logging
|
||||
import os
|
||||
|
||||
import cocotb_test.simulator
|
||||
|
||||
import cocotb
|
||||
from cocotb.clock import Clock
|
||||
from cocotb.triggers import RisingEdge
|
||||
from cocotb.regression import TestFactory
|
||||
|
||||
from cocotbext.axi import AxiLiteMaster
|
||||
|
||||
|
||||
class TB(object):
|
||||
def __init__(self, dut):
|
||||
self.dut = dut
|
||||
|
||||
self.log = logging.getLogger("cocotb.tb")
|
||||
self.log.setLevel(logging.DEBUG)
|
||||
|
||||
cocotb.fork(Clock(dut.clk, 4, units="ns").start())
|
||||
cocotb.fork(Clock(dut.phy_tx_clk, 6.4, units="ns").start())
|
||||
cocotb.fork(Clock(dut.phy_rx_clk, 6.4, units="ns").start())
|
||||
|
||||
self.axil_master = AxiLiteMaster(dut, "s_axil", dut.clk, dut.rst)
|
||||
|
||||
dut.phy_rx_error_count.setimmediatevalue(0)
|
||||
|
||||
dut.tdma_timeslot_index.setimmediatevalue(0)
|
||||
dut.tdma_timeslot_start.setimmediatevalue(0)
|
||||
dut.tdma_timeslot_active.setimmediatevalue(0)
|
||||
|
||||
async def reset(self):
|
||||
self.dut.rst.setimmediatevalue(0)
|
||||
await RisingEdge(self.dut.clk)
|
||||
await RisingEdge(self.dut.clk)
|
||||
self.dut.rst <= 1
|
||||
await RisingEdge(self.dut.clk)
|
||||
await RisingEdge(self.dut.clk)
|
||||
self.dut.rst <= 0
|
||||
await RisingEdge(self.dut.clk)
|
||||
await RisingEdge(self.dut.clk)
|
||||
|
||||
async def run_scheduler(self, period=50, active_period=None, slots=4, cycles=5):
|
||||
if active_period is None:
|
||||
active_period = period
|
||||
active_period = min(active_period, period)
|
||||
|
||||
await RisingEdge(self.dut.clk)
|
||||
for i in range(cycles):
|
||||
for k in range(slots):
|
||||
self.dut.tdma_timeslot_index <= k
|
||||
self.dut.tdma_timeslot_start <= 1
|
||||
self.dut.tdma_timeslot_active <= 1
|
||||
await RisingEdge(self.dut.clk)
|
||||
self.dut.tdma_timeslot_start <= 0
|
||||
for k in range(active_period-1):
|
||||
await RisingEdge(self.dut.clk)
|
||||
self.dut.tdma_timeslot_active <= 0
|
||||
for k in range(period-active_period):
|
||||
await RisingEdge(self.dut.clk)
|
||||
|
||||
async def dump_counters(self):
|
||||
cycles, updates, errors = await self.axil_master.read_dwords(0x0014, 3)
|
||||
self.log.info("Cycles: %d", cycles)
|
||||
self.log.info("Updates: %d", updates)
|
||||
self.log.info("Errors: %d", errors)
|
||||
|
||||
async def dump_timeslot_counters(self, slice_index=0):
|
||||
await self.axil_master.write_dword(0x0030, slice_index)
|
||||
counters = await self.axil_master.read_dwords(0x0200, 8)
|
||||
for k in range(4):
|
||||
self.log.info("Timeslot %d slice %d updates: %s", k, slice_index, counters[k*2])
|
||||
self.log.info("Timeslot %d slice %d errors: %s", k, slice_index, counters[k*2+1])
|
||||
|
||||
async def clear_timeslot_counters(self, slice_index=0):
|
||||
await self.axil_master.write_dword(0x0030, slice_index)
|
||||
await self.axil_master.write_dwords(0x0200, [0]*8)
|
||||
|
||||
|
||||
async def run_test(dut):
|
||||
|
||||
tb = TB(dut)
|
||||
|
||||
await tb.reset()
|
||||
|
||||
tb.log.info("Test error counts")
|
||||
|
||||
await tb.axil_master.write_dword(0x0000, 0x00000003)
|
||||
await tb.axil_master.write_dword(0x0020, 0x00000001)
|
||||
|
||||
await tb.dump_counters()
|
||||
await tb.dump_timeslot_counters()
|
||||
await tb.clear_timeslot_counters()
|
||||
|
||||
await tb.run_scheduler(period=50, active_period=None, slots=4, cycles=5)
|
||||
|
||||
await tb.dump_counters()
|
||||
await tb.dump_timeslot_counters()
|
||||
await tb.clear_timeslot_counters()
|
||||
|
||||
await RisingEdge(dut.clk)
|
||||
dut.phy_rx_error_count <= 1
|
||||
|
||||
await tb.run_scheduler(period=50, active_period=None, slots=4, cycles=5)
|
||||
|
||||
await RisingEdge(dut.clk)
|
||||
dut.phy_rx_error_count <= 0
|
||||
|
||||
await tb.dump_counters()
|
||||
await tb.dump_timeslot_counters()
|
||||
await tb.clear_timeslot_counters()
|
||||
|
||||
tb.log.info("Change duty cycle")
|
||||
|
||||
await tb.axil_master.write_dword(0x0000, 0x00000003)
|
||||
await tb.axil_master.write_dword(0x0020, 0x00000001)
|
||||
|
||||
await tb.dump_counters()
|
||||
await tb.dump_timeslot_counters()
|
||||
await tb.clear_timeslot_counters()
|
||||
|
||||
await tb.run_scheduler(period=50, active_period=40, slots=4, cycles=5)
|
||||
|
||||
await tb.dump_counters()
|
||||
await tb.dump_timeslot_counters()
|
||||
await tb.clear_timeslot_counters()
|
||||
|
||||
await RisingEdge(dut.clk)
|
||||
dut.phy_rx_error_count <= 1
|
||||
|
||||
await tb.run_scheduler(period=50, active_period=40, slots=4, cycles=5)
|
||||
|
||||
await RisingEdge(dut.clk)
|
||||
dut.phy_rx_error_count <= 0
|
||||
|
||||
await tb.dump_counters()
|
||||
await tb.dump_timeslot_counters()
|
||||
await tb.clear_timeslot_counters()
|
||||
|
||||
tb.log.info("Test slices")
|
||||
|
||||
await tb.axil_master.write_dword(0x0000, 0x00000003)
|
||||
await tb.axil_master.write_dword(0x0020, 0x00000003)
|
||||
await tb.axil_master.write_dword(0x0024, 0x00000010)
|
||||
await tb.axil_master.write_dword(0x0028, 0x00000020)
|
||||
|
||||
await tb.dump_counters()
|
||||
for k in range(3):
|
||||
await tb.dump_timeslot_counters(k)
|
||||
for k in range(3):
|
||||
await tb.clear_timeslot_counters(k)
|
||||
|
||||
await tb.run_scheduler(period=500, active_period=400, slots=4, cycles=5)
|
||||
|
||||
await tb.dump_counters()
|
||||
for k in range(3):
|
||||
await tb.dump_timeslot_counters(k)
|
||||
for k in range(3):
|
||||
await tb.clear_timeslot_counters(k)
|
||||
|
||||
await RisingEdge(dut.clk)
|
||||
dut.phy_rx_error_count <= 1
|
||||
|
||||
await tb.run_scheduler(period=500, active_period=400, slots=4, cycles=5)
|
||||
|
||||
await RisingEdge(dut.clk)
|
||||
dut.phy_rx_error_count <= 0
|
||||
|
||||
await tb.dump_counters()
|
||||
for k in range(3):
|
||||
await tb.dump_timeslot_counters(k)
|
||||
for k in range(3):
|
||||
await tb.clear_timeslot_counters(k)
|
||||
|
||||
await RisingEdge(dut.clk)
|
||||
await RisingEdge(dut.clk)
|
||||
|
||||
|
||||
if cocotb.SIM_NAME:
|
||||
|
||||
factory = TestFactory(run_test)
|
||||
factory.generate_tests()
|
||||
|
||||
|
||||
# cocotb-test
|
||||
|
||||
tests_dir = os.path.dirname(__file__)
|
||||
rtl_dir = os.path.abspath(os.path.join(tests_dir, '..', '..', 'rtl'))
|
||||
lib_dir = os.path.abspath(os.path.join(rtl_dir, '..', 'lib'))
|
||||
axi_rtl_dir = os.path.abspath(os.path.join(lib_dir, 'axi', 'rtl'))
|
||||
axis_rtl_dir = os.path.abspath(os.path.join(lib_dir, 'axis', 'rtl'))
|
||||
eth_rtl_dir = os.path.abspath(os.path.join(lib_dir, 'eth', 'rtl'))
|
||||
pcie_rtl_dir = os.path.abspath(os.path.join(lib_dir, 'pcie', 'rtl'))
|
||||
|
||||
|
||||
def test_tdma_ber_ch(request):
|
||||
dut = "tdma_ber_ch"
|
||||
module = os.path.splitext(os.path.basename(__file__))[0]
|
||||
toplevel = dut
|
||||
|
||||
verilog_sources = [
|
||||
os.path.join(rtl_dir, f"{dut}.v"),
|
||||
]
|
||||
|
||||
parameters = {}
|
||||
|
||||
parameters['INDEX_WIDTH'] = 6
|
||||
parameters['SLICE_WIDTH'] = 5
|
||||
parameters['AXIL_DATA_WIDTH'] = 32
|
||||
parameters['AXIL_ADDR_WIDTH'] = parameters['INDEX_WIDTH']+4
|
||||
parameters['AXIL_STRB_WIDTH'] = parameters['AXIL_DATA_WIDTH'] // 8
|
||||
|
||||
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(
|
||||
python_search=[tests_dir],
|
||||
verilog_sources=verilog_sources,
|
||||
toplevel=toplevel,
|
||||
module=module,
|
||||
parameters=parameters,
|
||||
sim_build=sim_build,
|
||||
extra_env=extra_env,
|
||||
)
|
99
fpga/common/tb/tdma_scheduler/Makefile
Normal file
99
fpga/common/tb/tdma_scheduler/Makefile
Normal file
@ -0,0 +1,99 @@
|
||||
# Copyright 2020, The Regents of the University of California.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
#
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
|
||||
# IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
|
||||
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
# OF SUCH DAMAGE.
|
||||
#
|
||||
# The views and conclusions contained in the software and documentation are those
|
||||
# of the authors and should not be interpreted as representing official policies,
|
||||
# either expressed or implied, of The Regents of the University of California.
|
||||
|
||||
TOPLEVEL_LANG = verilog
|
||||
|
||||
SIM ?= icarus
|
||||
WAVES ?= 0
|
||||
|
||||
COCOTB_HDL_TIMEUNIT = 1ns
|
||||
COCOTB_HDL_TIMEPRECISION = 1ps
|
||||
|
||||
DUT = tdma_scheduler
|
||||
TOPLEVEL = $(DUT)
|
||||
MODULE = test_$(DUT)
|
||||
VERILOG_SOURCES += ../../rtl/$(DUT).v
|
||||
|
||||
# module parameters
|
||||
export PARAM_INDEX_WIDTH = 8
|
||||
export PARAM_SCHEDULE_START_S = 0
|
||||
export PARAM_SCHEDULE_START_NS = 0
|
||||
export PARAM_SCHEDULE_PERIOD_S = 0
|
||||
export PARAM_SCHEDULE_PERIOD_NS = 1000000
|
||||
export PARAM_TIMESLOT_PERIOD_S = 0
|
||||
export PARAM_TIMESLOT_PERIOD_NS = 100000
|
||||
|
||||
SIM_BUILD ?= sim_build_$(MODULE)
|
||||
|
||||
ifeq ($(SIM), icarus)
|
||||
PLUSARGS += -fst
|
||||
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).INDEX_WIDTH=$(PARAM_INDEX_WIDTH)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).SCHEDULE_START_S=$(PARAM_SCHEDULE_START_S)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).SCHEDULE_START_NS=$(PARAM_SCHEDULE_START_NS)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).SCHEDULE_PERIOD_S=$(PARAM_SCHEDULE_PERIOD_S)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).SCHEDULE_PERIOD_NS=$(PARAM_SCHEDULE_PERIOD_NS)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).TIMESLOT_PERIOD_S=$(PARAM_TIMESLOT_PERIOD_S)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).TIMESLOT_PERIOD_NS=$(PARAM_TIMESLOT_PERIOD_NS)
|
||||
|
||||
ifeq ($(WAVES), 1)
|
||||
VERILOG_SOURCES += iverilog_dump.v
|
||||
COMPILE_ARGS += -s iverilog_dump
|
||||
endif
|
||||
else ifeq ($(SIM), verilator)
|
||||
COMPILE_ARGS += -Wno-SELRANGE -Wno-WIDTH
|
||||
|
||||
COMPILE_ARGS += -GINDEX_WIDTH=$(PARAM_INDEX_WIDTH)
|
||||
COMPILE_ARGS += -GSCHEDULE_START_S=$(PARAM_SCHEDULE_START_S)
|
||||
COMPILE_ARGS += -GSCHEDULE_START_NS=$(PARAM_SCHEDULE_START_NS)
|
||||
COMPILE_ARGS += -GSCHEDULE_PERIOD_S=$(PARAM_SCHEDULE_PERIOD_S)
|
||||
COMPILE_ARGS += -GSCHEDULE_PERIOD_NS=$(PARAM_SCHEDULE_PERIOD_NS)
|
||||
COMPILE_ARGS += -GTIMESLOT_PERIOD_S=$(PARAM_TIMESLOT_PERIOD_S)
|
||||
COMPILE_ARGS += -GTIMESLOT_PERIOD_NS=$(PARAM_TIMESLOT_PERIOD_NS)
|
||||
|
||||
ifeq ($(WAVES), 1)
|
||||
COMPILE_ARGS += --trace-fst
|
||||
endif
|
||||
endif
|
||||
|
||||
iverilog_dump.v:
|
||||
echo 'module iverilog_dump();' > $@
|
||||
echo 'initial begin' >> $@
|
||||
echo ' $$dumpfile("$(TOPLEVEL).fst");' >> $@
|
||||
echo ' $$dumpvars(0, $(TOPLEVEL));' >> $@
|
||||
echo 'end' >> $@
|
||||
echo 'endmodule' >> $@
|
||||
|
||||
clean::
|
||||
@rm -rf sim_build_*
|
||||
@rm -rf iverilog_dump.v
|
||||
@rm -rf dump.fst $(TOPLEVEL).fst
|
||||
|
||||
include $(shell cocotb-config --makefiles)/Makefile.sim
|
||||
|
170
fpga/common/tb/tdma_scheduler/test_tdma_scheduler.py
Normal file
170
fpga/common/tb/tdma_scheduler/test_tdma_scheduler.py
Normal file
@ -0,0 +1,170 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
|
||||
Copyright 2020, The Regents of the University of California.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
|
||||
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of The Regents of the University of California.
|
||||
|
||||
"""
|
||||
|
||||
import logging
|
||||
import os
|
||||
|
||||
import cocotb_test.simulator
|
||||
|
||||
import cocotb
|
||||
from cocotb.clock import Clock
|
||||
from cocotb.triggers import RisingEdge, Timer
|
||||
from cocotb.regression import TestFactory
|
||||
|
||||
from cocotbext.eth import PtpClock
|
||||
|
||||
|
||||
class TB(object):
|
||||
def __init__(self, dut):
|
||||
self.dut = dut
|
||||
|
||||
self.log = logging.getLogger("cocotb.tb")
|
||||
self.log.setLevel(logging.DEBUG)
|
||||
|
||||
cocotb.fork(Clock(dut.clk, 4, units="ns").start())
|
||||
|
||||
self.ptp_clock = PtpClock(
|
||||
ts_96=dut.input_ts_96,
|
||||
ts_step=dut.input_ts_step,
|
||||
clock=dut.clk,
|
||||
reset=dut.rst,
|
||||
period_ns=6.4
|
||||
)
|
||||
|
||||
dut.enable.setimmediatevalue(0)
|
||||
dut.input_schedule_start.setimmediatevalue(0)
|
||||
dut.input_schedule_start_valid.setimmediatevalue(0)
|
||||
dut.input_schedule_period.setimmediatevalue(0)
|
||||
dut.input_schedule_period_valid.setimmediatevalue(0)
|
||||
dut.input_timeslot_period.setimmediatevalue(0)
|
||||
dut.input_timeslot_period_valid.setimmediatevalue(0)
|
||||
dut.input_active_period.setimmediatevalue(0)
|
||||
dut.input_active_period_valid.setimmediatevalue(0)
|
||||
|
||||
async def reset(self):
|
||||
self.dut.rst.setimmediatevalue(0)
|
||||
await RisingEdge(self.dut.clk)
|
||||
await RisingEdge(self.dut.clk)
|
||||
self.dut.rst <= 1
|
||||
await RisingEdge(self.dut.clk)
|
||||
await RisingEdge(self.dut.clk)
|
||||
self.dut.rst <= 0
|
||||
await RisingEdge(self.dut.clk)
|
||||
await RisingEdge(self.dut.clk)
|
||||
|
||||
|
||||
async def run_test(dut):
|
||||
|
||||
tb = TB(dut)
|
||||
|
||||
await tb.reset()
|
||||
|
||||
dut.enable <= 1
|
||||
|
||||
tb.log.info("Test pulse out")
|
||||
|
||||
await RisingEdge(dut.clk)
|
||||
|
||||
dut.input_schedule_start <= 1000
|
||||
dut.input_schedule_start_valid <= 1
|
||||
dut.input_schedule_period <= 2000
|
||||
dut.input_schedule_period_valid <= 1
|
||||
dut.input_timeslot_period <= 400
|
||||
dut.input_timeslot_period_valid <= 1
|
||||
dut.input_active_period <= 300
|
||||
dut.input_active_period_valid <= 1
|
||||
|
||||
await RisingEdge(dut.clk)
|
||||
|
||||
dut.input_schedule_start_valid <= 0
|
||||
dut.input_schedule_period_valid <= 0
|
||||
dut.input_timeslot_period_valid <= 0
|
||||
dut.input_active_period_valid <= 0
|
||||
|
||||
await Timer(10000, 'ns')
|
||||
|
||||
await RisingEdge(dut.clk)
|
||||
await RisingEdge(dut.clk)
|
||||
|
||||
|
||||
if cocotb.SIM_NAME:
|
||||
|
||||
factory = TestFactory(run_test)
|
||||
factory.generate_tests()
|
||||
|
||||
|
||||
# cocotb-test
|
||||
|
||||
tests_dir = os.path.dirname(__file__)
|
||||
rtl_dir = os.path.abspath(os.path.join(tests_dir, '..', '..', 'rtl'))
|
||||
lib_dir = os.path.abspath(os.path.join(rtl_dir, '..', 'lib'))
|
||||
axi_rtl_dir = os.path.abspath(os.path.join(lib_dir, 'axi', 'rtl'))
|
||||
axis_rtl_dir = os.path.abspath(os.path.join(lib_dir, 'axis', 'rtl'))
|
||||
eth_rtl_dir = os.path.abspath(os.path.join(lib_dir, 'eth', 'rtl'))
|
||||
pcie_rtl_dir = os.path.abspath(os.path.join(lib_dir, 'pcie', 'rtl'))
|
||||
|
||||
|
||||
def test_tdma_scheduler(request):
|
||||
dut = "tdma_scheduler"
|
||||
module = os.path.splitext(os.path.basename(__file__))[0]
|
||||
toplevel = dut
|
||||
|
||||
verilog_sources = [
|
||||
os.path.join(rtl_dir, f"{dut}.v"),
|
||||
]
|
||||
|
||||
parameters = {}
|
||||
|
||||
parameters['INDEX_WIDTH'] = 8
|
||||
parameters['SCHEDULE_START_S'] = 0
|
||||
parameters['SCHEDULE_START_NS'] = 0
|
||||
parameters['SCHEDULE_PERIOD_S'] = 0
|
||||
parameters['SCHEDULE_PERIOD_NS'] = 1000000
|
||||
parameters['TIMESLOT_PERIOD_S'] = 0
|
||||
parameters['TIMESLOT_PERIOD_NS'] = 100000
|
||||
|
||||
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(
|
||||
python_search=[tests_dir],
|
||||
verilog_sources=verilog_sources,
|
||||
toplevel=toplevel,
|
||||
module=module,
|
||||
parameters=parameters,
|
||||
sim_build=sim_build,
|
||||
extra_env=extra_env,
|
||||
)
|
@ -1,495 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
|
||||
Copyright 2019, The Regents of the University of California.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
|
||||
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of The Regents of the University of California.
|
||||
|
||||
"""
|
||||
|
||||
from myhdl import *
|
||||
import os
|
||||
|
||||
import axil
|
||||
import axis_ep
|
||||
|
||||
import random
|
||||
import struct
|
||||
|
||||
module = 'cpl_queue_manager'
|
||||
testbench = 'test_%s' % module
|
||||
|
||||
srcs = []
|
||||
|
||||
srcs.append("../rtl/%s.v" % module)
|
||||
srcs.append("%s.v" % testbench)
|
||||
|
||||
src = ' '.join(srcs)
|
||||
|
||||
build_cmd = "iverilog -o %s.vvp %s" % (testbench, src)
|
||||
|
||||
def bench():
|
||||
|
||||
# Parameters
|
||||
ADDR_WIDTH = 64
|
||||
REQ_TAG_WIDTH = 8
|
||||
OP_TABLE_SIZE = 16
|
||||
OP_TAG_WIDTH = 8
|
||||
QUEUE_INDEX_WIDTH = 8
|
||||
EVENT_WIDTH = 8
|
||||
QUEUE_PTR_WIDTH = 16
|
||||
LOG_QUEUE_SIZE_WIDTH = 4
|
||||
CPL_SIZE = 16
|
||||
PIPELINE = 2
|
||||
AXIL_DATA_WIDTH = 32
|
||||
AXIL_ADDR_WIDTH = 16
|
||||
AXIL_STRB_WIDTH = (AXIL_DATA_WIDTH/8)
|
||||
|
||||
# Inputs
|
||||
clk = Signal(bool(0))
|
||||
rst = Signal(bool(0))
|
||||
current_test = Signal(intbv(0)[8:])
|
||||
|
||||
s_axis_enqueue_req_queue = Signal(intbv(0)[QUEUE_INDEX_WIDTH:])
|
||||
s_axis_enqueue_req_tag = Signal(intbv(0)[REQ_TAG_WIDTH:])
|
||||
s_axis_enqueue_req_valid = Signal(bool(0))
|
||||
m_axis_enqueue_resp_ready = Signal(bool(0))
|
||||
s_axis_enqueue_commit_op_tag = Signal(intbv(0)[OP_TAG_WIDTH:])
|
||||
s_axis_enqueue_commit_valid = Signal(bool(0))
|
||||
s_axil_awaddr = Signal(intbv(0)[AXIL_ADDR_WIDTH:])
|
||||
s_axil_awprot = Signal(intbv(0)[3:])
|
||||
s_axil_awvalid = Signal(bool(0))
|
||||
s_axil_wdata = Signal(intbv(0)[AXIL_DATA_WIDTH:])
|
||||
s_axil_wstrb = Signal(intbv(0)[AXIL_STRB_WIDTH:])
|
||||
s_axil_wvalid = Signal(bool(0))
|
||||
s_axil_bready = Signal(bool(0))
|
||||
s_axil_araddr = Signal(intbv(0)[AXIL_ADDR_WIDTH:])
|
||||
s_axil_arprot = Signal(intbv(0)[3:])
|
||||
s_axil_arvalid = Signal(bool(0))
|
||||
s_axil_rready = Signal(bool(0))
|
||||
enable = Signal(bool(0))
|
||||
|
||||
# Outputs
|
||||
s_axis_enqueue_req_ready = Signal(bool(0))
|
||||
m_axis_enqueue_resp_queue = Signal(intbv(0)[QUEUE_INDEX_WIDTH:])
|
||||
m_axis_enqueue_resp_ptr = Signal(intbv(0)[QUEUE_PTR_WIDTH:])
|
||||
m_axis_enqueue_resp_addr = Signal(intbv(0)[ADDR_WIDTH:])
|
||||
m_axis_enqueue_resp_event = Signal(intbv(0)[EVENT_WIDTH:])
|
||||
m_axis_enqueue_resp_tag = Signal(intbv(0)[REQ_TAG_WIDTH:])
|
||||
m_axis_enqueue_resp_op_tag = Signal(intbv(0)[OP_TAG_WIDTH:])
|
||||
m_axis_enqueue_resp_full = Signal(bool(0))
|
||||
m_axis_enqueue_resp_error = Signal(bool(0))
|
||||
m_axis_enqueue_resp_valid = Signal(bool(0))
|
||||
s_axis_enqueue_commit_ready = Signal(bool(0))
|
||||
m_axis_event = Signal(intbv(0)[EVENT_WIDTH:])
|
||||
m_axis_event_source = Signal(intbv(0)[QUEUE_INDEX_WIDTH:])
|
||||
m_axis_event_valid = Signal(bool(0))
|
||||
s_axil_awready = Signal(bool(0))
|
||||
s_axil_wready = Signal(bool(0))
|
||||
s_axil_bresp = Signal(intbv(0)[2:])
|
||||
s_axil_bvalid = Signal(bool(0))
|
||||
s_axil_arready = Signal(bool(0))
|
||||
s_axil_rdata = Signal(intbv(0)[AXIL_DATA_WIDTH:])
|
||||
s_axil_rresp = Signal(intbv(0)[2:])
|
||||
s_axil_rvalid = Signal(bool(0))
|
||||
|
||||
# sources and sinks
|
||||
enqueue_req_source = axis_ep.AXIStreamSource()
|
||||
|
||||
enqueue_req_source_logic = enqueue_req_source.create_logic(
|
||||
clk,
|
||||
rst,
|
||||
tdata=(s_axis_enqueue_req_queue, s_axis_enqueue_req_tag),
|
||||
tvalid=s_axis_enqueue_req_valid,
|
||||
tready=s_axis_enqueue_req_ready,
|
||||
name='enqueue_req_source'
|
||||
)
|
||||
|
||||
enqueue_resp_sink = axis_ep.AXIStreamSink()
|
||||
|
||||
enqueue_resp_sink_logic = enqueue_resp_sink.create_logic(
|
||||
clk,
|
||||
rst,
|
||||
tdata=(m_axis_enqueue_resp_queue, m_axis_enqueue_resp_ptr, m_axis_enqueue_resp_addr, m_axis_enqueue_resp_event, m_axis_enqueue_resp_tag, m_axis_enqueue_resp_op_tag, m_axis_enqueue_resp_full, m_axis_enqueue_resp_error),
|
||||
tvalid=m_axis_enqueue_resp_valid,
|
||||
tready=m_axis_enqueue_resp_ready,
|
||||
name='enqueue_resp_sink'
|
||||
)
|
||||
|
||||
enqueue_commit_source = axis_ep.AXIStreamSource()
|
||||
|
||||
enqueue_commit_source_logic = enqueue_commit_source.create_logic(
|
||||
clk,
|
||||
rst,
|
||||
tdata=(s_axis_enqueue_commit_op_tag,),
|
||||
tvalid=s_axis_enqueue_commit_valid,
|
||||
tready=s_axis_enqueue_commit_ready,
|
||||
name='enqueue_commit_source'
|
||||
)
|
||||
|
||||
event_sink = axis_ep.AXIStreamSink()
|
||||
|
||||
event_sink_logic = event_sink.create_logic(
|
||||
clk,
|
||||
rst,
|
||||
tdata=(m_axis_event, m_axis_event_source),
|
||||
tvalid=m_axis_event_valid,
|
||||
name='event_sink'
|
||||
)
|
||||
|
||||
# AXI4-Lite master
|
||||
axil_master_inst = axil.AXILiteMaster()
|
||||
axil_master_pause = Signal(bool(False))
|
||||
|
||||
axil_master_logic = axil_master_inst.create_logic(
|
||||
clk,
|
||||
rst,
|
||||
m_axil_awaddr=s_axil_awaddr,
|
||||
m_axil_awprot=s_axil_awprot,
|
||||
m_axil_awvalid=s_axil_awvalid,
|
||||
m_axil_awready=s_axil_awready,
|
||||
m_axil_wdata=s_axil_wdata,
|
||||
m_axil_wstrb=s_axil_wstrb,
|
||||
m_axil_wvalid=s_axil_wvalid,
|
||||
m_axil_wready=s_axil_wready,
|
||||
m_axil_bresp=s_axil_bresp,
|
||||
m_axil_bvalid=s_axil_bvalid,
|
||||
m_axil_bready=s_axil_bready,
|
||||
m_axil_araddr=s_axil_araddr,
|
||||
m_axil_arprot=s_axil_arprot,
|
||||
m_axil_arvalid=s_axil_arvalid,
|
||||
m_axil_arready=s_axil_arready,
|
||||
m_axil_rdata=s_axil_rdata,
|
||||
m_axil_rresp=s_axil_rresp,
|
||||
m_axil_rvalid=s_axil_rvalid,
|
||||
m_axil_rready=s_axil_rready,
|
||||
pause=axil_master_pause,
|
||||
name='master'
|
||||
)
|
||||
|
||||
# DUT
|
||||
if os.system(build_cmd):
|
||||
raise Exception("Error running build command")
|
||||
|
||||
dut = Cosimulation(
|
||||
"vvp -m myhdl %s.vvp -lxt2" % testbench,
|
||||
clk=clk,
|
||||
rst=rst,
|
||||
current_test=current_test,
|
||||
s_axis_enqueue_req_queue=s_axis_enqueue_req_queue,
|
||||
s_axis_enqueue_req_tag=s_axis_enqueue_req_tag,
|
||||
s_axis_enqueue_req_valid=s_axis_enqueue_req_valid,
|
||||
s_axis_enqueue_req_ready=s_axis_enqueue_req_ready,
|
||||
m_axis_enqueue_resp_queue=m_axis_enqueue_resp_queue,
|
||||
m_axis_enqueue_resp_ptr=m_axis_enqueue_resp_ptr,
|
||||
m_axis_enqueue_resp_addr=m_axis_enqueue_resp_addr,
|
||||
m_axis_enqueue_resp_event=m_axis_enqueue_resp_event,
|
||||
m_axis_enqueue_resp_tag=m_axis_enqueue_resp_tag,
|
||||
m_axis_enqueue_resp_op_tag=m_axis_enqueue_resp_op_tag,
|
||||
m_axis_enqueue_resp_full=m_axis_enqueue_resp_full,
|
||||
m_axis_enqueue_resp_error=m_axis_enqueue_resp_error,
|
||||
m_axis_enqueue_resp_valid=m_axis_enqueue_resp_valid,
|
||||
m_axis_enqueue_resp_ready=m_axis_enqueue_resp_ready,
|
||||
s_axis_enqueue_commit_op_tag=s_axis_enqueue_commit_op_tag,
|
||||
s_axis_enqueue_commit_valid=s_axis_enqueue_commit_valid,
|
||||
s_axis_enqueue_commit_ready=s_axis_enqueue_commit_ready,
|
||||
m_axis_event=m_axis_event,
|
||||
m_axis_event_source=m_axis_event_source,
|
||||
m_axis_event_valid=m_axis_event_valid,
|
||||
s_axil_awaddr=s_axil_awaddr,
|
||||
s_axil_awprot=s_axil_awprot,
|
||||
s_axil_awvalid=s_axil_awvalid,
|
||||
s_axil_awready=s_axil_awready,
|
||||
s_axil_wdata=s_axil_wdata,
|
||||
s_axil_wstrb=s_axil_wstrb,
|
||||
s_axil_wvalid=s_axil_wvalid,
|
||||
s_axil_wready=s_axil_wready,
|
||||
s_axil_bresp=s_axil_bresp,
|
||||
s_axil_bvalid=s_axil_bvalid,
|
||||
s_axil_bready=s_axil_bready,
|
||||
s_axil_araddr=s_axil_araddr,
|
||||
s_axil_arprot=s_axil_arprot,
|
||||
s_axil_arvalid=s_axil_arvalid,
|
||||
s_axil_arready=s_axil_arready,
|
||||
s_axil_rdata=s_axil_rdata,
|
||||
s_axil_rresp=s_axil_rresp,
|
||||
s_axil_rvalid=s_axil_rvalid,
|
||||
s_axil_rready=s_axil_rready,
|
||||
enable=enable
|
||||
)
|
||||
|
||||
@always(delay(4))
|
||||
def clkgen():
|
||||
clk.next = not clk
|
||||
|
||||
@instance
|
||||
def check():
|
||||
yield delay(100)
|
||||
yield clk.posedge
|
||||
rst.next = 1
|
||||
yield clk.posedge
|
||||
rst.next = 0
|
||||
yield clk.posedge
|
||||
yield delay(100)
|
||||
yield clk.posedge
|
||||
|
||||
# testbench stimulus
|
||||
|
||||
enable.next = 1
|
||||
|
||||
yield clk.posedge
|
||||
print("test 1: read and write queue configuration registers")
|
||||
current_test.next = 1
|
||||
|
||||
axil_master_inst.init_write(0*32+0, struct.pack('<Q', 0x8877665544332211)) # address
|
||||
axil_master_inst.init_write(0*32+8, struct.pack('<L', 0x00000004)) # active, log size
|
||||
axil_master_inst.init_write(0*32+12, struct.pack('<L', 0x80000001)) # armed, continuous, event
|
||||
axil_master_inst.init_write(0*32+16, struct.pack('<L', 0x00000000)) # head pointer
|
||||
axil_master_inst.init_write(0*32+24, struct.pack('<L', 0x00000000)) # tail pointer
|
||||
axil_master_inst.init_write(0*32+8, struct.pack('<L', 0x80000004)) # active, log size
|
||||
|
||||
yield axil_master_inst.wait()
|
||||
yield clk.posedge
|
||||
|
||||
axil_master_inst.init_read(0*32+0, 8)
|
||||
axil_master_inst.init_read(0*32+8, 4)
|
||||
axil_master_inst.init_read(0*32+12, 4)
|
||||
|
||||
yield axil_master_inst.wait()
|
||||
yield clk.posedge
|
||||
|
||||
data = axil_master_inst.get_read_data()
|
||||
assert struct.unpack('<Q', data[1])[0] == 0x8877665544332211
|
||||
data = axil_master_inst.get_read_data()
|
||||
assert struct.unpack('<L', data[1])[0] == 0x80000004
|
||||
data = axil_master_inst.get_read_data()
|
||||
assert struct.unpack('<L', data[1])[0] == 0x80000001
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 2: enqueue and dequeue")
|
||||
current_test.next = 2
|
||||
|
||||
# read head pointer
|
||||
axil_master_inst.init_read(0*32+16, 4) # head pointer
|
||||
yield axil_master_inst.wait()
|
||||
|
||||
data = axil_master_inst.get_read_data()
|
||||
head_ptr = struct.unpack('<L', data[1])[0]
|
||||
|
||||
# enqueue request
|
||||
enqueue_req_source.send([(0, 1)])
|
||||
|
||||
yield enqueue_resp_sink.wait()
|
||||
|
||||
resp = enqueue_resp_sink.recv()
|
||||
print(resp)
|
||||
|
||||
# enqueue commit
|
||||
enqueue_commit_source.send([(resp.data[0][5],)])
|
||||
|
||||
# check event
|
||||
yield event_sink.wait()
|
||||
event = event_sink.recv()
|
||||
assert event.data[0][0] == 1 # event
|
||||
assert event.data[0][1] == 0 # source (queue)
|
||||
|
||||
yield delay(100)
|
||||
|
||||
# read head pointer
|
||||
axil_master_inst.init_read(0*32+16, 4) # head pointer
|
||||
yield axil_master_inst.wait()
|
||||
|
||||
data = axil_master_inst.get_read_data()
|
||||
new_head_ptr = struct.unpack('<L', data[1])[0]
|
||||
|
||||
assert new_head_ptr - head_ptr == 1
|
||||
|
||||
# increment tail pointer
|
||||
axil_master_inst.init_read(0*32+24, 4) # tail pointer
|
||||
yield axil_master_inst.wait()
|
||||
|
||||
data = axil_master_inst.get_read_data()
|
||||
tail_ptr = struct.unpack('<L', data[1])[0]
|
||||
|
||||
axil_master_inst.init_write(0*32+24, struct.pack('<L', tail_ptr + 1)) # tail pointer
|
||||
|
||||
yield axil_master_inst.wait()
|
||||
yield clk.posedge
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 3: set up more queues")
|
||||
current_test.next = 3
|
||||
|
||||
axil_master_inst.init_write(0*32+8, struct.pack('<L', 0x00000004)) # active, log size
|
||||
axil_master_inst.init_write(0*32+0, struct.pack('<Q', 0x5555555555000000)) # address
|
||||
axil_master_inst.init_write(0*32+8, struct.pack('<L', 0x00000004)) # active, log size
|
||||
axil_master_inst.init_write(0*32+12, struct.pack('<L', 0xC0000000)) # armed, continuous, event
|
||||
axil_master_inst.init_write(0*32+16, struct.pack('<L', 0x0000fff0)) # head pointer
|
||||
axil_master_inst.init_write(0*32+24, struct.pack('<L', 0x0000fff0)) # tail pointer
|
||||
axil_master_inst.init_write(0*32+8, struct.pack('<L', 0x80000004)) # active, log size
|
||||
|
||||
axil_master_inst.init_write(1*32+8, struct.pack('<L', 0x00000004)) # active, log size
|
||||
axil_master_inst.init_write(1*32+0, struct.pack('<Q', 0x5555555555010000)) # address
|
||||
axil_master_inst.init_write(1*32+8, struct.pack('<L', 0x00000004)) # active, log size
|
||||
axil_master_inst.init_write(1*32+12, struct.pack('<L', 0xC0000001)) # armed, continuous, event
|
||||
axil_master_inst.init_write(1*32+16, struct.pack('<L', 0x0000fff0)) # head pointer
|
||||
axil_master_inst.init_write(1*32+24, struct.pack('<L', 0x0000fff0)) # tail pointer
|
||||
axil_master_inst.init_write(1*32+8, struct.pack('<L', 0x80000004)) # active, log size
|
||||
|
||||
axil_master_inst.init_write(2*32+8, struct.pack('<L', 0x00000004)) # active, log size
|
||||
axil_master_inst.init_write(2*32+0, struct.pack('<Q', 0x5555555555020000)) # address
|
||||
axil_master_inst.init_write(2*32+8, struct.pack('<L', 0x00000004)) # active, log size
|
||||
axil_master_inst.init_write(2*32+12, struct.pack('<L', 0xC0000002)) # armed, continuous, event
|
||||
axil_master_inst.init_write(2*32+16, struct.pack('<L', 0x0000fff0)) # head pointer
|
||||
axil_master_inst.init_write(2*32+24, struct.pack('<L', 0x0000fff0)) # tail pointer
|
||||
axil_master_inst.init_write(2*32+8, struct.pack('<L', 0x80000004)) # active, log size
|
||||
|
||||
axil_master_inst.init_write(3*32+8, struct.pack('<L', 0x00000004)) # active, log size
|
||||
axil_master_inst.init_write(3*32+0, struct.pack('<Q', 0x5555555555030000)) # address
|
||||
axil_master_inst.init_write(3*32+8, struct.pack('<L', 0x00000004)) # active, log size
|
||||
axil_master_inst.init_write(3*32+12, struct.pack('<L', 0xC0000003)) # armed, continuous, event
|
||||
axil_master_inst.init_write(3*32+16, struct.pack('<L', 0x0000fff0)) # head pointer
|
||||
axil_master_inst.init_write(3*32+24, struct.pack('<L', 0x0000fff0)) # tail pointer
|
||||
axil_master_inst.init_write(3*32+8, struct.pack('<L', 0x80000004)) # active, log size
|
||||
|
||||
yield axil_master_inst.wait()
|
||||
yield clk.posedge
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 4: multiple enqueue and dequeue")
|
||||
current_test.next = 4
|
||||
|
||||
current_tag = 1
|
||||
|
||||
queue_head_ptr = [0xfff0]*4
|
||||
queue_tail_ptr = [0xfff0]*4
|
||||
queue_depth = [0]*4
|
||||
queue_uncommit_depth = [0]*4
|
||||
|
||||
commit_list = []
|
||||
|
||||
random.seed(123456)
|
||||
|
||||
for i in range(50):
|
||||
# enqueue
|
||||
for k in range(random.randrange(8)):
|
||||
q = random.randrange(4)
|
||||
|
||||
if len(commit_list) < OP_TABLE_SIZE:
|
||||
print("Try enqueue into queue %d" % q)
|
||||
|
||||
# enqueue request
|
||||
enqueue_req_source.send([(q, current_tag)])
|
||||
|
||||
yield enqueue_resp_sink.wait()
|
||||
|
||||
resp = enqueue_resp_sink.recv()
|
||||
print(resp)
|
||||
|
||||
assert resp.data[0][0] == q
|
||||
#assert resp.data[0][1] == queue_head_ptr[q]
|
||||
assert (resp.data[0][2] >> 16) & 0xf == q
|
||||
assert (resp.data[0][2] >> 4) & 0xf == queue_head_ptr[q] & 0xf
|
||||
assert resp.data[0][3] == q
|
||||
|
||||
assert resp.data[0][4] == current_tag # tag
|
||||
assert not resp.data[0][7] # error
|
||||
|
||||
if queue_uncommit_depth[q] < 16:
|
||||
commit_list.append((q, resp.data[0][5]))
|
||||
queue_head_ptr[q] = (queue_head_ptr[q] + 1) & 0xffff
|
||||
queue_uncommit_depth[q] += 1
|
||||
else:
|
||||
print("Queue was full")
|
||||
assert resp.data[0][6] # full
|
||||
|
||||
current_tag = (current_tag + 1) % 256
|
||||
|
||||
# commit
|
||||
#random.shuffle(commit_list)
|
||||
for k in range(random.randrange(8)):
|
||||
if commit_list:
|
||||
q, t = commit_list.pop(0)
|
||||
|
||||
print("Commit enqueue into queue %d" % q)
|
||||
|
||||
# enqueue commit
|
||||
enqueue_commit_source.send([(t,)])
|
||||
|
||||
queue_depth[q] += 1
|
||||
|
||||
# check event
|
||||
yield event_sink.wait()
|
||||
event = event_sink.recv()
|
||||
assert event.data[0][0] == q # event
|
||||
assert event.data[0][1] == q # source (queue)
|
||||
|
||||
# dequeue
|
||||
for k in range(random.randrange(8)):
|
||||
q = random.randrange(4)
|
||||
|
||||
if queue_depth[q] > 0:
|
||||
print("Dequeue from queue %d" % q)
|
||||
|
||||
# increment tail pointer
|
||||
axil_master_inst.init_read(q*32+24, 4) # tail pointer
|
||||
yield axil_master_inst.wait()
|
||||
|
||||
data = axil_master_inst.get_read_data()
|
||||
tail_ptr = struct.unpack('<L', data[1])[0]
|
||||
|
||||
assert tail_ptr == queue_tail_ptr[q]
|
||||
|
||||
tail_ptr = (tail_ptr + 1) & 0xffff
|
||||
|
||||
queue_tail_ptr[q] = tail_ptr
|
||||
queue_depth[q] -= 1
|
||||
queue_uncommit_depth[q] -= 1
|
||||
|
||||
axil_master_inst.init_write(q*32+24, struct.pack('<L', tail_ptr)) # tail pointer
|
||||
yield axil_master_inst.wait()
|
||||
|
||||
yield delay(100)
|
||||
|
||||
raise StopSimulation
|
||||
|
||||
return instances()
|
||||
|
||||
def test_bench():
|
||||
sim = Simulation(bench())
|
||||
sim.run()
|
||||
|
||||
if __name__ == '__main__':
|
||||
print("Running test...")
|
||||
test_bench()
|
@ -1,221 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright 2019, The Regents of the University of California.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
|
||||
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of The Regents of the University of California.
|
||||
|
||||
*/
|
||||
|
||||
// Language: Verilog 2001
|
||||
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
/*
|
||||
* Testbench for cpl_queue_manager
|
||||
*/
|
||||
module test_cpl_queue_manager;
|
||||
|
||||
// Parameters
|
||||
parameter ADDR_WIDTH = 64;
|
||||
parameter REQ_TAG_WIDTH = 8;
|
||||
parameter OP_TABLE_SIZE = 16;
|
||||
parameter OP_TAG_WIDTH = 8;
|
||||
parameter QUEUE_INDEX_WIDTH = 8;
|
||||
parameter EVENT_WIDTH = 8;
|
||||
parameter QUEUE_PTR_WIDTH = 16;
|
||||
parameter LOG_QUEUE_SIZE_WIDTH = 4;
|
||||
parameter CPL_SIZE = 16;
|
||||
parameter PIPELINE = 2;
|
||||
parameter AXIL_DATA_WIDTH = 32;
|
||||
parameter AXIL_ADDR_WIDTH = 16;
|
||||
parameter AXIL_STRB_WIDTH = (AXIL_DATA_WIDTH/8);
|
||||
|
||||
// Inputs
|
||||
reg clk = 0;
|
||||
reg rst = 0;
|
||||
reg [7:0] current_test = 0;
|
||||
|
||||
reg [QUEUE_INDEX_WIDTH-1:0] s_axis_enqueue_req_queue = 0;
|
||||
reg [REQ_TAG_WIDTH-1:0] s_axis_enqueue_req_tag = 0;
|
||||
reg s_axis_enqueue_req_valid = 0;
|
||||
reg m_axis_enqueue_resp_ready = 0;
|
||||
reg [OP_TAG_WIDTH-1:0] s_axis_enqueue_commit_op_tag = 0;
|
||||
reg s_axis_enqueue_commit_valid = 0;
|
||||
reg [AXIL_ADDR_WIDTH-1:0] s_axil_awaddr = 0;
|
||||
reg [2:0] s_axil_awprot = 0;
|
||||
reg s_axil_awvalid = 0;
|
||||
reg [AXIL_DATA_WIDTH-1:0] s_axil_wdata = 0;
|
||||
reg [AXIL_STRB_WIDTH-1:0] s_axil_wstrb = 0;
|
||||
reg s_axil_wvalid = 0;
|
||||
reg s_axil_bready = 0;
|
||||
reg [AXIL_ADDR_WIDTH-1:0] s_axil_araddr = 0;
|
||||
reg [2:0] s_axil_arprot = 0;
|
||||
reg s_axil_arvalid = 0;
|
||||
reg s_axil_rready = 0;
|
||||
reg enable = 0;
|
||||
|
||||
// Outputs
|
||||
wire s_axis_enqueue_req_ready;
|
||||
wire [QUEUE_INDEX_WIDTH-1:0] m_axis_enqueue_resp_queue;
|
||||
wire [QUEUE_PTR_WIDTH-1:0] m_axis_enqueue_resp_ptr;
|
||||
wire [ADDR_WIDTH-1:0] m_axis_enqueue_resp_addr;
|
||||
wire [EVENT_WIDTH-1:0] m_axis_enqueue_resp_event;
|
||||
wire [REQ_TAG_WIDTH-1:0] m_axis_enqueue_resp_tag;
|
||||
wire [OP_TAG_WIDTH-1:0] m_axis_enqueue_resp_op_tag;
|
||||
wire m_axis_enqueue_resp_full;
|
||||
wire m_axis_enqueue_resp_error;
|
||||
wire m_axis_enqueue_resp_valid;
|
||||
wire s_axis_enqueue_commit_ready;
|
||||
wire [EVENT_WIDTH-1:0] m_axis_event;
|
||||
wire [QUEUE_INDEX_WIDTH-1:0] m_axis_event_source;
|
||||
wire m_axis_event_valid;
|
||||
wire s_axil_awready;
|
||||
wire s_axil_wready;
|
||||
wire [1:0] s_axil_bresp;
|
||||
wire s_axil_bvalid;
|
||||
wire s_axil_arready;
|
||||
wire [AXIL_DATA_WIDTH-1:0] s_axil_rdata;
|
||||
wire [1:0] s_axil_rresp;
|
||||
wire s_axil_rvalid;
|
||||
|
||||
initial begin
|
||||
// myhdl integration
|
||||
$from_myhdl(
|
||||
clk,
|
||||
rst,
|
||||
current_test,
|
||||
s_axis_enqueue_req_queue,
|
||||
s_axis_enqueue_req_tag,
|
||||
s_axis_enqueue_req_valid,
|
||||
m_axis_enqueue_resp_ready,
|
||||
s_axis_enqueue_commit_op_tag,
|
||||
s_axis_enqueue_commit_valid,
|
||||
s_axil_awaddr,
|
||||
s_axil_awprot,
|
||||
s_axil_awvalid,
|
||||
s_axil_wdata,
|
||||
s_axil_wstrb,
|
||||
s_axil_wvalid,
|
||||
s_axil_bready,
|
||||
s_axil_araddr,
|
||||
s_axil_arprot,
|
||||
s_axil_arvalid,
|
||||
s_axil_rready,
|
||||
enable
|
||||
);
|
||||
$to_myhdl(
|
||||
s_axis_enqueue_req_ready,
|
||||
m_axis_enqueue_resp_queue,
|
||||
m_axis_enqueue_resp_ptr,
|
||||
m_axis_enqueue_resp_addr,
|
||||
m_axis_enqueue_resp_event,
|
||||
m_axis_enqueue_resp_tag,
|
||||
m_axis_enqueue_resp_op_tag,
|
||||
m_axis_enqueue_resp_full,
|
||||
m_axis_enqueue_resp_error,
|
||||
m_axis_enqueue_resp_valid,
|
||||
s_axis_enqueue_commit_ready,
|
||||
m_axis_event,
|
||||
m_axis_event_source,
|
||||
m_axis_event_valid,
|
||||
s_axil_awready,
|
||||
s_axil_wready,
|
||||
s_axil_bresp,
|
||||
s_axil_bvalid,
|
||||
s_axil_arready,
|
||||
s_axil_rdata,
|
||||
s_axil_rresp,
|
||||
s_axil_rvalid
|
||||
);
|
||||
|
||||
// dump file
|
||||
$dumpfile("test_cpl_queue_manager.lxt");
|
||||
$dumpvars(0, test_cpl_queue_manager);
|
||||
end
|
||||
|
||||
cpl_queue_manager #(
|
||||
.ADDR_WIDTH(ADDR_WIDTH),
|
||||
.REQ_TAG_WIDTH(REQ_TAG_WIDTH),
|
||||
.OP_TABLE_SIZE(OP_TABLE_SIZE),
|
||||
.OP_TAG_WIDTH(OP_TAG_WIDTH),
|
||||
.QUEUE_INDEX_WIDTH(QUEUE_INDEX_WIDTH),
|
||||
.EVENT_WIDTH(EVENT_WIDTH),
|
||||
.QUEUE_PTR_WIDTH(QUEUE_PTR_WIDTH),
|
||||
.LOG_QUEUE_SIZE_WIDTH(LOG_QUEUE_SIZE_WIDTH),
|
||||
.CPL_SIZE(CPL_SIZE),
|
||||
.PIPELINE(PIPELINE),
|
||||
.AXIL_DATA_WIDTH(AXIL_DATA_WIDTH),
|
||||
.AXIL_ADDR_WIDTH(AXIL_ADDR_WIDTH),
|
||||
.AXIL_STRB_WIDTH(AXIL_STRB_WIDTH)
|
||||
)
|
||||
UUT (
|
||||
.clk(clk),
|
||||
.rst(rst),
|
||||
.s_axis_enqueue_req_queue(s_axis_enqueue_req_queue),
|
||||
.s_axis_enqueue_req_tag(s_axis_enqueue_req_tag),
|
||||
.s_axis_enqueue_req_valid(s_axis_enqueue_req_valid),
|
||||
.s_axis_enqueue_req_ready(s_axis_enqueue_req_ready),
|
||||
.m_axis_enqueue_resp_queue(m_axis_enqueue_resp_queue),
|
||||
.m_axis_enqueue_resp_ptr(m_axis_enqueue_resp_ptr),
|
||||
.m_axis_enqueue_resp_addr(m_axis_enqueue_resp_addr),
|
||||
.m_axis_enqueue_resp_event(m_axis_enqueue_resp_event),
|
||||
.m_axis_enqueue_resp_tag(m_axis_enqueue_resp_tag),
|
||||
.m_axis_enqueue_resp_op_tag(m_axis_enqueue_resp_op_tag),
|
||||
.m_axis_enqueue_resp_full(m_axis_enqueue_resp_full),
|
||||
.m_axis_enqueue_resp_error(m_axis_enqueue_resp_error),
|
||||
.m_axis_enqueue_resp_valid(m_axis_enqueue_resp_valid),
|
||||
.m_axis_enqueue_resp_ready(m_axis_enqueue_resp_ready),
|
||||
.s_axis_enqueue_commit_op_tag(s_axis_enqueue_commit_op_tag),
|
||||
.s_axis_enqueue_commit_valid(s_axis_enqueue_commit_valid),
|
||||
.s_axis_enqueue_commit_ready(s_axis_enqueue_commit_ready),
|
||||
.m_axis_event(m_axis_event),
|
||||
.m_axis_event_source(m_axis_event_source),
|
||||
.m_axis_event_valid(m_axis_event_valid),
|
||||
.s_axil_awaddr(s_axil_awaddr),
|
||||
.s_axil_awprot(s_axil_awprot),
|
||||
.s_axil_awvalid(s_axil_awvalid),
|
||||
.s_axil_awready(s_axil_awready),
|
||||
.s_axil_wdata(s_axil_wdata),
|
||||
.s_axil_wstrb(s_axil_wstrb),
|
||||
.s_axil_wvalid(s_axil_wvalid),
|
||||
.s_axil_wready(s_axil_wready),
|
||||
.s_axil_bresp(s_axil_bresp),
|
||||
.s_axil_bvalid(s_axil_bvalid),
|
||||
.s_axil_bready(s_axil_bready),
|
||||
.s_axil_araddr(s_axil_araddr),
|
||||
.s_axil_arprot(s_axil_arprot),
|
||||
.s_axil_arvalid(s_axil_arvalid),
|
||||
.s_axil_arready(s_axil_arready),
|
||||
.s_axil_rdata(s_axil_rdata),
|
||||
.s_axil_rresp(s_axil_rresp),
|
||||
.s_axil_rvalid(s_axil_rvalid),
|
||||
.s_axil_rready(s_axil_rready),
|
||||
.enable(enable)
|
||||
);
|
||||
|
||||
endmodule
|
@ -1,494 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
|
||||
Copyright 2019, The Regents of the University of California.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
|
||||
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of The Regents of the University of California.
|
||||
|
||||
"""
|
||||
|
||||
from myhdl import *
|
||||
import os
|
||||
|
||||
import axil
|
||||
import axis_ep
|
||||
|
||||
import random
|
||||
import struct
|
||||
|
||||
module = 'queue_manager'
|
||||
testbench = 'test_%s' % module
|
||||
|
||||
srcs = []
|
||||
|
||||
srcs.append("../rtl/%s.v" % module)
|
||||
srcs.append("%s.v" % testbench)
|
||||
|
||||
src = ' '.join(srcs)
|
||||
|
||||
build_cmd = "iverilog -o %s.vvp %s" % (testbench, src)
|
||||
|
||||
def bench():
|
||||
|
||||
# Parameters
|
||||
ADDR_WIDTH = 64
|
||||
REQ_TAG_WIDTH = 8
|
||||
OP_TABLE_SIZE = 16
|
||||
OP_TAG_WIDTH = 8
|
||||
QUEUE_INDEX_WIDTH = 8
|
||||
CPL_INDEX_WIDTH = 8
|
||||
QUEUE_PTR_WIDTH = 16
|
||||
LOG_QUEUE_SIZE_WIDTH = 4
|
||||
DESC_SIZE = 16
|
||||
LOG_BLOCK_SIZE_WIDTH = 2
|
||||
PIPELINE = 2
|
||||
AXIL_DATA_WIDTH = 32
|
||||
AXIL_ADDR_WIDTH = 16
|
||||
AXIL_STRB_WIDTH = (AXIL_DATA_WIDTH/8)
|
||||
|
||||
# Inputs
|
||||
clk = Signal(bool(0))
|
||||
rst = Signal(bool(0))
|
||||
current_test = Signal(intbv(0)[8:])
|
||||
|
||||
s_axis_dequeue_req_queue = Signal(intbv(0)[QUEUE_INDEX_WIDTH:])
|
||||
s_axis_dequeue_req_tag = Signal(intbv(0)[REQ_TAG_WIDTH:])
|
||||
s_axis_dequeue_req_valid = Signal(bool(0))
|
||||
m_axis_dequeue_resp_ready = Signal(bool(0))
|
||||
s_axis_dequeue_commit_op_tag = Signal(intbv(0)[OP_TAG_WIDTH:])
|
||||
s_axis_dequeue_commit_valid = Signal(bool(0))
|
||||
s_axil_awaddr = Signal(intbv(0)[AXIL_ADDR_WIDTH:])
|
||||
s_axil_awprot = Signal(intbv(0)[3:])
|
||||
s_axil_awvalid = Signal(bool(0))
|
||||
s_axil_wdata = Signal(intbv(0)[AXIL_DATA_WIDTH:])
|
||||
s_axil_wstrb = Signal(intbv(0)[AXIL_STRB_WIDTH:])
|
||||
s_axil_wvalid = Signal(bool(0))
|
||||
s_axil_bready = Signal(bool(0))
|
||||
s_axil_araddr = Signal(intbv(0)[AXIL_ADDR_WIDTH:])
|
||||
s_axil_arprot = Signal(intbv(0)[3:])
|
||||
s_axil_arvalid = Signal(bool(0))
|
||||
s_axil_rready = Signal(bool(0))
|
||||
enable = Signal(bool(0))
|
||||
|
||||
# Outputs
|
||||
s_axis_dequeue_req_ready = Signal(bool(0))
|
||||
m_axis_dequeue_resp_queue = Signal(intbv(0)[QUEUE_INDEX_WIDTH:])
|
||||
m_axis_dequeue_resp_ptr = Signal(intbv(0)[QUEUE_PTR_WIDTH:])
|
||||
m_axis_dequeue_resp_addr = Signal(intbv(0)[ADDR_WIDTH:])
|
||||
m_axis_dequeue_resp_block_size = Signal(intbv(0)[LOG_BLOCK_SIZE_WIDTH:])
|
||||
m_axis_dequeue_resp_cpl = Signal(intbv(0)[CPL_INDEX_WIDTH:])
|
||||
m_axis_dequeue_resp_tag = Signal(intbv(0)[REQ_TAG_WIDTH:])
|
||||
m_axis_dequeue_resp_op_tag = Signal(intbv(0)[OP_TAG_WIDTH:])
|
||||
m_axis_dequeue_resp_empty = Signal(bool(0))
|
||||
m_axis_dequeue_resp_error = Signal(bool(0))
|
||||
m_axis_dequeue_resp_valid = Signal(bool(0))
|
||||
s_axis_dequeue_commit_ready = Signal(bool(0))
|
||||
m_axis_doorbell_queue = Signal(intbv(0)[QUEUE_INDEX_WIDTH:])
|
||||
m_axis_doorbell_valid = Signal(bool(0))
|
||||
s_axil_awready = Signal(bool(0))
|
||||
s_axil_wready = Signal(bool(0))
|
||||
s_axil_bresp = Signal(intbv(0)[2:])
|
||||
s_axil_bvalid = Signal(bool(0))
|
||||
s_axil_arready = Signal(bool(0))
|
||||
s_axil_rdata = Signal(intbv(0)[AXIL_DATA_WIDTH:])
|
||||
s_axil_rresp = Signal(intbv(0)[2:])
|
||||
s_axil_rvalid = Signal(bool(0))
|
||||
|
||||
# sources and sinks
|
||||
dequeue_req_source = axis_ep.AXIStreamSource()
|
||||
|
||||
dequeue_req_source_logic = dequeue_req_source.create_logic(
|
||||
clk,
|
||||
rst,
|
||||
tdata=(s_axis_dequeue_req_queue, s_axis_dequeue_req_tag),
|
||||
tvalid=s_axis_dequeue_req_valid,
|
||||
tready=s_axis_dequeue_req_ready,
|
||||
name='dequeue_req_source'
|
||||
)
|
||||
|
||||
dequeue_resp_sink = axis_ep.AXIStreamSink()
|
||||
|
||||
dequeue_resp_sink_logic = dequeue_resp_sink.create_logic(
|
||||
clk,
|
||||
rst,
|
||||
tdata=(m_axis_dequeue_resp_queue, m_axis_dequeue_resp_ptr, m_axis_dequeue_resp_addr, m_axis_dequeue_resp_block_size, m_axis_dequeue_resp_cpl, m_axis_dequeue_resp_tag, m_axis_dequeue_resp_op_tag, m_axis_dequeue_resp_empty, m_axis_dequeue_resp_error),
|
||||
tvalid=m_axis_dequeue_resp_valid,
|
||||
tready=m_axis_dequeue_resp_ready,
|
||||
name='dequeue_resp_sink'
|
||||
)
|
||||
|
||||
dequeue_commit_source = axis_ep.AXIStreamSource()
|
||||
|
||||
dequeue_commit_source_logic = dequeue_commit_source.create_logic(
|
||||
clk,
|
||||
rst,
|
||||
tdata=(s_axis_dequeue_commit_op_tag,),
|
||||
tvalid=s_axis_dequeue_commit_valid,
|
||||
tready=s_axis_dequeue_commit_ready,
|
||||
name='dequeue_commit_source'
|
||||
)
|
||||
|
||||
doorbell_sink = axis_ep.AXIStreamSink()
|
||||
|
||||
doorbell_sink_logic = doorbell_sink.create_logic(
|
||||
clk,
|
||||
rst,
|
||||
tdata=(m_axis_doorbell_queue,),
|
||||
tvalid=m_axis_doorbell_valid,
|
||||
name='doorbell_sink'
|
||||
)
|
||||
|
||||
# AXI4-Lite master
|
||||
axil_master_inst = axil.AXILiteMaster()
|
||||
axil_master_pause = Signal(bool(False))
|
||||
|
||||
axil_master_logic = axil_master_inst.create_logic(
|
||||
clk,
|
||||
rst,
|
||||
m_axil_awaddr=s_axil_awaddr,
|
||||
m_axil_awprot=s_axil_awprot,
|
||||
m_axil_awvalid=s_axil_awvalid,
|
||||
m_axil_awready=s_axil_awready,
|
||||
m_axil_wdata=s_axil_wdata,
|
||||
m_axil_wstrb=s_axil_wstrb,
|
||||
m_axil_wvalid=s_axil_wvalid,
|
||||
m_axil_wready=s_axil_wready,
|
||||
m_axil_bresp=s_axil_bresp,
|
||||
m_axil_bvalid=s_axil_bvalid,
|
||||
m_axil_bready=s_axil_bready,
|
||||
m_axil_araddr=s_axil_araddr,
|
||||
m_axil_arprot=s_axil_arprot,
|
||||
m_axil_arvalid=s_axil_arvalid,
|
||||
m_axil_arready=s_axil_arready,
|
||||
m_axil_rdata=s_axil_rdata,
|
||||
m_axil_rresp=s_axil_rresp,
|
||||
m_axil_rvalid=s_axil_rvalid,
|
||||
m_axil_rready=s_axil_rready,
|
||||
pause=axil_master_pause,
|
||||
name='master'
|
||||
)
|
||||
|
||||
# DUT
|
||||
if os.system(build_cmd):
|
||||
raise Exception("Error running build command")
|
||||
|
||||
dut = Cosimulation(
|
||||
"vvp -m myhdl %s.vvp -lxt2" % testbench,
|
||||
clk=clk,
|
||||
rst=rst,
|
||||
current_test=current_test,
|
||||
s_axis_dequeue_req_queue=s_axis_dequeue_req_queue,
|
||||
s_axis_dequeue_req_tag=s_axis_dequeue_req_tag,
|
||||
s_axis_dequeue_req_valid=s_axis_dequeue_req_valid,
|
||||
s_axis_dequeue_req_ready=s_axis_dequeue_req_ready,
|
||||
m_axis_dequeue_resp_queue=m_axis_dequeue_resp_queue,
|
||||
m_axis_dequeue_resp_ptr=m_axis_dequeue_resp_ptr,
|
||||
m_axis_dequeue_resp_addr=m_axis_dequeue_resp_addr,
|
||||
m_axis_dequeue_resp_block_size=m_axis_dequeue_resp_block_size,
|
||||
m_axis_dequeue_resp_cpl=m_axis_dequeue_resp_cpl,
|
||||
m_axis_dequeue_resp_tag=m_axis_dequeue_resp_tag,
|
||||
m_axis_dequeue_resp_op_tag=m_axis_dequeue_resp_op_tag,
|
||||
m_axis_dequeue_resp_empty=m_axis_dequeue_resp_empty,
|
||||
m_axis_dequeue_resp_error=m_axis_dequeue_resp_error,
|
||||
m_axis_dequeue_resp_valid=m_axis_dequeue_resp_valid,
|
||||
m_axis_dequeue_resp_ready=m_axis_dequeue_resp_ready,
|
||||
s_axis_dequeue_commit_op_tag=s_axis_dequeue_commit_op_tag,
|
||||
s_axis_dequeue_commit_valid=s_axis_dequeue_commit_valid,
|
||||
s_axis_dequeue_commit_ready=s_axis_dequeue_commit_ready,
|
||||
m_axis_doorbell_queue=m_axis_doorbell_queue,
|
||||
m_axis_doorbell_valid=m_axis_doorbell_valid,
|
||||
s_axil_awaddr=s_axil_awaddr,
|
||||
s_axil_awprot=s_axil_awprot,
|
||||
s_axil_awvalid=s_axil_awvalid,
|
||||
s_axil_awready=s_axil_awready,
|
||||
s_axil_wdata=s_axil_wdata,
|
||||
s_axil_wstrb=s_axil_wstrb,
|
||||
s_axil_wvalid=s_axil_wvalid,
|
||||
s_axil_wready=s_axil_wready,
|
||||
s_axil_bresp=s_axil_bresp,
|
||||
s_axil_bvalid=s_axil_bvalid,
|
||||
s_axil_bready=s_axil_bready,
|
||||
s_axil_araddr=s_axil_araddr,
|
||||
s_axil_arprot=s_axil_arprot,
|
||||
s_axil_arvalid=s_axil_arvalid,
|
||||
s_axil_arready=s_axil_arready,
|
||||
s_axil_rdata=s_axil_rdata,
|
||||
s_axil_rresp=s_axil_rresp,
|
||||
s_axil_rvalid=s_axil_rvalid,
|
||||
s_axil_rready=s_axil_rready,
|
||||
enable=enable
|
||||
)
|
||||
|
||||
@always(delay(4))
|
||||
def clkgen():
|
||||
clk.next = not clk
|
||||
|
||||
@instance
|
||||
def check():
|
||||
yield delay(100)
|
||||
yield clk.posedge
|
||||
rst.next = 1
|
||||
yield clk.posedge
|
||||
rst.next = 0
|
||||
yield clk.posedge
|
||||
yield delay(100)
|
||||
yield clk.posedge
|
||||
|
||||
# testbench stimulus
|
||||
|
||||
enable.next = 1
|
||||
|
||||
yield clk.posedge
|
||||
print("test 1: read and write queue configuration registers")
|
||||
current_test.next = 1
|
||||
|
||||
axil_master_inst.init_write(0*32+0, struct.pack('<Q', 0x8877665544332211)) # address
|
||||
axil_master_inst.init_write(0*32+8, struct.pack('<L', 0x00000004)) # active, log size
|
||||
axil_master_inst.init_write(0*32+12, struct.pack('<L', 0x00000001)) # completion queue index
|
||||
axil_master_inst.init_write(0*32+16, struct.pack('<L', 0x00000000)) # head pointer
|
||||
axil_master_inst.init_write(0*32+24, struct.pack('<L', 0x00000000)) # tail pointer
|
||||
axil_master_inst.init_write(0*32+8, struct.pack('<L', 0x80000004)) # active, log size
|
||||
|
||||
yield axil_master_inst.wait()
|
||||
yield clk.posedge
|
||||
|
||||
axil_master_inst.init_read(0*32+0, 8)
|
||||
axil_master_inst.init_read(0*32+8, 4)
|
||||
axil_master_inst.init_read(0*32+12, 4)
|
||||
|
||||
yield axil_master_inst.wait()
|
||||
yield clk.posedge
|
||||
|
||||
data = axil_master_inst.get_read_data()
|
||||
assert struct.unpack('<Q', data[1])[0] == 0x8877665544332211
|
||||
data = axil_master_inst.get_read_data()
|
||||
assert struct.unpack('<L', data[1])[0] == 0x80000004
|
||||
data = axil_master_inst.get_read_data()
|
||||
assert struct.unpack('<L', data[1])[0] == 0x00000001
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 2: enqueue and dequeue")
|
||||
current_test.next = 2
|
||||
|
||||
# increment head pointer
|
||||
axil_master_inst.init_read(0*32+16, 4) # head pointer
|
||||
yield axil_master_inst.wait()
|
||||
|
||||
data = axil_master_inst.get_read_data()
|
||||
head_ptr = struct.unpack('<L', data[1])[0]
|
||||
|
||||
axil_master_inst.init_write(0*32+16, struct.pack('<L', head_ptr + 1)) # head pointer
|
||||
|
||||
yield axil_master_inst.wait()
|
||||
yield clk.posedge
|
||||
|
||||
# check for doorbell event
|
||||
yield doorbell_sink.wait()
|
||||
db = doorbell_sink.recv()
|
||||
assert db.data[0][0] == 0
|
||||
|
||||
# read tail pointer
|
||||
axil_master_inst.init_read(0*32+24, 4) # tail pointer
|
||||
yield axil_master_inst.wait()
|
||||
|
||||
data = axil_master_inst.get_read_data()
|
||||
tail_ptr = struct.unpack('<L', data[1])[0]
|
||||
|
||||
# dequeue request
|
||||
dequeue_req_source.send([(0, 1)])
|
||||
|
||||
yield dequeue_resp_sink.wait()
|
||||
|
||||
resp = dequeue_resp_sink.recv()
|
||||
print(resp)
|
||||
|
||||
# dequeue commit
|
||||
dequeue_commit_source.send([(resp.data[0][6],)])
|
||||
|
||||
yield delay(100)
|
||||
|
||||
# read tail pointer
|
||||
axil_master_inst.init_read(0*32+24, 4) # tail pointer
|
||||
yield axil_master_inst.wait()
|
||||
|
||||
data = axil_master_inst.get_read_data()
|
||||
new_tail_ptr = struct.unpack('<L', data[1])[0]
|
||||
|
||||
assert new_tail_ptr - tail_ptr == 1
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 3: set up more queues")
|
||||
current_test.next = 3
|
||||
|
||||
axil_master_inst.init_write(0*32+8, struct.pack('<L', 0x00000004)) # active, log size
|
||||
axil_master_inst.init_write(0*32+0, struct.pack('<Q', 0x5555555555000000)) # address
|
||||
axil_master_inst.init_write(0*32+8, struct.pack('<L', 0x00000004)) # active, log size
|
||||
axil_master_inst.init_write(0*32+12, struct.pack('<L', 0x00000000)) # completion queue index
|
||||
axil_master_inst.init_write(0*32+16, struct.pack('<L', 0x0000fff0)) # head pointer
|
||||
axil_master_inst.init_write(0*32+24, struct.pack('<L', 0x0000fff0)) # tail pointer
|
||||
axil_master_inst.init_write(0*32+8, struct.pack('<L', 0x80000004)) # active, log size
|
||||
|
||||
axil_master_inst.init_write(1*32+8, struct.pack('<L', 0x00000004)) # active, log size
|
||||
axil_master_inst.init_write(1*32+0, struct.pack('<Q', 0x5555555555010000)) # address
|
||||
axil_master_inst.init_write(1*32+8, struct.pack('<L', 0x00000004)) # active, log size
|
||||
axil_master_inst.init_write(1*32+12, struct.pack('<L', 0x00000001)) # completion queue index
|
||||
axil_master_inst.init_write(1*32+16, struct.pack('<L', 0x0000fff0)) # head pointer
|
||||
axil_master_inst.init_write(1*32+24, struct.pack('<L', 0x0000fff0)) # tail pointer
|
||||
axil_master_inst.init_write(1*32+8, struct.pack('<L', 0x80000004)) # active, log size
|
||||
|
||||
axil_master_inst.init_write(2*32+8, struct.pack('<L', 0x00000004)) # active, log size
|
||||
axil_master_inst.init_write(2*32+0, struct.pack('<Q', 0x5555555555020000)) # address
|
||||
axil_master_inst.init_write(2*32+8, struct.pack('<L', 0x00000004)) # active, log size
|
||||
axil_master_inst.init_write(2*32+12, struct.pack('<L', 0x00000002)) # completion queue index
|
||||
axil_master_inst.init_write(2*32+16, struct.pack('<L', 0x0000fff0)) # head pointer
|
||||
axil_master_inst.init_write(2*32+24, struct.pack('<L', 0x0000fff0)) # tail pointer
|
||||
axil_master_inst.init_write(2*32+8, struct.pack('<L', 0x80000004)) # active, log size
|
||||
|
||||
axil_master_inst.init_write(3*32+8, struct.pack('<L', 0x00000004)) # active, log size
|
||||
axil_master_inst.init_write(3*32+0, struct.pack('<Q', 0x5555555555030000)) # address
|
||||
axil_master_inst.init_write(3*32+8, struct.pack('<L', 0x00000004)) # active, log size
|
||||
axil_master_inst.init_write(3*32+12, struct.pack('<L', 0x00000003)) # completion queue index
|
||||
axil_master_inst.init_write(3*32+16, struct.pack('<L', 0x0000fff0)) # head pointer
|
||||
axil_master_inst.init_write(3*32+24, struct.pack('<L', 0x0000fff0)) # tail pointer
|
||||
axil_master_inst.init_write(3*32+8, struct.pack('<L', 0x80000004)) # active, log size
|
||||
|
||||
yield axil_master_inst.wait()
|
||||
yield clk.posedge
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 4: multiple enqueue and dequeue")
|
||||
current_test.next = 4
|
||||
|
||||
current_tag = 1
|
||||
|
||||
queue_head_ptr = [0xfff0]*4
|
||||
queue_tail_ptr = [0xfff0]*4
|
||||
queue_depth = [0]*4
|
||||
queue_uncommit_depth = [0]*4
|
||||
|
||||
commit_list = []
|
||||
|
||||
random.seed(123456)
|
||||
|
||||
for i in range(50):
|
||||
# enqueue
|
||||
for k in range(random.randrange(8)):
|
||||
q = random.randrange(4)
|
||||
|
||||
if queue_depth[q] < 16:
|
||||
print("Enqueue into queue %d" % q)
|
||||
|
||||
# increment head pointer
|
||||
axil_master_inst.init_read(q*32+16, 4) # head pointer
|
||||
yield axil_master_inst.wait()
|
||||
|
||||
data = axil_master_inst.get_read_data()
|
||||
head_ptr = struct.unpack('<L', data[1])[0]
|
||||
|
||||
assert head_ptr == queue_head_ptr[q]
|
||||
|
||||
head_ptr = (head_ptr + 1) & 0xffff
|
||||
|
||||
queue_head_ptr[q] = head_ptr
|
||||
queue_depth[q] += 1
|
||||
queue_uncommit_depth[q] += 1
|
||||
|
||||
axil_master_inst.init_write(q*32+16, struct.pack('<L', head_ptr)) # head pointer
|
||||
yield axil_master_inst.wait()
|
||||
|
||||
# check doorbell event
|
||||
yield doorbell_sink.wait()
|
||||
db = doorbell_sink.recv()
|
||||
assert db.data[0][0] == q
|
||||
|
||||
# dequeue
|
||||
for k in range(random.randrange(8)):
|
||||
q = random.randrange(4)
|
||||
|
||||
if len(commit_list) < OP_TABLE_SIZE:
|
||||
print("Try dequeue from queue %d" % q)
|
||||
|
||||
# dequeue request
|
||||
dequeue_req_source.send([(q, current_tag)])
|
||||
|
||||
yield dequeue_resp_sink.wait()
|
||||
|
||||
resp = dequeue_resp_sink.recv()
|
||||
print(resp)
|
||||
|
||||
assert resp.data[0][0] == q
|
||||
assert resp.data[0][1] == queue_tail_ptr[q]
|
||||
assert (resp.data[0][2] >> 16) & 0xf == q
|
||||
assert (resp.data[0][2] >> 4) & 0xf == queue_tail_ptr[q] & 0xf
|
||||
assert resp.data[0][4] == q
|
||||
|
||||
assert resp.data[0][5] == current_tag # tag
|
||||
assert not resp.data[0][8] # error
|
||||
|
||||
if queue_uncommit_depth[q]:
|
||||
commit_list.append((q, resp.data[0][6]))
|
||||
queue_tail_ptr[q] = (queue_tail_ptr[q] + 1) & 0xffff
|
||||
queue_uncommit_depth[q] -= 1
|
||||
else:
|
||||
print("Queue was empty")
|
||||
assert resp.data[0][7] # empty
|
||||
|
||||
current_tag = (current_tag + 1) % 256
|
||||
|
||||
# commit
|
||||
#random.shuffle(commit_list)
|
||||
for k in range(random.randrange(8)):
|
||||
if commit_list:
|
||||
q, t = commit_list.pop(0)
|
||||
|
||||
print("Commit dequeue from queue %d" % q)
|
||||
|
||||
# dequeue commit
|
||||
dequeue_commit_source.send([(t,)])
|
||||
|
||||
queue_depth[q] -= 1
|
||||
|
||||
yield delay(100)
|
||||
|
||||
raise StopSimulation
|
||||
|
||||
return instances()
|
||||
|
||||
def test_bench():
|
||||
sim = Simulation(bench())
|
||||
sim.run()
|
||||
|
||||
if __name__ == '__main__':
|
||||
print("Running test...")
|
||||
test_bench()
|
@ -1,223 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright 2019, The Regents of the University of California.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
|
||||
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of The Regents of the University of California.
|
||||
|
||||
*/
|
||||
|
||||
// Language: Verilog 2001
|
||||
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
/*
|
||||
* Testbench for queue_manager
|
||||
*/
|
||||
module test_queue_manager;
|
||||
|
||||
// Parameters
|
||||
parameter ADDR_WIDTH = 64;
|
||||
parameter REQ_TAG_WIDTH = 8;
|
||||
parameter OP_TABLE_SIZE = 16;
|
||||
parameter OP_TAG_WIDTH = 8;
|
||||
parameter QUEUE_INDEX_WIDTH = 8;
|
||||
parameter CPL_INDEX_WIDTH = 8;
|
||||
parameter QUEUE_PTR_WIDTH = 16;
|
||||
parameter LOG_QUEUE_SIZE_WIDTH = 4;
|
||||
parameter DESC_SIZE = 16;
|
||||
parameter LOG_BLOCK_SIZE_WIDTH = 2;
|
||||
parameter PIPELINE = 2;
|
||||
parameter AXIL_DATA_WIDTH = 32;
|
||||
parameter AXIL_ADDR_WIDTH = 16;
|
||||
parameter AXIL_STRB_WIDTH = (AXIL_DATA_WIDTH/8);
|
||||
|
||||
// Inputs
|
||||
reg clk = 0;
|
||||
reg rst = 0;
|
||||
reg [7:0] current_test = 0;
|
||||
|
||||
reg [QUEUE_INDEX_WIDTH-1:0] s_axis_dequeue_req_queue = 0;
|
||||
reg [REQ_TAG_WIDTH-1:0] s_axis_dequeue_req_tag = 0;
|
||||
reg s_axis_dequeue_req_valid = 0;
|
||||
reg m_axis_dequeue_resp_ready = 0;
|
||||
reg [OP_TAG_WIDTH-1:0] s_axis_dequeue_commit_op_tag = 0;
|
||||
reg s_axis_dequeue_commit_valid = 0;
|
||||
reg [AXIL_ADDR_WIDTH-1:0] s_axil_awaddr = 0;
|
||||
reg [2:0] s_axil_awprot = 0;
|
||||
reg s_axil_awvalid = 0;
|
||||
reg [AXIL_DATA_WIDTH-1:0] s_axil_wdata = 0;
|
||||
reg [AXIL_STRB_WIDTH-1:0] s_axil_wstrb = 0;
|
||||
reg s_axil_wvalid = 0;
|
||||
reg s_axil_bready = 0;
|
||||
reg [AXIL_ADDR_WIDTH-1:0] s_axil_araddr = 0;
|
||||
reg [2:0] s_axil_arprot = 0;
|
||||
reg s_axil_arvalid = 0;
|
||||
reg s_axil_rready = 0;
|
||||
reg enable = 0;
|
||||
|
||||
// Outputs
|
||||
wire s_axis_dequeue_req_ready;
|
||||
wire [QUEUE_INDEX_WIDTH-1:0] m_axis_dequeue_resp_queue;
|
||||
wire [QUEUE_PTR_WIDTH-1:0] m_axis_dequeue_resp_ptr;
|
||||
wire [ADDR_WIDTH-1:0] m_axis_dequeue_resp_addr;
|
||||
wire [LOG_BLOCK_SIZE_WIDTH-1:0] m_axis_dequeue_resp_block_size;
|
||||
wire [CPL_INDEX_WIDTH-1:0] m_axis_dequeue_resp_cpl;
|
||||
wire [REQ_TAG_WIDTH-1:0] m_axis_dequeue_resp_tag;
|
||||
wire [OP_TAG_WIDTH-1:0] m_axis_dequeue_resp_op_tag;
|
||||
wire m_axis_dequeue_resp_empty;
|
||||
wire m_axis_dequeue_resp_error;
|
||||
wire m_axis_dequeue_resp_valid;
|
||||
wire s_axis_dequeue_commit_ready;
|
||||
wire [QUEUE_INDEX_WIDTH-1:0] m_axis_doorbell_queue;
|
||||
wire m_axis_doorbell_valid;
|
||||
wire s_axil_awready;
|
||||
wire s_axil_wready;
|
||||
wire [1:0] s_axil_bresp;
|
||||
wire s_axil_bvalid;
|
||||
wire s_axil_arready;
|
||||
wire [AXIL_DATA_WIDTH-1:0] s_axil_rdata;
|
||||
wire [1:0] s_axil_rresp;
|
||||
wire s_axil_rvalid;
|
||||
|
||||
initial begin
|
||||
// myhdl integration
|
||||
$from_myhdl(
|
||||
clk,
|
||||
rst,
|
||||
current_test,
|
||||
s_axis_dequeue_req_queue,
|
||||
s_axis_dequeue_req_tag,
|
||||
s_axis_dequeue_req_valid,
|
||||
m_axis_dequeue_resp_ready,
|
||||
s_axis_dequeue_commit_op_tag,
|
||||
s_axis_dequeue_commit_valid,
|
||||
s_axil_awaddr,
|
||||
s_axil_awprot,
|
||||
s_axil_awvalid,
|
||||
s_axil_wdata,
|
||||
s_axil_wstrb,
|
||||
s_axil_wvalid,
|
||||
s_axil_bready,
|
||||
s_axil_araddr,
|
||||
s_axil_arprot,
|
||||
s_axil_arvalid,
|
||||
s_axil_rready,
|
||||
enable
|
||||
);
|
||||
$to_myhdl(
|
||||
s_axis_dequeue_req_ready,
|
||||
m_axis_dequeue_resp_queue,
|
||||
m_axis_dequeue_resp_ptr,
|
||||
m_axis_dequeue_resp_addr,
|
||||
m_axis_dequeue_resp_block_size,
|
||||
m_axis_dequeue_resp_cpl,
|
||||
m_axis_dequeue_resp_tag,
|
||||
m_axis_dequeue_resp_op_tag,
|
||||
m_axis_dequeue_resp_empty,
|
||||
m_axis_dequeue_resp_error,
|
||||
m_axis_dequeue_resp_valid,
|
||||
s_axis_dequeue_commit_ready,
|
||||
m_axis_doorbell_queue,
|
||||
m_axis_doorbell_valid,
|
||||
s_axil_awready,
|
||||
s_axil_wready,
|
||||
s_axil_bresp,
|
||||
s_axil_bvalid,
|
||||
s_axil_arready,
|
||||
s_axil_rdata,
|
||||
s_axil_rresp,
|
||||
s_axil_rvalid
|
||||
);
|
||||
|
||||
// dump file
|
||||
$dumpfile("test_queue_manager.lxt");
|
||||
$dumpvars(0, test_queue_manager);
|
||||
end
|
||||
|
||||
queue_manager #(
|
||||
.ADDR_WIDTH(ADDR_WIDTH),
|
||||
.REQ_TAG_WIDTH(REQ_TAG_WIDTH),
|
||||
.OP_TABLE_SIZE(OP_TABLE_SIZE),
|
||||
.OP_TAG_WIDTH(OP_TAG_WIDTH),
|
||||
.QUEUE_INDEX_WIDTH(QUEUE_INDEX_WIDTH),
|
||||
.CPL_INDEX_WIDTH(CPL_INDEX_WIDTH),
|
||||
.QUEUE_PTR_WIDTH(QUEUE_PTR_WIDTH),
|
||||
.LOG_QUEUE_SIZE_WIDTH(LOG_QUEUE_SIZE_WIDTH),
|
||||
.DESC_SIZE(DESC_SIZE),
|
||||
.LOG_BLOCK_SIZE_WIDTH(LOG_BLOCK_SIZE_WIDTH),
|
||||
.PIPELINE(PIPELINE),
|
||||
.AXIL_DATA_WIDTH(AXIL_DATA_WIDTH),
|
||||
.AXIL_ADDR_WIDTH(AXIL_ADDR_WIDTH),
|
||||
.AXIL_STRB_WIDTH(AXIL_STRB_WIDTH)
|
||||
)
|
||||
UUT (
|
||||
.clk(clk),
|
||||
.rst(rst),
|
||||
.s_axis_dequeue_req_queue(s_axis_dequeue_req_queue),
|
||||
.s_axis_dequeue_req_tag(s_axis_dequeue_req_tag),
|
||||
.s_axis_dequeue_req_valid(s_axis_dequeue_req_valid),
|
||||
.s_axis_dequeue_req_ready(s_axis_dequeue_req_ready),
|
||||
.m_axis_dequeue_resp_queue(m_axis_dequeue_resp_queue),
|
||||
.m_axis_dequeue_resp_ptr(m_axis_dequeue_resp_ptr),
|
||||
.m_axis_dequeue_resp_addr(m_axis_dequeue_resp_addr),
|
||||
.m_axis_dequeue_resp_block_size(m_axis_dequeue_resp_block_size),
|
||||
.m_axis_dequeue_resp_cpl(m_axis_dequeue_resp_cpl),
|
||||
.m_axis_dequeue_resp_tag(m_axis_dequeue_resp_tag),
|
||||
.m_axis_dequeue_resp_op_tag(m_axis_dequeue_resp_op_tag),
|
||||
.m_axis_dequeue_resp_empty(m_axis_dequeue_resp_empty),
|
||||
.m_axis_dequeue_resp_error(m_axis_dequeue_resp_error),
|
||||
.m_axis_dequeue_resp_valid(m_axis_dequeue_resp_valid),
|
||||
.m_axis_dequeue_resp_ready(m_axis_dequeue_resp_ready),
|
||||
.s_axis_dequeue_commit_op_tag(s_axis_dequeue_commit_op_tag),
|
||||
.s_axis_dequeue_commit_valid(s_axis_dequeue_commit_valid),
|
||||
.s_axis_dequeue_commit_ready(s_axis_dequeue_commit_ready),
|
||||
.m_axis_doorbell_queue(m_axis_doorbell_queue),
|
||||
.m_axis_doorbell_valid(m_axis_doorbell_valid),
|
||||
.s_axil_awaddr(s_axil_awaddr),
|
||||
.s_axil_awprot(s_axil_awprot),
|
||||
.s_axil_awvalid(s_axil_awvalid),
|
||||
.s_axil_awready(s_axil_awready),
|
||||
.s_axil_wdata(s_axil_wdata),
|
||||
.s_axil_wstrb(s_axil_wstrb),
|
||||
.s_axil_wvalid(s_axil_wvalid),
|
||||
.s_axil_wready(s_axil_wready),
|
||||
.s_axil_bresp(s_axil_bresp),
|
||||
.s_axil_bvalid(s_axil_bvalid),
|
||||
.s_axil_bready(s_axil_bready),
|
||||
.s_axil_araddr(s_axil_araddr),
|
||||
.s_axil_arprot(s_axil_arprot),
|
||||
.s_axil_arvalid(s_axil_arvalid),
|
||||
.s_axil_arready(s_axil_arready),
|
||||
.s_axil_rdata(s_axil_rdata),
|
||||
.s_axil_rresp(s_axil_rresp),
|
||||
.s_axil_rvalid(s_axil_rvalid),
|
||||
.s_axil_rready(s_axil_rready),
|
||||
.enable(enable)
|
||||
);
|
||||
|
||||
endmodule
|
@ -1,322 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
|
||||
Copyright 2019, The Regents of the University of California.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
|
||||
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of The Regents of the University of California.
|
||||
|
||||
"""
|
||||
|
||||
from myhdl import *
|
||||
import os
|
||||
|
||||
import axis_ep
|
||||
import eth_ep
|
||||
|
||||
module = 'rx_checksum'
|
||||
testbench = 'test_%s_256' % module
|
||||
|
||||
srcs = []
|
||||
|
||||
srcs.append("../rtl/%s.v" % module)
|
||||
srcs.append("%s.v" % testbench)
|
||||
|
||||
src = ' '.join(srcs)
|
||||
|
||||
build_cmd = "iverilog -o %s.vvp %s" % (testbench, src)
|
||||
|
||||
def frame_checksum(frame):
|
||||
data = bytearray()
|
||||
if isinstance(frame, eth_ep.EthFrame):
|
||||
data = frame.payload.data
|
||||
elif isinstance(frame, axis_ep.AXIStreamFrame):
|
||||
data = frame.data[14:]
|
||||
else:
|
||||
return None
|
||||
|
||||
csum = 0
|
||||
odd = False
|
||||
|
||||
for b in data:
|
||||
if odd:
|
||||
csum += b
|
||||
else:
|
||||
csum += b << 8
|
||||
odd = not odd
|
||||
|
||||
csum = (csum & 0xffff) + (csum >> 16)
|
||||
csum = (csum & 0xffff) + (csum >> 16)
|
||||
|
||||
return csum
|
||||
|
||||
def bench():
|
||||
|
||||
# Parameters
|
||||
DATA_WIDTH = 256
|
||||
KEEP_WIDTH = (DATA_WIDTH/8)
|
||||
|
||||
# Inputs
|
||||
clk = Signal(bool(0))
|
||||
rst = Signal(bool(0))
|
||||
current_test = Signal(intbv(0)[8:])
|
||||
|
||||
s_axis_tdata = Signal(intbv(0)[DATA_WIDTH:])
|
||||
s_axis_tkeep = Signal(intbv(0)[KEEP_WIDTH:])
|
||||
s_axis_tvalid = Signal(bool(0))
|
||||
s_axis_tlast = Signal(bool(0))
|
||||
|
||||
# Outputs
|
||||
m_axis_csum = Signal(intbv(0)[16:])
|
||||
m_axis_csum_valid = Signal(bool(0))
|
||||
|
||||
# sources and sinks
|
||||
source_pause = Signal(bool(0))
|
||||
|
||||
source = axis_ep.AXIStreamSource()
|
||||
|
||||
source_logic = source.create_logic(
|
||||
clk,
|
||||
rst,
|
||||
tdata=s_axis_tdata,
|
||||
tkeep=s_axis_tkeep,
|
||||
tvalid=s_axis_tvalid,
|
||||
tlast=s_axis_tlast,
|
||||
pause=source_pause,
|
||||
name='source'
|
||||
)
|
||||
|
||||
sink = axis_ep.AXIStreamSink()
|
||||
|
||||
sink_logic = sink.create_logic(
|
||||
clk,
|
||||
rst,
|
||||
tdata=(m_axis_csum,),
|
||||
tvalid=m_axis_csum_valid,
|
||||
name='sink'
|
||||
)
|
||||
|
||||
# DUT
|
||||
if os.system(build_cmd):
|
||||
raise Exception("Error running build command")
|
||||
|
||||
dut = Cosimulation(
|
||||
"vvp -m myhdl %s.vvp -lxt2" % testbench,
|
||||
clk=clk,
|
||||
rst=rst,
|
||||
current_test=current_test,
|
||||
s_axis_tdata=s_axis_tdata,
|
||||
s_axis_tkeep=s_axis_tkeep,
|
||||
s_axis_tvalid=s_axis_tvalid,
|
||||
s_axis_tlast=s_axis_tlast,
|
||||
m_axis_csum=m_axis_csum,
|
||||
m_axis_csum_valid=m_axis_csum_valid
|
||||
)
|
||||
|
||||
@always(delay(4))
|
||||
def clkgen():
|
||||
clk.next = not clk
|
||||
|
||||
def wait_normal():
|
||||
while s_axis_tvalid:
|
||||
yield clk.posedge
|
||||
|
||||
def wait_pause_source():
|
||||
while s_axis_tvalid:
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
source_pause.next = False
|
||||
yield clk.posedge
|
||||
source_pause.next = True
|
||||
yield clk.posedge
|
||||
|
||||
source_pause.next = False
|
||||
|
||||
@instance
|
||||
def check():
|
||||
yield delay(100)
|
||||
yield clk.posedge
|
||||
rst.next = 1
|
||||
yield clk.posedge
|
||||
rst.next = 0
|
||||
yield clk.posedge
|
||||
yield delay(100)
|
||||
yield clk.posedge
|
||||
|
||||
# testbench stimulus
|
||||
|
||||
for payload_len in list(range(1, 128)) + list([1024, 1500, 9000, 9214]):
|
||||
yield clk.posedge
|
||||
print("test 1: test packet, length %d" % payload_len)
|
||||
current_test.next = 1
|
||||
|
||||
test_frame = eth_ep.EthFrame()
|
||||
test_frame.eth_dest_mac = 0xDAD1D2D3D4D5
|
||||
test_frame.eth_src_mac = 0x5A5152535455
|
||||
test_frame.eth_type = 0x8000
|
||||
test_frame.payload = bytearray((x%256 for x in range(payload_len)))
|
||||
|
||||
axis_frame = test_frame.build_axis()
|
||||
|
||||
for wait in wait_normal, wait_pause_source:
|
||||
source.send(axis_frame)
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
yield wait()
|
||||
|
||||
yield sink.wait()
|
||||
rx_csum = sink.recv().data[0][0]
|
||||
print(hex(rx_csum))
|
||||
|
||||
csum = frame_checksum(test_frame)
|
||||
print(hex(csum))
|
||||
|
||||
assert rx_csum == csum
|
||||
|
||||
assert sink.empty()
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 2: back-to-back packets, length %d" % payload_len)
|
||||
current_test.next = 2
|
||||
|
||||
test_frame1 = eth_ep.EthFrame()
|
||||
test_frame1.eth_dest_mac = 0xDAD1D2D3D4D5
|
||||
test_frame1.eth_src_mac = 0x5A5152535455
|
||||
test_frame1.eth_type = 0x8000
|
||||
test_frame1.payload = bytearray((x%256 for x in range(payload_len)))
|
||||
test_frame2 = eth_ep.EthFrame()
|
||||
test_frame2.eth_dest_mac = 0xDAD1D2D3D4D5
|
||||
test_frame2.eth_src_mac = 0x5A5152535455
|
||||
test_frame2.eth_type = 0x8000
|
||||
test_frame2.payload = bytearray((~x%256 for x in range(payload_len)))
|
||||
|
||||
axis_frame1 = test_frame1.build_axis()
|
||||
axis_frame2 = test_frame2.build_axis()
|
||||
|
||||
for wait in wait_normal, wait_pause_source:
|
||||
source.send(axis_frame1)
|
||||
source.send(axis_frame2)
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
yield wait()
|
||||
|
||||
yield sink.wait()
|
||||
rx_csum = sink.recv().data[0][0]
|
||||
print(hex(rx_csum))
|
||||
|
||||
csum = frame_checksum(test_frame1)
|
||||
print(hex(csum))
|
||||
|
||||
assert rx_csum == csum
|
||||
|
||||
yield sink.wait()
|
||||
rx_csum = sink.recv().data[0][0]
|
||||
print(hex(rx_csum))
|
||||
|
||||
csum = frame_checksum(test_frame2)
|
||||
print(hex(csum))
|
||||
|
||||
assert rx_csum == csum
|
||||
|
||||
assert sink.empty()
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 3: overflow test")
|
||||
current_test.next = 3
|
||||
|
||||
axis_frame = axis_ep.AXIStreamFrame(bytearray([0xff]*10240))
|
||||
|
||||
for wait in wait_normal, wait_pause_source:
|
||||
source.send(axis_frame)
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
yield wait()
|
||||
|
||||
yield sink.wait()
|
||||
rx_csum = sink.recv().data[0][0]
|
||||
print(hex(rx_csum))
|
||||
|
||||
csum = frame_checksum(axis_frame)
|
||||
print(hex(csum))
|
||||
|
||||
assert rx_csum == csum
|
||||
|
||||
assert sink.empty()
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 4: checksum test")
|
||||
current_test.next = 4
|
||||
|
||||
test_frame = eth_ep.EthFrame()
|
||||
test_frame.eth_dest_mac = 0xDA0203040506
|
||||
test_frame.eth_src_mac = 0xCA0203040506
|
||||
test_frame.eth_type = 0x005a
|
||||
test_frame.payload = b'\xab\xcd'+bytearray(range(20, 108))
|
||||
|
||||
axis_frame = test_frame.build_axis()
|
||||
|
||||
for wait in wait_normal, wait_pause_source:
|
||||
source.send(axis_frame)
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
yield wait()
|
||||
|
||||
yield sink.wait()
|
||||
rx_csum = sink.recv().data[0][0]
|
||||
print(hex(rx_csum))
|
||||
|
||||
csum = frame_checksum(test_frame)
|
||||
print(hex(csum))
|
||||
|
||||
assert csum == 0x8ad8
|
||||
assert rx_csum == csum
|
||||
|
||||
assert sink.empty()
|
||||
|
||||
yield delay(100)
|
||||
|
||||
raise StopSimulation
|
||||
|
||||
return instances()
|
||||
|
||||
def test_bench():
|
||||
sim = Simulation(bench())
|
||||
sim.run()
|
||||
|
||||
if __name__ == '__main__':
|
||||
print("Running test...")
|
||||
test_bench()
|
@ -1,97 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright 2019, The Regents of the University of California.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
|
||||
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of The Regents of the University of California.
|
||||
|
||||
*/
|
||||
|
||||
// Language: Verilog 2001
|
||||
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
/*
|
||||
* Testbench for rx_checksum
|
||||
*/
|
||||
module test_rx_checksum_256;
|
||||
|
||||
// Parameters
|
||||
parameter DATA_WIDTH = 256;
|
||||
parameter KEEP_WIDTH = (DATA_WIDTH/8);
|
||||
|
||||
// Inputs
|
||||
reg clk = 0;
|
||||
reg rst = 0;
|
||||
reg [7:0] current_test = 0;
|
||||
|
||||
reg [DATA_WIDTH-1:0] s_axis_tdata = 0;
|
||||
reg [KEEP_WIDTH-1:0] s_axis_tkeep = 0;
|
||||
reg s_axis_tvalid = 0;
|
||||
reg s_axis_tlast = 0;
|
||||
|
||||
// Outputs
|
||||
wire [15:0] m_axis_csum;
|
||||
wire m_axis_csum_valid;
|
||||
|
||||
initial begin
|
||||
// myhdl integration
|
||||
$from_myhdl(
|
||||
clk,
|
||||
rst,
|
||||
current_test,
|
||||
s_axis_tdata,
|
||||
s_axis_tkeep,
|
||||
s_axis_tvalid,
|
||||
s_axis_tlast
|
||||
);
|
||||
$to_myhdl(
|
||||
m_axis_csum,
|
||||
m_axis_csum_valid
|
||||
);
|
||||
|
||||
// dump file
|
||||
$dumpfile("test_rx_checksum_256.lxt");
|
||||
$dumpvars(0, test_rx_checksum_256);
|
||||
end
|
||||
|
||||
rx_checksum #(
|
||||
.DATA_WIDTH(DATA_WIDTH),
|
||||
.KEEP_WIDTH(KEEP_WIDTH)
|
||||
)
|
||||
UUT (
|
||||
.clk(clk),
|
||||
.rst(rst),
|
||||
.s_axis_tdata(s_axis_tdata),
|
||||
.s_axis_tkeep(s_axis_tkeep),
|
||||
.s_axis_tvalid(s_axis_tvalid),
|
||||
.s_axis_tlast(s_axis_tlast),
|
||||
.m_axis_csum(m_axis_csum),
|
||||
.m_axis_csum_valid(m_axis_csum_valid)
|
||||
);
|
||||
|
||||
endmodule
|
@ -1,322 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
|
||||
Copyright 2019, The Regents of the University of California.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
|
||||
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of The Regents of the University of California.
|
||||
|
||||
"""
|
||||
|
||||
from myhdl import *
|
||||
import os
|
||||
|
||||
import axis_ep
|
||||
import eth_ep
|
||||
|
||||
module = 'rx_checksum'
|
||||
testbench = 'test_%s_64' % module
|
||||
|
||||
srcs = []
|
||||
|
||||
srcs.append("../rtl/%s.v" % module)
|
||||
srcs.append("%s.v" % testbench)
|
||||
|
||||
src = ' '.join(srcs)
|
||||
|
||||
build_cmd = "iverilog -o %s.vvp %s" % (testbench, src)
|
||||
|
||||
def frame_checksum(frame):
|
||||
data = bytearray()
|
||||
if isinstance(frame, eth_ep.EthFrame):
|
||||
data = frame.payload.data
|
||||
elif isinstance(frame, axis_ep.AXIStreamFrame):
|
||||
data = frame.data[14:]
|
||||
else:
|
||||
return None
|
||||
|
||||
csum = 0
|
||||
odd = False
|
||||
|
||||
for b in data:
|
||||
if odd:
|
||||
csum += b
|
||||
else:
|
||||
csum += b << 8
|
||||
odd = not odd
|
||||
|
||||
csum = (csum & 0xffff) + (csum >> 16)
|
||||
csum = (csum & 0xffff) + (csum >> 16)
|
||||
|
||||
return csum
|
||||
|
||||
def bench():
|
||||
|
||||
# Parameters
|
||||
DATA_WIDTH = 64
|
||||
KEEP_WIDTH = (DATA_WIDTH/8)
|
||||
|
||||
# Inputs
|
||||
clk = Signal(bool(0))
|
||||
rst = Signal(bool(0))
|
||||
current_test = Signal(intbv(0)[8:])
|
||||
|
||||
s_axis_tdata = Signal(intbv(0)[DATA_WIDTH:])
|
||||
s_axis_tkeep = Signal(intbv(0)[KEEP_WIDTH:])
|
||||
s_axis_tvalid = Signal(bool(0))
|
||||
s_axis_tlast = Signal(bool(0))
|
||||
|
||||
# Outputs
|
||||
m_axis_csum = Signal(intbv(0)[16:])
|
||||
m_axis_csum_valid = Signal(bool(0))
|
||||
|
||||
# sources and sinks
|
||||
source_pause = Signal(bool(0))
|
||||
|
||||
source = axis_ep.AXIStreamSource()
|
||||
|
||||
source_logic = source.create_logic(
|
||||
clk,
|
||||
rst,
|
||||
tdata=s_axis_tdata,
|
||||
tkeep=s_axis_tkeep,
|
||||
tvalid=s_axis_tvalid,
|
||||
tlast=s_axis_tlast,
|
||||
pause=source_pause,
|
||||
name='source'
|
||||
)
|
||||
|
||||
sink = axis_ep.AXIStreamSink()
|
||||
|
||||
sink_logic = sink.create_logic(
|
||||
clk,
|
||||
rst,
|
||||
tdata=(m_axis_csum,),
|
||||
tvalid=m_axis_csum_valid,
|
||||
name='sink'
|
||||
)
|
||||
|
||||
# DUT
|
||||
if os.system(build_cmd):
|
||||
raise Exception("Error running build command")
|
||||
|
||||
dut = Cosimulation(
|
||||
"vvp -m myhdl %s.vvp -lxt2" % testbench,
|
||||
clk=clk,
|
||||
rst=rst,
|
||||
current_test=current_test,
|
||||
s_axis_tdata=s_axis_tdata,
|
||||
s_axis_tkeep=s_axis_tkeep,
|
||||
s_axis_tvalid=s_axis_tvalid,
|
||||
s_axis_tlast=s_axis_tlast,
|
||||
m_axis_csum=m_axis_csum,
|
||||
m_axis_csum_valid=m_axis_csum_valid
|
||||
)
|
||||
|
||||
@always(delay(4))
|
||||
def clkgen():
|
||||
clk.next = not clk
|
||||
|
||||
def wait_normal():
|
||||
while s_axis_tvalid:
|
||||
yield clk.posedge
|
||||
|
||||
def wait_pause_source():
|
||||
while s_axis_tvalid:
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
source_pause.next = False
|
||||
yield clk.posedge
|
||||
source_pause.next = True
|
||||
yield clk.posedge
|
||||
|
||||
source_pause.next = False
|
||||
|
||||
@instance
|
||||
def check():
|
||||
yield delay(100)
|
||||
yield clk.posedge
|
||||
rst.next = 1
|
||||
yield clk.posedge
|
||||
rst.next = 0
|
||||
yield clk.posedge
|
||||
yield delay(100)
|
||||
yield clk.posedge
|
||||
|
||||
# testbench stimulus
|
||||
|
||||
for payload_len in list(range(1, 128)) + list([1024, 1500, 9000, 9214]):
|
||||
yield clk.posedge
|
||||
print("test 1: test packet, length %d" % payload_len)
|
||||
current_test.next = 1
|
||||
|
||||
test_frame = eth_ep.EthFrame()
|
||||
test_frame.eth_dest_mac = 0xDAD1D2D3D4D5
|
||||
test_frame.eth_src_mac = 0x5A5152535455
|
||||
test_frame.eth_type = 0x8000
|
||||
test_frame.payload = bytearray((x%256 for x in range(payload_len)))
|
||||
|
||||
axis_frame = test_frame.build_axis()
|
||||
|
||||
for wait in wait_normal, wait_pause_source:
|
||||
source.send(axis_frame)
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
yield wait()
|
||||
|
||||
yield sink.wait()
|
||||
rx_csum = sink.recv().data[0][0]
|
||||
print(hex(rx_csum))
|
||||
|
||||
csum = frame_checksum(test_frame)
|
||||
print(hex(csum))
|
||||
|
||||
assert rx_csum == csum
|
||||
|
||||
assert sink.empty()
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 2: back-to-back packets, length %d" % payload_len)
|
||||
current_test.next = 2
|
||||
|
||||
test_frame1 = eth_ep.EthFrame()
|
||||
test_frame1.eth_dest_mac = 0xDAD1D2D3D4D5
|
||||
test_frame1.eth_src_mac = 0x5A5152535455
|
||||
test_frame1.eth_type = 0x8000
|
||||
test_frame1.payload = bytearray((x%256 for x in range(payload_len)))
|
||||
test_frame2 = eth_ep.EthFrame()
|
||||
test_frame2.eth_dest_mac = 0xDAD1D2D3D4D5
|
||||
test_frame2.eth_src_mac = 0x5A5152535455
|
||||
test_frame2.eth_type = 0x8000
|
||||
test_frame2.payload = bytearray((~x%256 for x in range(payload_len)))
|
||||
|
||||
axis_frame1 = test_frame1.build_axis()
|
||||
axis_frame2 = test_frame2.build_axis()
|
||||
|
||||
for wait in wait_normal, wait_pause_source:
|
||||
source.send(axis_frame1)
|
||||
source.send(axis_frame2)
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
yield wait()
|
||||
|
||||
yield sink.wait()
|
||||
rx_csum = sink.recv().data[0][0]
|
||||
print(hex(rx_csum))
|
||||
|
||||
csum = frame_checksum(test_frame1)
|
||||
print(hex(csum))
|
||||
|
||||
assert rx_csum == csum
|
||||
|
||||
yield sink.wait()
|
||||
rx_csum = sink.recv().data[0][0]
|
||||
print(hex(rx_csum))
|
||||
|
||||
csum = frame_checksum(test_frame2)
|
||||
print(hex(csum))
|
||||
|
||||
assert rx_csum == csum
|
||||
|
||||
assert sink.empty()
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 3: overflow test")
|
||||
current_test.next = 3
|
||||
|
||||
axis_frame = axis_ep.AXIStreamFrame(bytearray([0xff]*10240))
|
||||
|
||||
for wait in wait_normal, wait_pause_source:
|
||||
source.send(axis_frame)
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
yield wait()
|
||||
|
||||
yield sink.wait()
|
||||
rx_csum = sink.recv().data[0][0]
|
||||
print(hex(rx_csum))
|
||||
|
||||
csum = frame_checksum(axis_frame)
|
||||
print(hex(csum))
|
||||
|
||||
assert rx_csum == csum
|
||||
|
||||
assert sink.empty()
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 4: checksum test")
|
||||
current_test.next = 4
|
||||
|
||||
test_frame = eth_ep.EthFrame()
|
||||
test_frame.eth_dest_mac = 0xDA0203040506
|
||||
test_frame.eth_src_mac = 0xCA0203040506
|
||||
test_frame.eth_type = 0x005a
|
||||
test_frame.payload = b'\xab\xcd'+bytearray(range(20, 108))
|
||||
|
||||
axis_frame = test_frame.build_axis()
|
||||
|
||||
for wait in wait_normal, wait_pause_source:
|
||||
source.send(axis_frame)
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
yield wait()
|
||||
|
||||
yield sink.wait()
|
||||
rx_csum = sink.recv().data[0][0]
|
||||
print(hex(rx_csum))
|
||||
|
||||
csum = frame_checksum(test_frame)
|
||||
print(hex(csum))
|
||||
|
||||
assert csum == 0x8ad8
|
||||
assert rx_csum == csum
|
||||
|
||||
assert sink.empty()
|
||||
|
||||
yield delay(100)
|
||||
|
||||
raise StopSimulation
|
||||
|
||||
return instances()
|
||||
|
||||
def test_bench():
|
||||
sim = Simulation(bench())
|
||||
sim.run()
|
||||
|
||||
if __name__ == '__main__':
|
||||
print("Running test...")
|
||||
test_bench()
|
@ -1,97 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright 2019, The Regents of the University of California.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
|
||||
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of The Regents of the University of California.
|
||||
|
||||
*/
|
||||
|
||||
// Language: Verilog 2001
|
||||
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
/*
|
||||
* Testbench for rx_checksum
|
||||
*/
|
||||
module test_rx_checksum_64;
|
||||
|
||||
// Parameters
|
||||
parameter DATA_WIDTH = 64;
|
||||
parameter KEEP_WIDTH = (DATA_WIDTH/8);
|
||||
|
||||
// Inputs
|
||||
reg clk = 0;
|
||||
reg rst = 0;
|
||||
reg [7:0] current_test = 0;
|
||||
|
||||
reg [DATA_WIDTH-1:0] s_axis_tdata = 0;
|
||||
reg [KEEP_WIDTH-1:0] s_axis_tkeep = 0;
|
||||
reg s_axis_tvalid = 0;
|
||||
reg s_axis_tlast = 0;
|
||||
|
||||
// Outputs
|
||||
wire [15:0] m_axis_csum;
|
||||
wire m_axis_csum_valid;
|
||||
|
||||
initial begin
|
||||
// myhdl integration
|
||||
$from_myhdl(
|
||||
clk,
|
||||
rst,
|
||||
current_test,
|
||||
s_axis_tdata,
|
||||
s_axis_tkeep,
|
||||
s_axis_tvalid,
|
||||
s_axis_tlast
|
||||
);
|
||||
$to_myhdl(
|
||||
m_axis_csum,
|
||||
m_axis_csum_valid
|
||||
);
|
||||
|
||||
// dump file
|
||||
$dumpfile("test_rx_checksum_64.lxt");
|
||||
$dumpvars(0, test_rx_checksum_64);
|
||||
end
|
||||
|
||||
rx_checksum #(
|
||||
.DATA_WIDTH(DATA_WIDTH),
|
||||
.KEEP_WIDTH(KEEP_WIDTH)
|
||||
)
|
||||
UUT (
|
||||
.clk(clk),
|
||||
.rst(rst),
|
||||
.s_axis_tdata(s_axis_tdata),
|
||||
.s_axis_tkeep(s_axis_tkeep),
|
||||
.s_axis_tvalid(s_axis_tvalid),
|
||||
.s_axis_tlast(s_axis_tlast),
|
||||
.m_axis_csum(m_axis_csum),
|
||||
.m_axis_csum_valid(m_axis_csum_valid)
|
||||
);
|
||||
|
||||
endmodule
|
@ -1,536 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
|
||||
Copyright 2019, The Regents of the University of California.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
|
||||
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of The Regents of the University of California.
|
||||
|
||||
"""
|
||||
|
||||
from myhdl import *
|
||||
import os
|
||||
import ipaddress
|
||||
|
||||
import axis_ep
|
||||
import eth_ep
|
||||
import ip_ep
|
||||
import udp_ep
|
||||
|
||||
module = 'rx_hash'
|
||||
testbench = 'test_%s_256' % module
|
||||
|
||||
srcs = []
|
||||
|
||||
srcs.append("../rtl/%s.v" % module)
|
||||
srcs.append("%s.v" % testbench)
|
||||
|
||||
src = ' '.join(srcs)
|
||||
|
||||
build_cmd = "iverilog -o %s.vvp %s" % (testbench, src)
|
||||
|
||||
def hash_toep(data, key):
|
||||
k = len(key)*8-32
|
||||
key = int.from_bytes(key, 'big')
|
||||
|
||||
h = 0
|
||||
|
||||
for b in data:
|
||||
for i in range(8):
|
||||
if b & 0x80 >> i:
|
||||
h ^= (key >> k) & 0xffffffff
|
||||
k -= 1
|
||||
|
||||
return h
|
||||
|
||||
def tuple_pack(src_ip, dest_ip, src_port=None, dest_port=None):
|
||||
src_ip = ipaddress.ip_address(src_ip)
|
||||
dest_ip = ipaddress.ip_address(dest_ip)
|
||||
if src_ip.version == 6 or dest_ip.version == 6:
|
||||
src_ip = int(src_ip).to_bytes(16, 'big')
|
||||
dest_ip = int(dest_ip).to_bytes(16, 'big')
|
||||
else:
|
||||
src_ip = int(src_ip).to_bytes(4, 'big')
|
||||
dest_ip = int(dest_ip).to_bytes(4, 'big')
|
||||
data = src_ip+dest_ip
|
||||
if src_port is not None and dest_port is not None:
|
||||
data += src_port.to_bytes(2, 'big') + dest_port.to_bytes(2, 'big')
|
||||
return data
|
||||
|
||||
def bench():
|
||||
|
||||
# Parameters
|
||||
DATA_WIDTH = 256
|
||||
KEEP_WIDTH = (DATA_WIDTH/8)
|
||||
|
||||
# Inputs
|
||||
clk = Signal(bool(0))
|
||||
rst = Signal(bool(0))
|
||||
current_test = Signal(intbv(0)[8:])
|
||||
|
||||
s_axis_tdata = Signal(intbv(0)[DATA_WIDTH:])
|
||||
s_axis_tkeep = Signal(intbv(0)[KEEP_WIDTH:])
|
||||
s_axis_tvalid = Signal(bool(0))
|
||||
s_axis_tlast = Signal(bool(0))
|
||||
hash_key = Signal(intbv(0)[40*8:])
|
||||
|
||||
# Outputs
|
||||
m_axis_hash = Signal(intbv(0)[32:])
|
||||
m_axis_hash_type = Signal(intbv(0)[4:])
|
||||
m_axis_hash_valid = Signal(bool(0))
|
||||
|
||||
# sources and sinks
|
||||
source_pause = Signal(bool(0))
|
||||
|
||||
source = axis_ep.AXIStreamSource()
|
||||
|
||||
source_logic = source.create_logic(
|
||||
clk,
|
||||
rst,
|
||||
tdata=s_axis_tdata,
|
||||
tkeep=s_axis_tkeep,
|
||||
tvalid=s_axis_tvalid,
|
||||
tlast=s_axis_tlast,
|
||||
pause=source_pause,
|
||||
name='source'
|
||||
)
|
||||
|
||||
sink = axis_ep.AXIStreamSink()
|
||||
|
||||
sink_logic = sink.create_logic(
|
||||
clk,
|
||||
rst,
|
||||
tdata=(m_axis_hash, m_axis_hash_type),
|
||||
tvalid=m_axis_hash_valid,
|
||||
name='sink'
|
||||
)
|
||||
|
||||
# DUT
|
||||
if os.system(build_cmd):
|
||||
raise Exception("Error running build command")
|
||||
|
||||
dut = Cosimulation(
|
||||
"vvp -m myhdl %s.vvp -lxt2" % testbench,
|
||||
clk=clk,
|
||||
rst=rst,
|
||||
current_test=current_test,
|
||||
s_axis_tdata=s_axis_tdata,
|
||||
s_axis_tkeep=s_axis_tkeep,
|
||||
s_axis_tvalid=s_axis_tvalid,
|
||||
s_axis_tlast=s_axis_tlast,
|
||||
hash_key=hash_key,
|
||||
m_axis_hash=m_axis_hash,
|
||||
m_axis_hash_type=m_axis_hash_type,
|
||||
m_axis_hash_valid=m_axis_hash_valid
|
||||
)
|
||||
|
||||
@always(delay(4))
|
||||
def clkgen():
|
||||
clk.next = not clk
|
||||
|
||||
def wait_normal():
|
||||
while s_axis_tvalid:
|
||||
yield clk.posedge
|
||||
|
||||
def wait_pause_source():
|
||||
while s_axis_tvalid:
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
source_pause.next = False
|
||||
yield clk.posedge
|
||||
source_pause.next = True
|
||||
yield clk.posedge
|
||||
|
||||
source_pause.next = False
|
||||
|
||||
@instance
|
||||
def check():
|
||||
yield delay(100)
|
||||
yield clk.posedge
|
||||
rst.next = 1
|
||||
yield clk.posedge
|
||||
rst.next = 0
|
||||
yield clk.posedge
|
||||
yield delay(100)
|
||||
yield clk.posedge
|
||||
|
||||
# testbench stimulus
|
||||
|
||||
key = [0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2,
|
||||
0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0,
|
||||
0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4,
|
||||
0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c,
|
||||
0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa]
|
||||
|
||||
hash_key.next = int.from_bytes(key, 'big')
|
||||
|
||||
for payload_len in list(range(1, 128)) + list([1024, 1500, 9000, 9214]):
|
||||
yield clk.posedge
|
||||
print("test 1: test raw ethernet frame, length %d" % payload_len)
|
||||
current_test.next = 1
|
||||
|
||||
test_frame = eth_ep.EthFrame()
|
||||
test_frame.eth_dest_mac = 0xDAD1D2D3D4D5
|
||||
test_frame.eth_src_mac = 0x5A5152535455
|
||||
test_frame.eth_type = 0x8000
|
||||
test_frame.payload = bytearray((x%256 for x in range(payload_len)))
|
||||
|
||||
axis_frame = test_frame.build_axis()
|
||||
|
||||
for wait in wait_normal, wait_pause_source:
|
||||
source.send(axis_frame)
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
yield wait()
|
||||
|
||||
yield sink.wait()
|
||||
rx_hash = sink.recv().data[0]
|
||||
print(rx_hash)
|
||||
|
||||
assert rx_hash[1] == 0b0000
|
||||
|
||||
assert sink.empty()
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 2: test raw IP frame, length %d" % payload_len)
|
||||
current_test.next = 2
|
||||
|
||||
test_frame = ip_ep.IPFrame()
|
||||
test_frame.eth_dest_mac = 0xDAD1D2D3D4D5
|
||||
test_frame.eth_src_mac = 0x5A5152535455
|
||||
test_frame.eth_type = 0x0800
|
||||
test_frame.ip_version = 4
|
||||
test_frame.ip_ihl = 5
|
||||
test_frame.ip_length = None
|
||||
test_frame.ip_identification = 0
|
||||
test_frame.ip_flags = 2
|
||||
test_frame.ip_fragment_offset = 0
|
||||
test_frame.ip_ttl = 64
|
||||
test_frame.ip_protocol = 0x1
|
||||
test_frame.ip_header_checksum = None
|
||||
test_frame.ip_source_ip = 0xc0a80164
|
||||
test_frame.ip_dest_ip = 0xc0a80165
|
||||
test_frame.payload = bytearray((x%256 for x in range(payload_len)))
|
||||
|
||||
axis_frame = test_frame.build_axis()
|
||||
|
||||
for wait in wait_normal, wait_pause_source:
|
||||
source.send(axis_frame)
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
yield wait()
|
||||
|
||||
yield sink.wait()
|
||||
rx_hash = sink.recv().data[0]
|
||||
print(rx_hash)
|
||||
|
||||
h = hash_toep(tuple_pack(test_frame.ip_source_ip, test_frame.ip_dest_ip), key)
|
||||
print(hex(h))
|
||||
|
||||
assert rx_hash[0] == h
|
||||
assert rx_hash[1] == 0b0001
|
||||
|
||||
assert sink.empty()
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 3: test UDP frame, length %d" % payload_len)
|
||||
current_test.next = 3
|
||||
|
||||
test_frame = udp_ep.UDPFrame()
|
||||
test_frame.eth_dest_mac = 0xDAD1D2D3D4D5
|
||||
test_frame.eth_src_mac = 0x5A5152535455
|
||||
test_frame.eth_type = 0x0800
|
||||
test_frame.ip_version = 4
|
||||
test_frame.ip_ihl = 5
|
||||
test_frame.ip_length = None
|
||||
test_frame.ip_identification = 0
|
||||
test_frame.ip_flags = 2
|
||||
test_frame.ip_fragment_offset = 0
|
||||
test_frame.ip_ttl = 64
|
||||
test_frame.ip_protocol = 0x11
|
||||
test_frame.ip_header_checksum = None
|
||||
test_frame.ip_source_ip = 0xc0a80164
|
||||
test_frame.ip_dest_ip = 0xc0a80165
|
||||
test_frame.udp_source_port = 1
|
||||
test_frame.udp_dest_port = 2
|
||||
test_frame.udp_length = None
|
||||
test_frame.udp_checksum = None
|
||||
test_frame.payload = bytearray((x%256 for x in range(payload_len)))
|
||||
|
||||
axis_frame = test_frame.build_axis()
|
||||
|
||||
for wait in wait_normal, wait_pause_source:
|
||||
source.send(axis_frame)
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
yield wait()
|
||||
|
||||
yield sink.wait()
|
||||
rx_hash = sink.recv().data[0]
|
||||
print(rx_hash)
|
||||
|
||||
h = hash_toep(tuple_pack(test_frame.ip_source_ip, test_frame.ip_dest_ip, test_frame.udp_source_port, test_frame.udp_dest_port), key)
|
||||
print(hex(h))
|
||||
|
||||
assert rx_hash[0] == h
|
||||
assert rx_hash[1] == 0b1001
|
||||
|
||||
assert sink.empty()
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 4: test TCP frame, length %d" % payload_len)
|
||||
current_test.next = 4
|
||||
|
||||
test_frame = ip_ep.IPFrame()
|
||||
test_frame.eth_dest_mac = 0xDAD1D2D3D4D5
|
||||
test_frame.eth_src_mac = 0x5A5152535455
|
||||
test_frame.eth_type = 0x0800
|
||||
test_frame.ip_version = 4
|
||||
test_frame.ip_ihl = 5
|
||||
test_frame.ip_length = None
|
||||
test_frame.ip_identification = 0
|
||||
test_frame.ip_flags = 2
|
||||
test_frame.ip_fragment_offset = 0
|
||||
test_frame.ip_ttl = 64
|
||||
test_frame.ip_protocol = 0x6
|
||||
test_frame.ip_header_checksum = None
|
||||
test_frame.ip_source_ip = 0xc0a80164
|
||||
test_frame.ip_dest_ip = 0xc0a80165
|
||||
test_frame.payload = b'\x12\x34\x43\x21'+bytearray((x%256 for x in range(payload_len)))
|
||||
|
||||
axis_frame = test_frame.build_axis()
|
||||
|
||||
for wait in wait_normal, wait_pause_source:
|
||||
source.send(axis_frame)
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
yield wait()
|
||||
|
||||
yield sink.wait()
|
||||
rx_hash = sink.recv().data[0]
|
||||
print(rx_hash)
|
||||
|
||||
h = hash_toep(tuple_pack(test_frame.ip_source_ip, test_frame.ip_dest_ip, 0x1234, 0x4321), key)
|
||||
print(hex(h))
|
||||
|
||||
assert rx_hash[0] == h
|
||||
assert rx_hash[1] == 0b0101
|
||||
|
||||
assert sink.empty()
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 5: back-to-back frames, length %d" % payload_len)
|
||||
current_test.next = 5
|
||||
|
||||
test_frame1 = eth_ep.EthFrame()
|
||||
test_frame1.eth_dest_mac = 0xDAD1D2D3D4D5
|
||||
test_frame1.eth_src_mac = 0x5A5152535455
|
||||
test_frame1.eth_type = 0x8000
|
||||
test_frame1.payload = bytearray((x%256 for x in range(payload_len)))
|
||||
|
||||
test_frame2 = ip_ep.IPFrame()
|
||||
test_frame2.eth_dest_mac = 0xDAD1D2D3D4D5
|
||||
test_frame2.eth_src_mac = 0x5A5152535455
|
||||
test_frame2.eth_type = 0x0800
|
||||
test_frame2.ip_version = 4
|
||||
test_frame2.ip_ihl = 5
|
||||
test_frame2.ip_length = None
|
||||
test_frame2.ip_identification = 0
|
||||
test_frame2.ip_flags = 2
|
||||
test_frame2.ip_fragment_offset = 0
|
||||
test_frame2.ip_ttl = 64
|
||||
test_frame2.ip_protocol = 0x1
|
||||
test_frame2.ip_header_checksum = None
|
||||
test_frame2.ip_source_ip = 0xc0a80164
|
||||
test_frame2.ip_dest_ip = 0xc0a80165
|
||||
test_frame2.payload = bytearray((x%256 for x in range(payload_len)))
|
||||
|
||||
test_frame3 = udp_ep.UDPFrame()
|
||||
test_frame3.eth_dest_mac = 0xDAD1D2D3D4D5
|
||||
test_frame3.eth_src_mac = 0x5A5152535455
|
||||
test_frame3.eth_type = 0x0800
|
||||
test_frame3.ip_version = 4
|
||||
test_frame3.ip_ihl = 5
|
||||
test_frame3.ip_length = None
|
||||
test_frame3.ip_identification = 0
|
||||
test_frame3.ip_flags = 2
|
||||
test_frame3.ip_fragment_offset = 0
|
||||
test_frame3.ip_ttl = 64
|
||||
test_frame3.ip_protocol = 0x11
|
||||
test_frame3.ip_header_checksum = None
|
||||
test_frame3.ip_source_ip = 0xc0a80164
|
||||
test_frame3.ip_dest_ip = 0xc0a80165
|
||||
test_frame3.udp_source_port = 1
|
||||
test_frame3.udp_dest_port = 2
|
||||
test_frame3.udp_length = None
|
||||
test_frame3.udp_checksum = None
|
||||
test_frame3.payload = bytearray((x%256 for x in range(payload_len)))
|
||||
|
||||
test_frame4 = ip_ep.IPFrame()
|
||||
test_frame4.eth_dest_mac = 0xDAD1D2D3D4D5
|
||||
test_frame4.eth_src_mac = 0x5A5152535455
|
||||
test_frame4.eth_type = 0x0800
|
||||
test_frame4.ip_version = 4
|
||||
test_frame4.ip_ihl = 5
|
||||
test_frame4.ip_length = None
|
||||
test_frame4.ip_identification = 0
|
||||
test_frame4.ip_flags = 2
|
||||
test_frame4.ip_fragment_offset = 0
|
||||
test_frame4.ip_ttl = 64
|
||||
test_frame4.ip_protocol = 0x6
|
||||
test_frame4.ip_header_checksum = None
|
||||
test_frame4.ip_source_ip = 0xc0a80164
|
||||
test_frame4.ip_dest_ip = 0xc0a80165
|
||||
test_frame4.payload = b'\x12\x34\x43\x21'+bytearray((x%256 for x in range(payload_len)))
|
||||
|
||||
axis_frame1 = test_frame1.build_axis()
|
||||
axis_frame2 = test_frame2.build_axis()
|
||||
axis_frame3 = test_frame3.build_axis()
|
||||
axis_frame4 = test_frame4.build_axis()
|
||||
|
||||
for wait in wait_normal, wait_pause_source:
|
||||
source.send(axis_frame1)
|
||||
source.send(axis_frame2)
|
||||
source.send(axis_frame3)
|
||||
source.send(axis_frame4)
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
yield wait()
|
||||
|
||||
yield sink.wait()
|
||||
rx_hash = sink.recv().data[0]
|
||||
print(rx_hash)
|
||||
|
||||
assert rx_hash[1] == 0b0000
|
||||
|
||||
yield sink.wait()
|
||||
rx_hash = sink.recv().data[0]
|
||||
print(rx_hash)
|
||||
|
||||
h = hash_toep(tuple_pack(test_frame2.ip_source_ip, test_frame2.ip_dest_ip), key)
|
||||
print(hex(h))
|
||||
|
||||
assert rx_hash[0] == h
|
||||
assert rx_hash[1] == 0b0001
|
||||
|
||||
yield sink.wait()
|
||||
rx_hash = sink.recv().data[0]
|
||||
print(rx_hash)
|
||||
|
||||
h = hash_toep(tuple_pack(test_frame3.ip_source_ip, test_frame3.ip_dest_ip, test_frame3.udp_source_port, test_frame3.udp_dest_port), key)
|
||||
print(hex(h))
|
||||
|
||||
assert rx_hash[0] == h
|
||||
assert rx_hash[1] == 0b1001
|
||||
|
||||
yield sink.wait()
|
||||
rx_hash = sink.recv().data[0]
|
||||
print(rx_hash)
|
||||
|
||||
h = hash_toep(tuple_pack(test_frame4.ip_source_ip, test_frame4.ip_dest_ip, 0x1234, 0x4321), key)
|
||||
print(hex(h))
|
||||
|
||||
assert rx_hash[0] == h
|
||||
assert rx_hash[1] == 0b0101
|
||||
|
||||
assert sink.empty()
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 6: hash test")
|
||||
current_test.next = 6
|
||||
|
||||
test_frame = udp_ep.UDPFrame()
|
||||
test_frame.eth_dest_mac = 0xDAD1D2D3D4D5
|
||||
test_frame.eth_src_mac = 0x5A5152535455
|
||||
test_frame.eth_type = 0x0800
|
||||
test_frame.ip_version = 4
|
||||
test_frame.ip_ihl = 5
|
||||
test_frame.ip_length = None
|
||||
test_frame.ip_identification = 0
|
||||
test_frame.ip_flags = 2
|
||||
test_frame.ip_fragment_offset = 0
|
||||
test_frame.ip_ttl = 64
|
||||
test_frame.ip_protocol = 0x11
|
||||
test_frame.ip_header_checksum = None
|
||||
test_frame.ip_source_ip = 0x420995bb
|
||||
test_frame.ip_dest_ip = 0xa18e6450
|
||||
test_frame.udp_source_port = 2794
|
||||
test_frame.udp_dest_port = 1766
|
||||
test_frame.udp_length = None
|
||||
test_frame.udp_checksum = None
|
||||
test_frame.payload = bytearray((x%256 for x in range(128)))
|
||||
|
||||
axis_frame = test_frame.build_axis()
|
||||
|
||||
for wait in wait_normal, wait_pause_source:
|
||||
source.send(axis_frame)
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
yield wait()
|
||||
|
||||
yield sink.wait()
|
||||
rx_hash = sink.recv().data[0]
|
||||
print(rx_hash)
|
||||
|
||||
h = hash_toep(tuple_pack(test_frame.ip_source_ip, test_frame.ip_dest_ip, test_frame.udp_source_port, test_frame.udp_dest_port), key)
|
||||
print(hex(h))
|
||||
|
||||
assert rx_hash[0] == h
|
||||
assert rx_hash[1] == 0b1001
|
||||
assert h == 0x51ccc178
|
||||
|
||||
assert sink.empty()
|
||||
|
||||
yield delay(100)
|
||||
|
||||
raise StopSimulation
|
||||
|
||||
return instances()
|
||||
|
||||
def test_bench():
|
||||
sim = Simulation(bench())
|
||||
sim.run()
|
||||
|
||||
if __name__ == '__main__':
|
||||
print("Running test...")
|
||||
test_bench()
|
@ -1,103 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright 2019, The Regents of the University of California.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
|
||||
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of The Regents of the University of California.
|
||||
|
||||
*/
|
||||
|
||||
// Language: Verilog 2001
|
||||
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
/*
|
||||
* Testbench for rx_hash
|
||||
*/
|
||||
module test_rx_hash_256;
|
||||
|
||||
// Parameters
|
||||
parameter DATA_WIDTH = 256;
|
||||
parameter KEEP_WIDTH = (DATA_WIDTH/8);
|
||||
|
||||
// Inputs
|
||||
reg clk = 0;
|
||||
reg rst = 0;
|
||||
reg [7:0] current_test = 0;
|
||||
|
||||
reg [DATA_WIDTH-1:0] s_axis_tdata = 0;
|
||||
reg [KEEP_WIDTH-1:0] s_axis_tkeep = 0;
|
||||
reg s_axis_tvalid = 0;
|
||||
reg s_axis_tlast = 0;
|
||||
reg [40*8-1:0] hash_key = 0;
|
||||
|
||||
// Outputs
|
||||
wire [31:0] m_axis_hash;
|
||||
wire [3:0] m_axis_hash_type;
|
||||
wire m_axis_hash_valid;
|
||||
|
||||
initial begin
|
||||
// myhdl integration
|
||||
$from_myhdl(
|
||||
clk,
|
||||
rst,
|
||||
current_test,
|
||||
s_axis_tdata,
|
||||
s_axis_tkeep,
|
||||
s_axis_tvalid,
|
||||
s_axis_tlast,
|
||||
hash_key
|
||||
);
|
||||
$to_myhdl(
|
||||
m_axis_hash,
|
||||
m_axis_hash_type,
|
||||
m_axis_hash_valid
|
||||
);
|
||||
|
||||
// dump file
|
||||
$dumpfile("test_rx_hash_256.lxt");
|
||||
$dumpvars(0, test_rx_hash_256);
|
||||
end
|
||||
|
||||
rx_hash #(
|
||||
.DATA_WIDTH(DATA_WIDTH),
|
||||
.KEEP_WIDTH(KEEP_WIDTH)
|
||||
)
|
||||
UUT (
|
||||
.clk(clk),
|
||||
.rst(rst),
|
||||
.s_axis_tdata(s_axis_tdata),
|
||||
.s_axis_tkeep(s_axis_tkeep),
|
||||
.s_axis_tvalid(s_axis_tvalid),
|
||||
.s_axis_tlast(s_axis_tlast),
|
||||
.hash_key(hash_key),
|
||||
.m_axis_hash(m_axis_hash),
|
||||
.m_axis_hash_type(m_axis_hash_type),
|
||||
.m_axis_hash_valid(m_axis_hash_valid)
|
||||
);
|
||||
|
||||
endmodule
|
@ -1,536 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
|
||||
Copyright 2019, The Regents of the University of California.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
|
||||
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of The Regents of the University of California.
|
||||
|
||||
"""
|
||||
|
||||
from myhdl import *
|
||||
import os
|
||||
import ipaddress
|
||||
|
||||
import axis_ep
|
||||
import eth_ep
|
||||
import ip_ep
|
||||
import udp_ep
|
||||
|
||||
module = 'rx_hash'
|
||||
testbench = 'test_%s_64' % module
|
||||
|
||||
srcs = []
|
||||
|
||||
srcs.append("../rtl/%s.v" % module)
|
||||
srcs.append("%s.v" % testbench)
|
||||
|
||||
src = ' '.join(srcs)
|
||||
|
||||
build_cmd = "iverilog -o %s.vvp %s" % (testbench, src)
|
||||
|
||||
def hash_toep(data, key):
|
||||
k = len(key)*8-32
|
||||
key = int.from_bytes(key, 'big')
|
||||
|
||||
h = 0
|
||||
|
||||
for b in data:
|
||||
for i in range(8):
|
||||
if b & 0x80 >> i:
|
||||
h ^= (key >> k) & 0xffffffff
|
||||
k -= 1
|
||||
|
||||
return h
|
||||
|
||||
def tuple_pack(src_ip, dest_ip, src_port=None, dest_port=None):
|
||||
src_ip = ipaddress.ip_address(src_ip)
|
||||
dest_ip = ipaddress.ip_address(dest_ip)
|
||||
if src_ip.version == 6 or dest_ip.version == 6:
|
||||
src_ip = int(src_ip).to_bytes(16, 'big')
|
||||
dest_ip = int(dest_ip).to_bytes(16, 'big')
|
||||
else:
|
||||
src_ip = int(src_ip).to_bytes(4, 'big')
|
||||
dest_ip = int(dest_ip).to_bytes(4, 'big')
|
||||
data = src_ip+dest_ip
|
||||
if src_port is not None and dest_port is not None:
|
||||
data += src_port.to_bytes(2, 'big') + dest_port.to_bytes(2, 'big')
|
||||
return data
|
||||
|
||||
def bench():
|
||||
|
||||
# Parameters
|
||||
DATA_WIDTH = 64
|
||||
KEEP_WIDTH = (DATA_WIDTH/8)
|
||||
|
||||
# Inputs
|
||||
clk = Signal(bool(0))
|
||||
rst = Signal(bool(0))
|
||||
current_test = Signal(intbv(0)[8:])
|
||||
|
||||
s_axis_tdata = Signal(intbv(0)[DATA_WIDTH:])
|
||||
s_axis_tkeep = Signal(intbv(0)[KEEP_WIDTH:])
|
||||
s_axis_tvalid = Signal(bool(0))
|
||||
s_axis_tlast = Signal(bool(0))
|
||||
hash_key = Signal(intbv(0)[40*8:])
|
||||
|
||||
# Outputs
|
||||
m_axis_hash = Signal(intbv(0)[32:])
|
||||
m_axis_hash_type = Signal(intbv(0)[4:])
|
||||
m_axis_hash_valid = Signal(bool(0))
|
||||
|
||||
# sources and sinks
|
||||
source_pause = Signal(bool(0))
|
||||
|
||||
source = axis_ep.AXIStreamSource()
|
||||
|
||||
source_logic = source.create_logic(
|
||||
clk,
|
||||
rst,
|
||||
tdata=s_axis_tdata,
|
||||
tkeep=s_axis_tkeep,
|
||||
tvalid=s_axis_tvalid,
|
||||
tlast=s_axis_tlast,
|
||||
pause=source_pause,
|
||||
name='source'
|
||||
)
|
||||
|
||||
sink = axis_ep.AXIStreamSink()
|
||||
|
||||
sink_logic = sink.create_logic(
|
||||
clk,
|
||||
rst,
|
||||
tdata=(m_axis_hash, m_axis_hash_type),
|
||||
tvalid=m_axis_hash_valid,
|
||||
name='sink'
|
||||
)
|
||||
|
||||
# DUT
|
||||
if os.system(build_cmd):
|
||||
raise Exception("Error running build command")
|
||||
|
||||
dut = Cosimulation(
|
||||
"vvp -m myhdl %s.vvp -lxt2" % testbench,
|
||||
clk=clk,
|
||||
rst=rst,
|
||||
current_test=current_test,
|
||||
s_axis_tdata=s_axis_tdata,
|
||||
s_axis_tkeep=s_axis_tkeep,
|
||||
s_axis_tvalid=s_axis_tvalid,
|
||||
s_axis_tlast=s_axis_tlast,
|
||||
hash_key=hash_key,
|
||||
m_axis_hash=m_axis_hash,
|
||||
m_axis_hash_type=m_axis_hash_type,
|
||||
m_axis_hash_valid=m_axis_hash_valid
|
||||
)
|
||||
|
||||
@always(delay(4))
|
||||
def clkgen():
|
||||
clk.next = not clk
|
||||
|
||||
def wait_normal():
|
||||
while s_axis_tvalid:
|
||||
yield clk.posedge
|
||||
|
||||
def wait_pause_source():
|
||||
while s_axis_tvalid:
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
source_pause.next = False
|
||||
yield clk.posedge
|
||||
source_pause.next = True
|
||||
yield clk.posedge
|
||||
|
||||
source_pause.next = False
|
||||
|
||||
@instance
|
||||
def check():
|
||||
yield delay(100)
|
||||
yield clk.posedge
|
||||
rst.next = 1
|
||||
yield clk.posedge
|
||||
rst.next = 0
|
||||
yield clk.posedge
|
||||
yield delay(100)
|
||||
yield clk.posedge
|
||||
|
||||
# testbench stimulus
|
||||
|
||||
key = [0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2,
|
||||
0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0,
|
||||
0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4,
|
||||
0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c,
|
||||
0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa]
|
||||
|
||||
hash_key.next = int.from_bytes(key, 'big')
|
||||
|
||||
for payload_len in list(range(1, 128)) + list([1024, 1500, 9000, 9214]):
|
||||
yield clk.posedge
|
||||
print("test 1: test raw ethernet frame, length %d" % payload_len)
|
||||
current_test.next = 1
|
||||
|
||||
test_frame = eth_ep.EthFrame()
|
||||
test_frame.eth_dest_mac = 0xDAD1D2D3D4D5
|
||||
test_frame.eth_src_mac = 0x5A5152535455
|
||||
test_frame.eth_type = 0x8000
|
||||
test_frame.payload = bytearray((x%256 for x in range(payload_len)))
|
||||
|
||||
axis_frame = test_frame.build_axis()
|
||||
|
||||
for wait in wait_normal, wait_pause_source:
|
||||
source.send(axis_frame)
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
yield wait()
|
||||
|
||||
yield sink.wait()
|
||||
rx_hash = sink.recv().data[0]
|
||||
print(rx_hash)
|
||||
|
||||
assert rx_hash[1] == 0b0000
|
||||
|
||||
assert sink.empty()
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 2: test raw IP frame, length %d" % payload_len)
|
||||
current_test.next = 2
|
||||
|
||||
test_frame = ip_ep.IPFrame()
|
||||
test_frame.eth_dest_mac = 0xDAD1D2D3D4D5
|
||||
test_frame.eth_src_mac = 0x5A5152535455
|
||||
test_frame.eth_type = 0x0800
|
||||
test_frame.ip_version = 4
|
||||
test_frame.ip_ihl = 5
|
||||
test_frame.ip_length = None
|
||||
test_frame.ip_identification = 0
|
||||
test_frame.ip_flags = 2
|
||||
test_frame.ip_fragment_offset = 0
|
||||
test_frame.ip_ttl = 64
|
||||
test_frame.ip_protocol = 0x1
|
||||
test_frame.ip_header_checksum = None
|
||||
test_frame.ip_source_ip = 0xc0a80164
|
||||
test_frame.ip_dest_ip = 0xc0a80165
|
||||
test_frame.payload = bytearray((x%256 for x in range(payload_len)))
|
||||
|
||||
axis_frame = test_frame.build_axis()
|
||||
|
||||
for wait in wait_normal, wait_pause_source:
|
||||
source.send(axis_frame)
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
yield wait()
|
||||
|
||||
yield sink.wait()
|
||||
rx_hash = sink.recv().data[0]
|
||||
print(rx_hash)
|
||||
|
||||
h = hash_toep(tuple_pack(test_frame.ip_source_ip, test_frame.ip_dest_ip), key)
|
||||
print(hex(h))
|
||||
|
||||
assert rx_hash[0] == h
|
||||
assert rx_hash[1] == 0b0001
|
||||
|
||||
assert sink.empty()
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 3: test UDP frame, length %d" % payload_len)
|
||||
current_test.next = 3
|
||||
|
||||
test_frame = udp_ep.UDPFrame()
|
||||
test_frame.eth_dest_mac = 0xDAD1D2D3D4D5
|
||||
test_frame.eth_src_mac = 0x5A5152535455
|
||||
test_frame.eth_type = 0x0800
|
||||
test_frame.ip_version = 4
|
||||
test_frame.ip_ihl = 5
|
||||
test_frame.ip_length = None
|
||||
test_frame.ip_identification = 0
|
||||
test_frame.ip_flags = 2
|
||||
test_frame.ip_fragment_offset = 0
|
||||
test_frame.ip_ttl = 64
|
||||
test_frame.ip_protocol = 0x11
|
||||
test_frame.ip_header_checksum = None
|
||||
test_frame.ip_source_ip = 0xc0a80164
|
||||
test_frame.ip_dest_ip = 0xc0a80165
|
||||
test_frame.udp_source_port = 1
|
||||
test_frame.udp_dest_port = 2
|
||||
test_frame.udp_length = None
|
||||
test_frame.udp_checksum = None
|
||||
test_frame.payload = bytearray((x%256 for x in range(payload_len)))
|
||||
|
||||
axis_frame = test_frame.build_axis()
|
||||
|
||||
for wait in wait_normal, wait_pause_source:
|
||||
source.send(axis_frame)
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
yield wait()
|
||||
|
||||
yield sink.wait()
|
||||
rx_hash = sink.recv().data[0]
|
||||
print(rx_hash)
|
||||
|
||||
h = hash_toep(tuple_pack(test_frame.ip_source_ip, test_frame.ip_dest_ip, test_frame.udp_source_port, test_frame.udp_dest_port), key)
|
||||
print(hex(h))
|
||||
|
||||
assert rx_hash[0] == h
|
||||
assert rx_hash[1] == 0b1001
|
||||
|
||||
assert sink.empty()
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 4: test TCP frame, length %d" % payload_len)
|
||||
current_test.next = 4
|
||||
|
||||
test_frame = ip_ep.IPFrame()
|
||||
test_frame.eth_dest_mac = 0xDAD1D2D3D4D5
|
||||
test_frame.eth_src_mac = 0x5A5152535455
|
||||
test_frame.eth_type = 0x0800
|
||||
test_frame.ip_version = 4
|
||||
test_frame.ip_ihl = 5
|
||||
test_frame.ip_length = None
|
||||
test_frame.ip_identification = 0
|
||||
test_frame.ip_flags = 2
|
||||
test_frame.ip_fragment_offset = 0
|
||||
test_frame.ip_ttl = 64
|
||||
test_frame.ip_protocol = 0x6
|
||||
test_frame.ip_header_checksum = None
|
||||
test_frame.ip_source_ip = 0xc0a80164
|
||||
test_frame.ip_dest_ip = 0xc0a80165
|
||||
test_frame.payload = b'\x12\x34\x43\x21'+bytearray((x%256 for x in range(payload_len)))
|
||||
|
||||
axis_frame = test_frame.build_axis()
|
||||
|
||||
for wait in wait_normal, wait_pause_source:
|
||||
source.send(axis_frame)
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
yield wait()
|
||||
|
||||
yield sink.wait()
|
||||
rx_hash = sink.recv().data[0]
|
||||
print(rx_hash)
|
||||
|
||||
h = hash_toep(tuple_pack(test_frame.ip_source_ip, test_frame.ip_dest_ip, 0x1234, 0x4321), key)
|
||||
print(hex(h))
|
||||
|
||||
assert rx_hash[0] == h
|
||||
assert rx_hash[1] == 0b0101
|
||||
|
||||
assert sink.empty()
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 5: back-to-back frames, length %d" % payload_len)
|
||||
current_test.next = 5
|
||||
|
||||
test_frame1 = eth_ep.EthFrame()
|
||||
test_frame1.eth_dest_mac = 0xDAD1D2D3D4D5
|
||||
test_frame1.eth_src_mac = 0x5A5152535455
|
||||
test_frame1.eth_type = 0x8000
|
||||
test_frame1.payload = bytearray((x%256 for x in range(payload_len)))
|
||||
|
||||
test_frame2 = ip_ep.IPFrame()
|
||||
test_frame2.eth_dest_mac = 0xDAD1D2D3D4D5
|
||||
test_frame2.eth_src_mac = 0x5A5152535455
|
||||
test_frame2.eth_type = 0x0800
|
||||
test_frame2.ip_version = 4
|
||||
test_frame2.ip_ihl = 5
|
||||
test_frame2.ip_length = None
|
||||
test_frame2.ip_identification = 0
|
||||
test_frame2.ip_flags = 2
|
||||
test_frame2.ip_fragment_offset = 0
|
||||
test_frame2.ip_ttl = 64
|
||||
test_frame2.ip_protocol = 0x1
|
||||
test_frame2.ip_header_checksum = None
|
||||
test_frame2.ip_source_ip = 0xc0a80164
|
||||
test_frame2.ip_dest_ip = 0xc0a80165
|
||||
test_frame2.payload = bytearray((x%256 for x in range(payload_len)))
|
||||
|
||||
test_frame3 = udp_ep.UDPFrame()
|
||||
test_frame3.eth_dest_mac = 0xDAD1D2D3D4D5
|
||||
test_frame3.eth_src_mac = 0x5A5152535455
|
||||
test_frame3.eth_type = 0x0800
|
||||
test_frame3.ip_version = 4
|
||||
test_frame3.ip_ihl = 5
|
||||
test_frame3.ip_length = None
|
||||
test_frame3.ip_identification = 0
|
||||
test_frame3.ip_flags = 2
|
||||
test_frame3.ip_fragment_offset = 0
|
||||
test_frame3.ip_ttl = 64
|
||||
test_frame3.ip_protocol = 0x11
|
||||
test_frame3.ip_header_checksum = None
|
||||
test_frame3.ip_source_ip = 0xc0a80164
|
||||
test_frame3.ip_dest_ip = 0xc0a80165
|
||||
test_frame3.udp_source_port = 1
|
||||
test_frame3.udp_dest_port = 2
|
||||
test_frame3.udp_length = None
|
||||
test_frame3.udp_checksum = None
|
||||
test_frame3.payload = bytearray((x%256 for x in range(payload_len)))
|
||||
|
||||
test_frame4 = ip_ep.IPFrame()
|
||||
test_frame4.eth_dest_mac = 0xDAD1D2D3D4D5
|
||||
test_frame4.eth_src_mac = 0x5A5152535455
|
||||
test_frame4.eth_type = 0x0800
|
||||
test_frame4.ip_version = 4
|
||||
test_frame4.ip_ihl = 5
|
||||
test_frame4.ip_length = None
|
||||
test_frame4.ip_identification = 0
|
||||
test_frame4.ip_flags = 2
|
||||
test_frame4.ip_fragment_offset = 0
|
||||
test_frame4.ip_ttl = 64
|
||||
test_frame4.ip_protocol = 0x6
|
||||
test_frame4.ip_header_checksum = None
|
||||
test_frame4.ip_source_ip = 0xc0a80164
|
||||
test_frame4.ip_dest_ip = 0xc0a80165
|
||||
test_frame4.payload = b'\x12\x34\x43\x21'+bytearray((x%256 for x in range(payload_len)))
|
||||
|
||||
axis_frame1 = test_frame1.build_axis()
|
||||
axis_frame2 = test_frame2.build_axis()
|
||||
axis_frame3 = test_frame3.build_axis()
|
||||
axis_frame4 = test_frame4.build_axis()
|
||||
|
||||
for wait in wait_normal, wait_pause_source:
|
||||
source.send(axis_frame1)
|
||||
source.send(axis_frame2)
|
||||
source.send(axis_frame3)
|
||||
source.send(axis_frame4)
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
yield wait()
|
||||
|
||||
yield sink.wait()
|
||||
rx_hash = sink.recv().data[0]
|
||||
print(rx_hash)
|
||||
|
||||
assert rx_hash[1] == 0b0000
|
||||
|
||||
yield sink.wait()
|
||||
rx_hash = sink.recv().data[0]
|
||||
print(rx_hash)
|
||||
|
||||
h = hash_toep(tuple_pack(test_frame2.ip_source_ip, test_frame2.ip_dest_ip), key)
|
||||
print(hex(h))
|
||||
|
||||
assert rx_hash[0] == h
|
||||
assert rx_hash[1] == 0b0001
|
||||
|
||||
yield sink.wait()
|
||||
rx_hash = sink.recv().data[0]
|
||||
print(rx_hash)
|
||||
|
||||
h = hash_toep(tuple_pack(test_frame3.ip_source_ip, test_frame3.ip_dest_ip, test_frame3.udp_source_port, test_frame3.udp_dest_port), key)
|
||||
print(hex(h))
|
||||
|
||||
assert rx_hash[0] == h
|
||||
assert rx_hash[1] == 0b1001
|
||||
|
||||
yield sink.wait()
|
||||
rx_hash = sink.recv().data[0]
|
||||
print(rx_hash)
|
||||
|
||||
h = hash_toep(tuple_pack(test_frame4.ip_source_ip, test_frame4.ip_dest_ip, 0x1234, 0x4321), key)
|
||||
print(hex(h))
|
||||
|
||||
assert rx_hash[0] == h
|
||||
assert rx_hash[1] == 0b0101
|
||||
|
||||
assert sink.empty()
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 6: hash test")
|
||||
current_test.next = 6
|
||||
|
||||
test_frame = udp_ep.UDPFrame()
|
||||
test_frame.eth_dest_mac = 0xDAD1D2D3D4D5
|
||||
test_frame.eth_src_mac = 0x5A5152535455
|
||||
test_frame.eth_type = 0x0800
|
||||
test_frame.ip_version = 4
|
||||
test_frame.ip_ihl = 5
|
||||
test_frame.ip_length = None
|
||||
test_frame.ip_identification = 0
|
||||
test_frame.ip_flags = 2
|
||||
test_frame.ip_fragment_offset = 0
|
||||
test_frame.ip_ttl = 64
|
||||
test_frame.ip_protocol = 0x11
|
||||
test_frame.ip_header_checksum = None
|
||||
test_frame.ip_source_ip = 0x420995bb
|
||||
test_frame.ip_dest_ip = 0xa18e6450
|
||||
test_frame.udp_source_port = 2794
|
||||
test_frame.udp_dest_port = 1766
|
||||
test_frame.udp_length = None
|
||||
test_frame.udp_checksum = None
|
||||
test_frame.payload = bytearray((x%256 for x in range(128)))
|
||||
|
||||
axis_frame = test_frame.build_axis()
|
||||
|
||||
for wait in wait_normal, wait_pause_source:
|
||||
source.send(axis_frame)
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
yield wait()
|
||||
|
||||
yield sink.wait()
|
||||
rx_hash = sink.recv().data[0]
|
||||
print(rx_hash)
|
||||
|
||||
h = hash_toep(tuple_pack(test_frame.ip_source_ip, test_frame.ip_dest_ip, test_frame.udp_source_port, test_frame.udp_dest_port), key)
|
||||
print(hex(h))
|
||||
|
||||
assert rx_hash[0] == h
|
||||
assert rx_hash[1] == 0b1001
|
||||
assert h == 0x51ccc178
|
||||
|
||||
assert sink.empty()
|
||||
|
||||
yield delay(100)
|
||||
|
||||
raise StopSimulation
|
||||
|
||||
return instances()
|
||||
|
||||
def test_bench():
|
||||
sim = Simulation(bench())
|
||||
sim.run()
|
||||
|
||||
if __name__ == '__main__':
|
||||
print("Running test...")
|
||||
test_bench()
|
@ -1,103 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright 2019, The Regents of the University of California.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
|
||||
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of The Regents of the University of California.
|
||||
|
||||
*/
|
||||
|
||||
// Language: Verilog 2001
|
||||
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
/*
|
||||
* Testbench for rx_hash
|
||||
*/
|
||||
module test_rx_hash_64;
|
||||
|
||||
// Parameters
|
||||
parameter DATA_WIDTH = 64;
|
||||
parameter KEEP_WIDTH = (DATA_WIDTH/8);
|
||||
|
||||
// Inputs
|
||||
reg clk = 0;
|
||||
reg rst = 0;
|
||||
reg [7:0] current_test = 0;
|
||||
|
||||
reg [DATA_WIDTH-1:0] s_axis_tdata = 0;
|
||||
reg [KEEP_WIDTH-1:0] s_axis_tkeep = 0;
|
||||
reg s_axis_tvalid = 0;
|
||||
reg s_axis_tlast = 0;
|
||||
reg [40*8-1:0] hash_key = 0;
|
||||
|
||||
// Outputs
|
||||
wire [31:0] m_axis_hash;
|
||||
wire [3:0] m_axis_hash_type;
|
||||
wire m_axis_hash_valid;
|
||||
|
||||
initial begin
|
||||
// myhdl integration
|
||||
$from_myhdl(
|
||||
clk,
|
||||
rst,
|
||||
current_test,
|
||||
s_axis_tdata,
|
||||
s_axis_tkeep,
|
||||
s_axis_tvalid,
|
||||
s_axis_tlast,
|
||||
hash_key
|
||||
);
|
||||
$to_myhdl(
|
||||
m_axis_hash,
|
||||
m_axis_hash_type,
|
||||
m_axis_hash_valid
|
||||
);
|
||||
|
||||
// dump file
|
||||
$dumpfile("test_rx_hash_64.lxt");
|
||||
$dumpvars(0, test_rx_hash_64);
|
||||
end
|
||||
|
||||
rx_hash #(
|
||||
.DATA_WIDTH(DATA_WIDTH),
|
||||
.KEEP_WIDTH(KEEP_WIDTH)
|
||||
)
|
||||
UUT (
|
||||
.clk(clk),
|
||||
.rst(rst),
|
||||
.s_axis_tdata(s_axis_tdata),
|
||||
.s_axis_tkeep(s_axis_tkeep),
|
||||
.s_axis_tvalid(s_axis_tvalid),
|
||||
.s_axis_tlast(s_axis_tlast),
|
||||
.hash_key(hash_key),
|
||||
.m_axis_hash(m_axis_hash),
|
||||
.m_axis_hash_type(m_axis_hash_type),
|
||||
.m_axis_hash_valid(m_axis_hash_valid)
|
||||
);
|
||||
|
||||
endmodule
|
@ -1,233 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
|
||||
Copyright 2019, The Regents of the University of California.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
|
||||
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of The Regents of the University of California.
|
||||
|
||||
"""
|
||||
|
||||
from myhdl import *
|
||||
import os
|
||||
import struct
|
||||
|
||||
import axil
|
||||
import ptp
|
||||
|
||||
module = 'tdma_ber'
|
||||
testbench = 'test_%s' % module
|
||||
|
||||
srcs = []
|
||||
|
||||
srcs.append("../rtl/%s.v" % module)
|
||||
srcs.append("../rtl/tdma_ber_ch.v")
|
||||
srcs.append("../rtl/tdma_scheduler.v")
|
||||
srcs.append("../lib/axi/rtl/axil_interconnect.v")
|
||||
srcs.append("../lib/axi/rtl/arbiter.v")
|
||||
srcs.append("../lib/axi/rtl/priority_encoder.v")
|
||||
srcs.append("%s.v" % testbench)
|
||||
|
||||
src = ' '.join(srcs)
|
||||
|
||||
build_cmd = "iverilog -o %s.vvp %s" % (testbench, src)
|
||||
|
||||
def bench():
|
||||
|
||||
# Parameters
|
||||
COUNT = 2
|
||||
INDEX_WIDTH = 6
|
||||
SLICE_WIDTH = 5
|
||||
AXIL_DATA_WIDTH = 32
|
||||
AXIL_ADDR_WIDTH = INDEX_WIDTH+4+1+(COUNT-1).bit_length()
|
||||
AXIL_STRB_WIDTH = (AXIL_DATA_WIDTH/8)
|
||||
SCHEDULE_START_S = 0x0
|
||||
SCHEDULE_START_NS = 0x0
|
||||
SCHEDULE_PERIOD_S = 0
|
||||
SCHEDULE_PERIOD_NS = 1000000
|
||||
TIMESLOT_PERIOD_S = 0
|
||||
TIMESLOT_PERIOD_NS = 100000
|
||||
ACTIVE_PERIOD_S = 0
|
||||
ACTIVE_PERIOD_NS = 100000
|
||||
|
||||
# Inputs
|
||||
clk = Signal(bool(0))
|
||||
rst = Signal(bool(0))
|
||||
current_test = Signal(intbv(0)[8:])
|
||||
|
||||
phy_tx_clk = Signal(intbv(0)[COUNT:])
|
||||
phy_rx_clk = Signal(intbv(0)[COUNT:])
|
||||
phy_rx_error_count = Signal(intbv(0)[COUNT*7:])
|
||||
s_axil_awaddr = Signal(intbv(0)[AXIL_ADDR_WIDTH:])
|
||||
s_axil_awprot = Signal(intbv(0)[3:])
|
||||
s_axil_awvalid = Signal(bool(0))
|
||||
s_axil_wdata = Signal(intbv(0)[AXIL_DATA_WIDTH:])
|
||||
s_axil_wstrb = Signal(intbv(0)[AXIL_STRB_WIDTH:])
|
||||
s_axil_wvalid = Signal(bool(0))
|
||||
s_axil_bready = Signal(bool(0))
|
||||
s_axil_araddr = Signal(intbv(0)[AXIL_ADDR_WIDTH:])
|
||||
s_axil_arprot = Signal(intbv(0)[3:])
|
||||
s_axil_arvalid = Signal(bool(0))
|
||||
s_axil_rready = Signal(bool(0))
|
||||
ptp_ts_96 = Signal(intbv(0)[96:])
|
||||
ptp_ts_step = Signal(bool(0))
|
||||
|
||||
# Outputs
|
||||
phy_tx_prbs31_enable = Signal(intbv(0)[COUNT:])
|
||||
phy_rx_prbs31_enable = Signal(intbv(0)[COUNT:])
|
||||
s_axil_awready = Signal(bool(0))
|
||||
s_axil_wready = Signal(bool(0))
|
||||
s_axil_bresp = Signal(intbv(0)[2:])
|
||||
s_axil_bvalid = Signal(bool(0))
|
||||
s_axil_arready = Signal(bool(0))
|
||||
s_axil_rdata = Signal(intbv(0)[AXIL_DATA_WIDTH:])
|
||||
s_axil_rresp = Signal(intbv(0)[2:])
|
||||
s_axil_rvalid = Signal(bool(0))
|
||||
|
||||
# AXI4-Lite master
|
||||
axil_master_inst = axil.AXILiteMaster()
|
||||
axil_master_pause = Signal(bool(False))
|
||||
|
||||
axil_master_logic = axil_master_inst.create_logic(
|
||||
clk,
|
||||
rst,
|
||||
m_axil_awaddr=s_axil_awaddr,
|
||||
m_axil_awprot=s_axil_awprot,
|
||||
m_axil_awvalid=s_axil_awvalid,
|
||||
m_axil_awready=s_axil_awready,
|
||||
m_axil_wdata=s_axil_wdata,
|
||||
m_axil_wstrb=s_axil_wstrb,
|
||||
m_axil_wvalid=s_axil_wvalid,
|
||||
m_axil_wready=s_axil_wready,
|
||||
m_axil_bresp=s_axil_bresp,
|
||||
m_axil_bvalid=s_axil_bvalid,
|
||||
m_axil_bready=s_axil_bready,
|
||||
m_axil_araddr=s_axil_araddr,
|
||||
m_axil_arprot=s_axil_arprot,
|
||||
m_axil_arvalid=s_axil_arvalid,
|
||||
m_axil_arready=s_axil_arready,
|
||||
m_axil_rdata=s_axil_rdata,
|
||||
m_axil_rresp=s_axil_rresp,
|
||||
m_axil_rvalid=s_axil_rvalid,
|
||||
m_axil_rready=s_axil_rready,
|
||||
pause=axil_master_pause,
|
||||
name='master'
|
||||
)
|
||||
|
||||
# PTP clock
|
||||
ptp_clock = ptp.PtpClock()
|
||||
|
||||
ptp_logic = ptp_clock.create_logic(
|
||||
clk,
|
||||
rst,
|
||||
ts_96=ptp_ts_96
|
||||
)
|
||||
|
||||
# DUT
|
||||
if os.system(build_cmd):
|
||||
raise Exception("Error running build command")
|
||||
|
||||
dut = Cosimulation(
|
||||
"vvp -m myhdl %s.vvp -lxt2" % testbench,
|
||||
clk=clk,
|
||||
rst=rst,
|
||||
current_test=current_test,
|
||||
phy_tx_clk=phy_tx_clk,
|
||||
phy_rx_clk=phy_rx_clk,
|
||||
phy_rx_error_count=phy_rx_error_count,
|
||||
phy_tx_prbs31_enable=phy_tx_prbs31_enable,
|
||||
phy_rx_prbs31_enable=phy_rx_prbs31_enable,
|
||||
s_axil_awaddr=s_axil_awaddr,
|
||||
s_axil_awprot=s_axil_awprot,
|
||||
s_axil_awvalid=s_axil_awvalid,
|
||||
s_axil_awready=s_axil_awready,
|
||||
s_axil_wdata=s_axil_wdata,
|
||||
s_axil_wstrb=s_axil_wstrb,
|
||||
s_axil_wvalid=s_axil_wvalid,
|
||||
s_axil_wready=s_axil_wready,
|
||||
s_axil_bresp=s_axil_bresp,
|
||||
s_axil_bvalid=s_axil_bvalid,
|
||||
s_axil_bready=s_axil_bready,
|
||||
s_axil_araddr=s_axil_araddr,
|
||||
s_axil_arprot=s_axil_arprot,
|
||||
s_axil_arvalid=s_axil_arvalid,
|
||||
s_axil_arready=s_axil_arready,
|
||||
s_axil_rdata=s_axil_rdata,
|
||||
s_axil_rresp=s_axil_rresp,
|
||||
s_axil_rvalid=s_axil_rvalid,
|
||||
s_axil_rready=s_axil_rready,
|
||||
ptp_ts_96=ptp_ts_96,
|
||||
ptp_ts_step=ptp_ts_step
|
||||
)
|
||||
|
||||
@always(delay(4))
|
||||
def clkgen():
|
||||
clk.next = not clk
|
||||
|
||||
@always(delay(3))
|
||||
def clkgen2():
|
||||
phy_tx_clk.next = ~phy_tx_clk
|
||||
phy_rx_clk.next = ~phy_rx_clk
|
||||
|
||||
@instance
|
||||
def check():
|
||||
yield delay(100)
|
||||
yield clk.posedge
|
||||
rst.next = 1
|
||||
yield clk.posedge
|
||||
rst.next = 0
|
||||
yield clk.posedge
|
||||
yield delay(100)
|
||||
yield clk.posedge
|
||||
|
||||
# testbench stimulus
|
||||
|
||||
yield clk.posedge
|
||||
print("test 1: Test pulse out")
|
||||
current_test.next = 1
|
||||
|
||||
axil_master_inst.init_write(0x0110, struct.pack('<LLLL', 0, 500, 0, 0))
|
||||
axil_master_inst.init_write(0x0120, struct.pack('<LLLL', 0, 2000, 0, 0))
|
||||
axil_master_inst.init_write(0x0130, struct.pack('<LLLL', 0, 400, 0, 0))
|
||||
axil_master_inst.init_write(0x0140, struct.pack('<LLLL', 0, 300, 0, 0))
|
||||
axil_master_inst.init_write(0x0100, struct.pack('<L', 0x00000001))
|
||||
|
||||
yield delay(10000)
|
||||
|
||||
yield delay(100)
|
||||
|
||||
raise StopSimulation
|
||||
|
||||
return instances()
|
||||
|
||||
def test_bench():
|
||||
sim = Simulation(bench())
|
||||
sim.run()
|
||||
|
||||
if __name__ == '__main__':
|
||||
print("Running test...")
|
||||
test_bench()
|
@ -1,181 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright 2019, The Regents of the University of California.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
|
||||
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of The Regents of the University of California.
|
||||
|
||||
*/
|
||||
|
||||
// Language: Verilog 2001
|
||||
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
/*
|
||||
* Testbench for tdma_ber
|
||||
*/
|
||||
module test_tdma_ber;
|
||||
|
||||
// Parameters
|
||||
parameter COUNT = 2;
|
||||
parameter INDEX_WIDTH = 6;
|
||||
parameter SLICE_WIDTH = 5;
|
||||
parameter AXIL_DATA_WIDTH = 32;
|
||||
parameter AXIL_ADDR_WIDTH = INDEX_WIDTH+4+1+$clog2(COUNT);
|
||||
parameter AXIL_STRB_WIDTH = (AXIL_DATA_WIDTH/8);
|
||||
parameter SCHEDULE_START_S = 48'h0;
|
||||
parameter SCHEDULE_START_NS = 30'h0;
|
||||
parameter SCHEDULE_PERIOD_S = 48'd0;
|
||||
parameter SCHEDULE_PERIOD_NS = 30'd1000000;
|
||||
parameter TIMESLOT_PERIOD_S = 48'd0;
|
||||
parameter TIMESLOT_PERIOD_NS = 30'd100000;
|
||||
parameter ACTIVE_PERIOD_S = 48'd0;
|
||||
parameter ACTIVE_PERIOD_NS = 30'd100000;
|
||||
|
||||
// Inputs
|
||||
reg clk = 0;
|
||||
reg rst = 0;
|
||||
reg [7:0] current_test = 0;
|
||||
|
||||
reg [COUNT-1:0] phy_tx_clk = 0;
|
||||
reg [COUNT-1:0] phy_rx_clk = 0;
|
||||
reg [COUNT*7-1:0] phy_rx_error_count = 0;
|
||||
reg [AXIL_ADDR_WIDTH-1:0] s_axil_awaddr = 0;
|
||||
reg [2:0] s_axil_awprot = 0;
|
||||
reg s_axil_awvalid = 0;
|
||||
reg [AXIL_DATA_WIDTH-1:0] s_axil_wdata = 0;
|
||||
reg [AXIL_STRB_WIDTH-1:0] s_axil_wstrb = 0;
|
||||
reg s_axil_wvalid = 0;
|
||||
reg s_axil_bready = 0;
|
||||
reg [AXIL_ADDR_WIDTH-1:0] s_axil_araddr = 0;
|
||||
reg [2:0] s_axil_arprot = 0;
|
||||
reg s_axil_arvalid = 0;
|
||||
reg s_axil_rready = 0;
|
||||
reg [95:0] ptp_ts_96 = 0;
|
||||
reg ptp_ts_step = 0;
|
||||
|
||||
// Outputs
|
||||
wire [COUNT-1:0] phy_tx_prbs31_enable;
|
||||
wire [COUNT-1:0] phy_rx_prbs31_enable;
|
||||
wire s_axil_awready;
|
||||
wire s_axil_wready;
|
||||
wire [1:0] s_axil_bresp;
|
||||
wire s_axil_bvalid;
|
||||
wire s_axil_arready;
|
||||
wire [AXIL_DATA_WIDTH-1:0] s_axil_rdata;
|
||||
wire [1:0] s_axil_rresp;
|
||||
wire s_axil_rvalid;
|
||||
|
||||
initial begin
|
||||
// myhdl integration
|
||||
$from_myhdl(
|
||||
clk,
|
||||
rst,
|
||||
current_test,
|
||||
phy_tx_clk,
|
||||
phy_rx_clk,
|
||||
phy_rx_error_count,
|
||||
s_axil_awaddr,
|
||||
s_axil_awprot,
|
||||
s_axil_awvalid,
|
||||
s_axil_wdata,
|
||||
s_axil_wstrb,
|
||||
s_axil_wvalid,
|
||||
s_axil_bready,
|
||||
s_axil_araddr,
|
||||
s_axil_arprot,
|
||||
s_axil_arvalid,
|
||||
s_axil_rready,
|
||||
ptp_ts_96,
|
||||
ptp_ts_step
|
||||
);
|
||||
$to_myhdl(
|
||||
phy_tx_prbs31_enable,
|
||||
phy_rx_prbs31_enable,
|
||||
s_axil_awready,
|
||||
s_axil_wready,
|
||||
s_axil_bresp,
|
||||
s_axil_bvalid,
|
||||
s_axil_arready,
|
||||
s_axil_rdata,
|
||||
s_axil_rresp,
|
||||
s_axil_rvalid
|
||||
);
|
||||
|
||||
// dump file
|
||||
$dumpfile("test_tdma_ber.lxt");
|
||||
$dumpvars(0, test_tdma_ber);
|
||||
end
|
||||
|
||||
tdma_ber #(
|
||||
.COUNT(COUNT),
|
||||
.INDEX_WIDTH(INDEX_WIDTH),
|
||||
.SLICE_WIDTH(SLICE_WIDTH),
|
||||
.AXIL_DATA_WIDTH(AXIL_DATA_WIDTH),
|
||||
.AXIL_ADDR_WIDTH(AXIL_ADDR_WIDTH),
|
||||
.AXIL_STRB_WIDTH(AXIL_STRB_WIDTH),
|
||||
.SCHEDULE_START_S(SCHEDULE_START_S),
|
||||
.SCHEDULE_START_NS(SCHEDULE_START_NS),
|
||||
.SCHEDULE_PERIOD_S(SCHEDULE_PERIOD_S),
|
||||
.SCHEDULE_PERIOD_NS(SCHEDULE_PERIOD_NS),
|
||||
.TIMESLOT_PERIOD_S(TIMESLOT_PERIOD_S),
|
||||
.TIMESLOT_PERIOD_NS(TIMESLOT_PERIOD_NS),
|
||||
.ACTIVE_PERIOD_S(ACTIVE_PERIOD_S),
|
||||
.ACTIVE_PERIOD_NS(ACTIVE_PERIOD_NS)
|
||||
)
|
||||
UUT (
|
||||
.clk(clk),
|
||||
.rst(rst),
|
||||
.phy_tx_clk(phy_tx_clk),
|
||||
.phy_rx_clk(phy_rx_clk),
|
||||
.phy_rx_error_count(phy_rx_error_count),
|
||||
.phy_tx_prbs31_enable(phy_tx_prbs31_enable),
|
||||
.phy_rx_prbs31_enable(phy_rx_prbs31_enable),
|
||||
.s_axil_awaddr(s_axil_awaddr),
|
||||
.s_axil_awprot(s_axil_awprot),
|
||||
.s_axil_awvalid(s_axil_awvalid),
|
||||
.s_axil_awready(s_axil_awready),
|
||||
.s_axil_wdata(s_axil_wdata),
|
||||
.s_axil_wstrb(s_axil_wstrb),
|
||||
.s_axil_wvalid(s_axil_wvalid),
|
||||
.s_axil_wready(s_axil_wready),
|
||||
.s_axil_bresp(s_axil_bresp),
|
||||
.s_axil_bvalid(s_axil_bvalid),
|
||||
.s_axil_bready(s_axil_bready),
|
||||
.s_axil_araddr(s_axil_araddr),
|
||||
.s_axil_arprot(s_axil_arprot),
|
||||
.s_axil_arvalid(s_axil_arvalid),
|
||||
.s_axil_arready(s_axil_arready),
|
||||
.s_axil_rdata(s_axil_rdata),
|
||||
.s_axil_rresp(s_axil_rresp),
|
||||
.s_axil_rvalid(s_axil_rvalid),
|
||||
.s_axil_rready(s_axil_rready),
|
||||
.ptp_ts_96(ptp_ts_96),
|
||||
.ptp_ts_step(ptp_ts_step)
|
||||
);
|
||||
|
||||
endmodule
|
@ -1,535 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
|
||||
Copyright 2019, The Regents of the University of California.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
|
||||
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of The Regents of the University of California.
|
||||
|
||||
"""
|
||||
|
||||
from myhdl import *
|
||||
import os
|
||||
import struct
|
||||
|
||||
import axil
|
||||
|
||||
module = 'tdma_ber_ch'
|
||||
testbench = 'test_%s' % module
|
||||
|
||||
srcs = []
|
||||
|
||||
srcs.append("../rtl/%s.v" % module)
|
||||
srcs.append("%s.v" % testbench)
|
||||
|
||||
src = ' '.join(srcs)
|
||||
|
||||
build_cmd = "iverilog -o %s.vvp %s" % (testbench, src)
|
||||
|
||||
def bench():
|
||||
|
||||
# Parameters
|
||||
INDEX_WIDTH = 6
|
||||
SLICE_WIDTH = 5
|
||||
AXIL_DATA_WIDTH = 32
|
||||
AXIL_ADDR_WIDTH = INDEX_WIDTH+4
|
||||
AXIL_STRB_WIDTH = (AXIL_DATA_WIDTH/8)
|
||||
|
||||
# Inputs
|
||||
clk = Signal(bool(0))
|
||||
rst = Signal(bool(0))
|
||||
current_test = Signal(intbv(0)[8:])
|
||||
|
||||
phy_tx_clk = Signal(bool(0))
|
||||
phy_rx_clk = Signal(bool(0))
|
||||
phy_rx_error_count = Signal(intbv(0)[7:])
|
||||
s_axil_awaddr = Signal(intbv(0)[AXIL_ADDR_WIDTH:])
|
||||
s_axil_awprot = Signal(intbv(0)[3:])
|
||||
s_axil_awvalid = Signal(bool(0))
|
||||
s_axil_wdata = Signal(intbv(0)[AXIL_DATA_WIDTH:])
|
||||
s_axil_wstrb = Signal(intbv(0)[AXIL_STRB_WIDTH:])
|
||||
s_axil_wvalid = Signal(bool(0))
|
||||
s_axil_bready = Signal(bool(0))
|
||||
s_axil_araddr = Signal(intbv(0)[AXIL_ADDR_WIDTH:])
|
||||
s_axil_arprot = Signal(intbv(0)[3:])
|
||||
s_axil_arvalid = Signal(bool(0))
|
||||
s_axil_rready = Signal(bool(0))
|
||||
tdma_timeslot_index = Signal(intbv(0)[INDEX_WIDTH:])
|
||||
tdma_timeslot_start = Signal(bool(0))
|
||||
tdma_timeslot_active = Signal(bool(0))
|
||||
|
||||
# Outputs
|
||||
phy_tx_prbs31_enable = Signal(bool(0))
|
||||
phy_rx_prbs31_enable = Signal(bool(0))
|
||||
s_axil_awready = Signal(bool(0))
|
||||
s_axil_wready = Signal(bool(0))
|
||||
s_axil_bresp = Signal(intbv(0)[2:])
|
||||
s_axil_bvalid = Signal(bool(0))
|
||||
s_axil_arready = Signal(bool(0))
|
||||
s_axil_rdata = Signal(intbv(0)[AXIL_DATA_WIDTH:])
|
||||
s_axil_rresp = Signal(intbv(0)[2:])
|
||||
s_axil_rvalid = Signal(bool(0))
|
||||
|
||||
# AXI4-Lite master
|
||||
axil_master_inst = axil.AXILiteMaster()
|
||||
axil_master_pause = Signal(bool(False))
|
||||
|
||||
axil_master_logic = axil_master_inst.create_logic(
|
||||
clk,
|
||||
rst,
|
||||
m_axil_awaddr=s_axil_awaddr,
|
||||
m_axil_awprot=s_axil_awprot,
|
||||
m_axil_awvalid=s_axil_awvalid,
|
||||
m_axil_awready=s_axil_awready,
|
||||
m_axil_wdata=s_axil_wdata,
|
||||
m_axil_wstrb=s_axil_wstrb,
|
||||
m_axil_wvalid=s_axil_wvalid,
|
||||
m_axil_wready=s_axil_wready,
|
||||
m_axil_bresp=s_axil_bresp,
|
||||
m_axil_bvalid=s_axil_bvalid,
|
||||
m_axil_bready=s_axil_bready,
|
||||
m_axil_araddr=s_axil_araddr,
|
||||
m_axil_arprot=s_axil_arprot,
|
||||
m_axil_arvalid=s_axil_arvalid,
|
||||
m_axil_arready=s_axil_arready,
|
||||
m_axil_rdata=s_axil_rdata,
|
||||
m_axil_rresp=s_axil_rresp,
|
||||
m_axil_rvalid=s_axil_rvalid,
|
||||
m_axil_rready=s_axil_rready,
|
||||
pause=axil_master_pause,
|
||||
name='master'
|
||||
)
|
||||
|
||||
# DUT
|
||||
if os.system(build_cmd):
|
||||
raise Exception("Error running build command")
|
||||
|
||||
dut = Cosimulation(
|
||||
"vvp -m myhdl %s.vvp -lxt2" % testbench,
|
||||
clk=clk,
|
||||
rst=rst,
|
||||
current_test=current_test,
|
||||
phy_tx_clk=phy_tx_clk,
|
||||
phy_rx_clk=phy_rx_clk,
|
||||
phy_rx_error_count=phy_rx_error_count,
|
||||
phy_tx_prbs31_enable=phy_tx_prbs31_enable,
|
||||
phy_rx_prbs31_enable=phy_rx_prbs31_enable,
|
||||
s_axil_awaddr=s_axil_awaddr,
|
||||
s_axil_awprot=s_axil_awprot,
|
||||
s_axil_awvalid=s_axil_awvalid,
|
||||
s_axil_awready=s_axil_awready,
|
||||
s_axil_wdata=s_axil_wdata,
|
||||
s_axil_wstrb=s_axil_wstrb,
|
||||
s_axil_wvalid=s_axil_wvalid,
|
||||
s_axil_wready=s_axil_wready,
|
||||
s_axil_bresp=s_axil_bresp,
|
||||
s_axil_bvalid=s_axil_bvalid,
|
||||
s_axil_bready=s_axil_bready,
|
||||
s_axil_araddr=s_axil_araddr,
|
||||
s_axil_arprot=s_axil_arprot,
|
||||
s_axil_arvalid=s_axil_arvalid,
|
||||
s_axil_arready=s_axil_arready,
|
||||
s_axil_rdata=s_axil_rdata,
|
||||
s_axil_rresp=s_axil_rresp,
|
||||
s_axil_rvalid=s_axil_rvalid,
|
||||
s_axil_rready=s_axil_rready,
|
||||
tdma_timeslot_index=tdma_timeslot_index,
|
||||
tdma_timeslot_start=tdma_timeslot_start,
|
||||
tdma_timeslot_active=tdma_timeslot_active
|
||||
)
|
||||
|
||||
@always(delay(4))
|
||||
def clkgen():
|
||||
clk.next = not clk
|
||||
|
||||
@always(delay(3))
|
||||
def clkgen2():
|
||||
phy_tx_clk.next = not phy_tx_clk
|
||||
phy_rx_clk.next = not phy_rx_clk
|
||||
|
||||
@instance
|
||||
def check():
|
||||
yield delay(100)
|
||||
yield clk.posedge
|
||||
rst.next = 1
|
||||
yield clk.posedge
|
||||
rst.next = 0
|
||||
yield clk.posedge
|
||||
yield delay(100)
|
||||
yield clk.posedge
|
||||
|
||||
# testbench stimulus
|
||||
|
||||
yield clk.posedge
|
||||
print("test 1: test error counts")
|
||||
current_test.next = 1
|
||||
|
||||
axil_master_inst.init_write(0x0000, struct.pack('<L', 0x00000003))
|
||||
axil_master_inst.init_write(0x0020, struct.pack('<L', 0x00000001))
|
||||
|
||||
axil_master_inst.init_read(0x0014, 12)
|
||||
axil_master_inst.init_read(0x0200, 32)
|
||||
|
||||
yield axil_master_inst.wait()
|
||||
|
||||
axil_master_inst.init_write(0x0200, b'\x00'*32)
|
||||
|
||||
data = axil_master_inst.get_read_data()
|
||||
data = struct.unpack('<LLL', data[1])
|
||||
print(data)
|
||||
|
||||
data2 = axil_master_inst.get_read_data()
|
||||
data2 = struct.unpack('<8L', data2[1])
|
||||
print(data2)
|
||||
|
||||
yield clk.posedge
|
||||
for l in range(5):
|
||||
for k in range(4):
|
||||
tdma_timeslot_index.next = k
|
||||
tdma_timeslot_start.next = 1
|
||||
tdma_timeslot_active.next = 1
|
||||
yield clk.posedge
|
||||
tdma_timeslot_start.next = 0
|
||||
for k in range(49):
|
||||
yield clk.posedge
|
||||
tdma_timeslot_active.next = 0
|
||||
|
||||
axil_master_inst.init_read(0x0014, 12)
|
||||
axil_master_inst.init_read(0x0200, 32)
|
||||
|
||||
yield axil_master_inst.wait()
|
||||
|
||||
axil_master_inst.init_write(0x0200, b'\x00'*32)
|
||||
|
||||
yield axil_master_inst.wait()
|
||||
|
||||
data = axil_master_inst.get_read_data()
|
||||
data = struct.unpack('<LLL', data[1])
|
||||
print(data)
|
||||
|
||||
data2 = axil_master_inst.get_read_data()
|
||||
data2 = struct.unpack('<8L', data2[1])
|
||||
print(data2)
|
||||
|
||||
phy_rx_error_count.next = 1
|
||||
|
||||
yield clk.posedge
|
||||
for l in range(5):
|
||||
for k in range(4):
|
||||
tdma_timeslot_index.next = k
|
||||
tdma_timeslot_start.next = 1
|
||||
tdma_timeslot_active.next = 1
|
||||
yield clk.posedge
|
||||
tdma_timeslot_start.next = 0
|
||||
for k in range(49):
|
||||
yield clk.posedge
|
||||
tdma_timeslot_active.next = 0
|
||||
|
||||
phy_rx_error_count.next = 0
|
||||
|
||||
axil_master_inst.init_read(0x0014, 12)
|
||||
axil_master_inst.init_read(0x0200, 32)
|
||||
|
||||
yield axil_master_inst.wait()
|
||||
|
||||
axil_master_inst.init_write(0x0200, b'\x00'*32)
|
||||
|
||||
yield axil_master_inst.wait()
|
||||
|
||||
data = axil_master_inst.get_read_data()
|
||||
data = struct.unpack('<LLL', data[1])
|
||||
print(data)
|
||||
|
||||
data2 = axil_master_inst.get_read_data()
|
||||
data2 = struct.unpack('<8L', data2[1])
|
||||
print(data2)
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 2: change duty cycle")
|
||||
current_test.next = 2
|
||||
|
||||
axil_master_inst.init_write(0x0000, struct.pack('<L', 0x00000003))
|
||||
axil_master_inst.init_write(0x0020, struct.pack('<L', 0x00000001))
|
||||
|
||||
axil_master_inst.init_read(0x0014, 12)
|
||||
axil_master_inst.init_read(0x0200, 32)
|
||||
|
||||
yield axil_master_inst.wait()
|
||||
|
||||
axil_master_inst.init_write(0x0200, b'\x00'*32)
|
||||
|
||||
yield axil_master_inst.wait()
|
||||
|
||||
data = axil_master_inst.get_read_data()
|
||||
data = struct.unpack('<LLL', data[1])
|
||||
print(data)
|
||||
|
||||
data2 = axil_master_inst.get_read_data()
|
||||
data2 = struct.unpack('<8L', data2[1])
|
||||
print(data2)
|
||||
|
||||
yield clk.posedge
|
||||
for l in range(5):
|
||||
for k in range(4):
|
||||
tdma_timeslot_index.next = k
|
||||
tdma_timeslot_start.next = 1
|
||||
tdma_timeslot_active.next = 1
|
||||
yield clk.posedge
|
||||
tdma_timeslot_start.next = 0
|
||||
for k in range(39):
|
||||
yield clk.posedge
|
||||
tdma_timeslot_active.next = 0
|
||||
for k in range(10):
|
||||
yield clk.posedge
|
||||
|
||||
axil_master_inst.init_read(0x0014, 12)
|
||||
axil_master_inst.init_read(0x0200, 32)
|
||||
|
||||
yield axil_master_inst.wait()
|
||||
|
||||
axil_master_inst.init_write(0x0200, b'\x00'*32)
|
||||
|
||||
yield axil_master_inst.wait()
|
||||
|
||||
data = axil_master_inst.get_read_data()
|
||||
data = struct.unpack('<LLL', data[1])
|
||||
print(data)
|
||||
|
||||
data2 = axil_master_inst.get_read_data()
|
||||
data2 = struct.unpack('<8L', data2[1])
|
||||
print(data2)
|
||||
|
||||
phy_rx_error_count.next = 1
|
||||
|
||||
yield clk.posedge
|
||||
for l in range(5):
|
||||
for k in range(4):
|
||||
tdma_timeslot_index.next = k
|
||||
tdma_timeslot_start.next = 1
|
||||
tdma_timeslot_active.next = 1
|
||||
yield clk.posedge
|
||||
tdma_timeslot_start.next = 0
|
||||
for k in range(39):
|
||||
yield clk.posedge
|
||||
tdma_timeslot_active.next = 0
|
||||
for k in range(10):
|
||||
yield clk.posedge
|
||||
|
||||
phy_rx_error_count.next = 0
|
||||
|
||||
axil_master_inst.init_read(0x0014, 12)
|
||||
axil_master_inst.init_read(0x0200, 32)
|
||||
|
||||
yield axil_master_inst.wait()
|
||||
|
||||
axil_master_inst.init_write(0x0200, b'\x00'*32)
|
||||
|
||||
yield axil_master_inst.wait()
|
||||
|
||||
data = axil_master_inst.get_read_data()
|
||||
data = struct.unpack('<LLL', data[1])
|
||||
print(data)
|
||||
|
||||
data2 = axil_master_inst.get_read_data()
|
||||
data2 = struct.unpack('<8L', data2[1])
|
||||
print(data2)
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 3: test slices")
|
||||
current_test.next = 3
|
||||
|
||||
axil_master_inst.init_write(0x0000, struct.pack('<L', 0x00000003))
|
||||
axil_master_inst.init_write(0x0020, struct.pack('<L', 0x00000003))
|
||||
axil_master_inst.init_write(0x0024, struct.pack('<L', 0x00000010))
|
||||
axil_master_inst.init_write(0x0028, struct.pack('<L', 0x00000020))
|
||||
|
||||
axil_master_inst.init_read(0x0014, 12)
|
||||
|
||||
axil_master_inst.init_write(0x0030, struct.pack('<L', 0x00000000))
|
||||
yield axil_master_inst.wait()
|
||||
axil_master_inst.init_read(0x0200, 32)
|
||||
yield axil_master_inst.wait()
|
||||
axil_master_inst.init_write(0x0200, b'\x00'*32)
|
||||
yield axil_master_inst.wait()
|
||||
|
||||
axil_master_inst.init_write(0x0030, struct.pack('<L', 0x00000001))
|
||||
yield axil_master_inst.wait()
|
||||
axil_master_inst.init_read(0x0200, 32)
|
||||
yield axil_master_inst.wait()
|
||||
axil_master_inst.init_write(0x0200, b'\x00'*32)
|
||||
yield axil_master_inst.wait()
|
||||
|
||||
axil_master_inst.init_write(0x0030, struct.pack('<L', 0x00000002))
|
||||
yield axil_master_inst.wait()
|
||||
axil_master_inst.init_read(0x0200, 32)
|
||||
yield axil_master_inst.wait()
|
||||
axil_master_inst.init_write(0x0200, b'\x00'*32)
|
||||
yield axil_master_inst.wait()
|
||||
|
||||
data = axil_master_inst.get_read_data()
|
||||
data = struct.unpack('<LLL', data[1])
|
||||
print(data)
|
||||
|
||||
data2 = axil_master_inst.get_read_data()
|
||||
data2 = struct.unpack('<8L', data2[1])
|
||||
print(data2)
|
||||
|
||||
data2 = axil_master_inst.get_read_data()
|
||||
data2 = struct.unpack('<8L', data2[1])
|
||||
print(data2)
|
||||
|
||||
data2 = axil_master_inst.get_read_data()
|
||||
data2 = struct.unpack('<8L', data2[1])
|
||||
print(data2)
|
||||
|
||||
yield clk.posedge
|
||||
for l in range(5):
|
||||
for k in range(4):
|
||||
tdma_timeslot_index.next = k
|
||||
tdma_timeslot_start.next = 1
|
||||
tdma_timeslot_active.next = 1
|
||||
yield clk.posedge
|
||||
tdma_timeslot_start.next = 0
|
||||
for k in range(399):
|
||||
yield clk.posedge
|
||||
tdma_timeslot_active.next = 0
|
||||
for k in range(100):
|
||||
yield clk.posedge
|
||||
|
||||
axil_master_inst.init_read(0x0014, 12)
|
||||
|
||||
axil_master_inst.init_write(0x0030, struct.pack('<L', 0x00000000))
|
||||
yield axil_master_inst.wait()
|
||||
axil_master_inst.init_read(0x0200, 32)
|
||||
yield axil_master_inst.wait()
|
||||
axil_master_inst.init_write(0x0200, b'\x00'*32)
|
||||
yield axil_master_inst.wait()
|
||||
|
||||
axil_master_inst.init_write(0x0030, struct.pack('<L', 0x00000001))
|
||||
yield axil_master_inst.wait()
|
||||
axil_master_inst.init_read(0x0200, 32)
|
||||
yield axil_master_inst.wait()
|
||||
axil_master_inst.init_write(0x0200, b'\x00'*32)
|
||||
yield axil_master_inst.wait()
|
||||
|
||||
axil_master_inst.init_write(0x0030, struct.pack('<L', 0x00000002))
|
||||
yield axil_master_inst.wait()
|
||||
axil_master_inst.init_read(0x0200, 32)
|
||||
yield axil_master_inst.wait()
|
||||
axil_master_inst.init_write(0x0200, b'\x00'*32)
|
||||
yield axil_master_inst.wait()
|
||||
|
||||
data = axil_master_inst.get_read_data()
|
||||
data = struct.unpack('<LLL', data[1])
|
||||
print(data)
|
||||
|
||||
data2 = axil_master_inst.get_read_data()
|
||||
data2 = struct.unpack('<8L', data2[1])
|
||||
print(data2)
|
||||
|
||||
data2 = axil_master_inst.get_read_data()
|
||||
data2 = struct.unpack('<8L', data2[1])
|
||||
print(data2)
|
||||
|
||||
data2 = axil_master_inst.get_read_data()
|
||||
data2 = struct.unpack('<8L', data2[1])
|
||||
print(data2)
|
||||
|
||||
phy_rx_error_count.next = 1
|
||||
|
||||
yield clk.posedge
|
||||
for l in range(5):
|
||||
for k in range(4):
|
||||
tdma_timeslot_index.next = k
|
||||
tdma_timeslot_start.next = 1
|
||||
tdma_timeslot_active.next = 1
|
||||
yield clk.posedge
|
||||
tdma_timeslot_start.next = 0
|
||||
for k in range(399):
|
||||
yield clk.posedge
|
||||
tdma_timeslot_active.next = 0
|
||||
for k in range(100):
|
||||
yield clk.posedge
|
||||
|
||||
phy_rx_error_count.next = 0
|
||||
|
||||
axil_master_inst.init_read(0x0014, 12)
|
||||
|
||||
axil_master_inst.init_write(0x0030, struct.pack('<L', 0x00000000))
|
||||
yield axil_master_inst.wait()
|
||||
axil_master_inst.init_read(0x0200, 32)
|
||||
yield axil_master_inst.wait()
|
||||
axil_master_inst.init_write(0x0200, b'\x00'*32)
|
||||
yield axil_master_inst.wait()
|
||||
|
||||
axil_master_inst.init_write(0x0030, struct.pack('<L', 0x00000001))
|
||||
yield axil_master_inst.wait()
|
||||
axil_master_inst.init_read(0x0200, 32)
|
||||
yield axil_master_inst.wait()
|
||||
axil_master_inst.init_write(0x0200, b'\x00'*32)
|
||||
yield axil_master_inst.wait()
|
||||
|
||||
axil_master_inst.init_write(0x0030, struct.pack('<L', 0x00000002))
|
||||
yield axil_master_inst.wait()
|
||||
axil_master_inst.init_read(0x0200, 32)
|
||||
yield axil_master_inst.wait()
|
||||
axil_master_inst.init_write(0x0200, b'\x00'*32)
|
||||
yield axil_master_inst.wait()
|
||||
|
||||
data = axil_master_inst.get_read_data()
|
||||
data = struct.unpack('<LLL', data[1])
|
||||
print(data)
|
||||
|
||||
data2 = axil_master_inst.get_read_data()
|
||||
data2 = struct.unpack('<8L', data2[1])
|
||||
print(data2)
|
||||
|
||||
data2 = axil_master_inst.get_read_data()
|
||||
data2 = struct.unpack('<8L', data2[1])
|
||||
print(data2)
|
||||
|
||||
data2 = axil_master_inst.get_read_data()
|
||||
data2 = struct.unpack('<8L', data2[1])
|
||||
print(data2)
|
||||
|
||||
yield delay(100)
|
||||
|
||||
raise StopSimulation
|
||||
|
||||
return instances()
|
||||
|
||||
def test_bench():
|
||||
sim = Simulation(bench())
|
||||
sim.run()
|
||||
|
||||
if __name__ == '__main__':
|
||||
print("Running test...")
|
||||
test_bench()
|
@ -1,166 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright 2019, The Regents of the University of California.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
|
||||
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of The Regents of the University of California.
|
||||
|
||||
*/
|
||||
|
||||
// Language: Verilog 2001
|
||||
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
/*
|
||||
* Testbench for tdma_ber_ch
|
||||
*/
|
||||
module test_tdma_ber_ch;
|
||||
|
||||
// Parameters
|
||||
parameter INDEX_WIDTH = 6;
|
||||
parameter SLICE_WIDTH = 5;
|
||||
parameter AXIL_DATA_WIDTH = 32;
|
||||
parameter AXIL_ADDR_WIDTH = INDEX_WIDTH+4;
|
||||
parameter AXIL_STRB_WIDTH = (AXIL_DATA_WIDTH/8);
|
||||
|
||||
// Inputs
|
||||
reg clk = 0;
|
||||
reg rst = 0;
|
||||
reg [7:0] current_test = 0;
|
||||
|
||||
reg phy_tx_clk = 0;
|
||||
reg phy_rx_clk = 0;
|
||||
reg [6:0] phy_rx_error_count = 0;
|
||||
reg [AXIL_ADDR_WIDTH-1:0] s_axil_awaddr = 0;
|
||||
reg [2:0] s_axil_awprot = 0;
|
||||
reg s_axil_awvalid = 0;
|
||||
reg [AXIL_DATA_WIDTH-1:0] s_axil_wdata = 0;
|
||||
reg [AXIL_STRB_WIDTH-1:0] s_axil_wstrb = 0;
|
||||
reg s_axil_wvalid = 0;
|
||||
reg s_axil_bready = 0;
|
||||
reg [AXIL_ADDR_WIDTH-1:0] s_axil_araddr = 0;
|
||||
reg [2:0] s_axil_arprot = 0;
|
||||
reg s_axil_arvalid = 0;
|
||||
reg s_axil_rready = 0;
|
||||
reg [INDEX_WIDTH-1:0] tdma_timeslot_index = 0;
|
||||
reg tdma_timeslot_start = 0;
|
||||
reg tdma_timeslot_active = 0;
|
||||
|
||||
// Outputs
|
||||
wire phy_tx_prbs31_enable;
|
||||
wire phy_rx_prbs31_enable;
|
||||
wire s_axil_awready;
|
||||
wire s_axil_wready;
|
||||
wire [1:0] s_axil_bresp;
|
||||
wire s_axil_bvalid;
|
||||
wire s_axil_arready;
|
||||
wire [AXIL_DATA_WIDTH-1:0] s_axil_rdata;
|
||||
wire [1:0] s_axil_rresp;
|
||||
wire s_axil_rvalid;
|
||||
|
||||
initial begin
|
||||
// myhdl integration
|
||||
$from_myhdl(
|
||||
clk,
|
||||
rst,
|
||||
current_test,
|
||||
phy_tx_clk,
|
||||
phy_rx_clk,
|
||||
phy_rx_error_count,
|
||||
s_axil_awaddr,
|
||||
s_axil_awprot,
|
||||
s_axil_awvalid,
|
||||
s_axil_wdata,
|
||||
s_axil_wstrb,
|
||||
s_axil_wvalid,
|
||||
s_axil_bready,
|
||||
s_axil_araddr,
|
||||
s_axil_arprot,
|
||||
s_axil_arvalid,
|
||||
s_axil_rready,
|
||||
tdma_timeslot_index,
|
||||
tdma_timeslot_start,
|
||||
tdma_timeslot_active
|
||||
);
|
||||
$to_myhdl(
|
||||
phy_tx_prbs31_enable,
|
||||
phy_rx_prbs31_enable,
|
||||
s_axil_awready,
|
||||
s_axil_wready,
|
||||
s_axil_bresp,
|
||||
s_axil_bvalid,
|
||||
s_axil_arready,
|
||||
s_axil_rdata,
|
||||
s_axil_rresp,
|
||||
s_axil_rvalid
|
||||
);
|
||||
|
||||
// dump file
|
||||
$dumpfile("test_tdma_ber_ch.lxt");
|
||||
$dumpvars(0, test_tdma_ber_ch);
|
||||
end
|
||||
|
||||
tdma_ber_ch #(
|
||||
.INDEX_WIDTH(INDEX_WIDTH),
|
||||
.SLICE_WIDTH(SLICE_WIDTH),
|
||||
.AXIL_DATA_WIDTH(AXIL_DATA_WIDTH),
|
||||
.AXIL_ADDR_WIDTH(AXIL_ADDR_WIDTH),
|
||||
.AXIL_STRB_WIDTH(AXIL_STRB_WIDTH)
|
||||
)
|
||||
UUT (
|
||||
.clk(clk),
|
||||
.rst(rst),
|
||||
.phy_tx_clk(phy_tx_clk),
|
||||
.phy_rx_clk(phy_rx_clk),
|
||||
.phy_rx_error_count(phy_rx_error_count),
|
||||
.phy_tx_prbs31_enable(phy_tx_prbs31_enable),
|
||||
.phy_rx_prbs31_enable(phy_rx_prbs31_enable),
|
||||
.s_axil_awaddr(s_axil_awaddr),
|
||||
.s_axil_awprot(s_axil_awprot),
|
||||
.s_axil_awvalid(s_axil_awvalid),
|
||||
.s_axil_awready(s_axil_awready),
|
||||
.s_axil_wdata(s_axil_wdata),
|
||||
.s_axil_wstrb(s_axil_wstrb),
|
||||
.s_axil_wvalid(s_axil_wvalid),
|
||||
.s_axil_wready(s_axil_wready),
|
||||
.s_axil_bresp(s_axil_bresp),
|
||||
.s_axil_bvalid(s_axil_bvalid),
|
||||
.s_axil_bready(s_axil_bready),
|
||||
.s_axil_araddr(s_axil_araddr),
|
||||
.s_axil_arprot(s_axil_arprot),
|
||||
.s_axil_arvalid(s_axil_arvalid),
|
||||
.s_axil_arready(s_axil_arready),
|
||||
.s_axil_rdata(s_axil_rdata),
|
||||
.s_axil_rresp(s_axil_rresp),
|
||||
.s_axil_rvalid(s_axil_rvalid),
|
||||
.s_axil_rready(s_axil_rready),
|
||||
.tdma_timeslot_index(tdma_timeslot_index),
|
||||
.tdma_timeslot_start(tdma_timeslot_start),
|
||||
.tdma_timeslot_active(tdma_timeslot_active)
|
||||
);
|
||||
|
||||
endmodule
|
@ -1,180 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
|
||||
Copyright 2019, The Regents of the University of California.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
|
||||
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of The Regents of the University of California.
|
||||
|
||||
"""
|
||||
|
||||
from myhdl import *
|
||||
import os
|
||||
|
||||
import ptp
|
||||
|
||||
module = 'tdma_scheduler'
|
||||
testbench = 'test_%s' % module
|
||||
|
||||
srcs = []
|
||||
|
||||
srcs.append("../rtl/%s.v" % module)
|
||||
srcs.append("%s.v" % testbench)
|
||||
|
||||
src = ' '.join(srcs)
|
||||
|
||||
build_cmd = "iverilog -o %s.vvp %s" % (testbench, src)
|
||||
|
||||
def bench():
|
||||
|
||||
# Parameters
|
||||
INDEX_WIDTH = 8
|
||||
SCHEDULE_START_S = 0x0
|
||||
SCHEDULE_START_NS = 0x0
|
||||
SCHEDULE_PERIOD_S = 0
|
||||
SCHEDULE_PERIOD_NS = 1000000
|
||||
TIMESLOT_PERIOD_S = 0
|
||||
TIMESLOT_PERIOD_NS = 100000
|
||||
|
||||
# Inputs
|
||||
clk = Signal(bool(0))
|
||||
rst = Signal(bool(0))
|
||||
current_test = Signal(intbv(0)[8:])
|
||||
|
||||
input_ts_96 = Signal(intbv(0)[96:])
|
||||
input_ts_step = Signal(bool(0))
|
||||
enable = Signal(bool(0))
|
||||
input_schedule_start = Signal(intbv(0)[80:])
|
||||
input_schedule_start_valid = Signal(bool(0))
|
||||
input_schedule_period = Signal(intbv(0)[80:])
|
||||
input_schedule_period_valid = Signal(bool(0))
|
||||
input_timeslot_period = Signal(intbv(0)[80:])
|
||||
input_timeslot_period_valid = Signal(bool(0))
|
||||
input_active_period = Signal(intbv(0)[80:])
|
||||
input_active_period_valid = Signal(bool(0))
|
||||
|
||||
# Outputs
|
||||
locked = Signal(bool(0))
|
||||
error = Signal(bool(0))
|
||||
schedule_start = Signal(bool(0))
|
||||
timeslot_index = Signal(intbv(0)[INDEX_WIDTH:])
|
||||
timeslot_start = Signal(bool(0))
|
||||
timeslot_end = Signal(bool(0))
|
||||
timeslot_active = Signal(bool(0))
|
||||
|
||||
# PTP clock
|
||||
ptp_clock = ptp.PtpClock()
|
||||
|
||||
ptp_logic = ptp_clock.create_logic(
|
||||
clk,
|
||||
rst,
|
||||
ts_96=input_ts_96
|
||||
)
|
||||
|
||||
# DUT
|
||||
if os.system(build_cmd):
|
||||
raise Exception("Error running build command")
|
||||
|
||||
dut = Cosimulation(
|
||||
"vvp -m myhdl %s.vvp -lxt2" % testbench,
|
||||
clk=clk,
|
||||
rst=rst,
|
||||
current_test=current_test,
|
||||
input_ts_96=input_ts_96,
|
||||
input_ts_step=input_ts_step,
|
||||
enable=enable,
|
||||
input_schedule_start=input_schedule_start,
|
||||
input_schedule_start_valid=input_schedule_start_valid,
|
||||
input_schedule_period=input_schedule_period,
|
||||
input_schedule_period_valid=input_schedule_period_valid,
|
||||
input_timeslot_period=input_timeslot_period,
|
||||
input_timeslot_period_valid=input_timeslot_period_valid,
|
||||
input_active_period=input_active_period,
|
||||
input_active_period_valid=input_active_period_valid,
|
||||
locked=locked,
|
||||
error=error,
|
||||
schedule_start=schedule_start,
|
||||
timeslot_index=timeslot_index,
|
||||
timeslot_start=timeslot_start,
|
||||
timeslot_end=timeslot_end,
|
||||
timeslot_active=timeslot_active
|
||||
)
|
||||
|
||||
@always(delay(4))
|
||||
def clkgen():
|
||||
clk.next = not clk
|
||||
|
||||
@instance
|
||||
def check():
|
||||
yield delay(100)
|
||||
yield clk.posedge
|
||||
rst.next = 1
|
||||
yield clk.posedge
|
||||
rst.next = 0
|
||||
yield clk.posedge
|
||||
yield delay(100)
|
||||
yield clk.posedge
|
||||
|
||||
# testbench stimulus
|
||||
|
||||
enable.next = 1
|
||||
|
||||
yield clk.posedge
|
||||
print("test 1: Test pulse out")
|
||||
current_test.next = 1
|
||||
|
||||
input_schedule_start.next = 1000
|
||||
input_schedule_start_valid.next = 1
|
||||
input_schedule_period.next = 2000
|
||||
input_schedule_period_valid.next = 1
|
||||
input_timeslot_period.next = 400
|
||||
input_timeslot_period_valid.next = 1
|
||||
input_active_period.next = 300
|
||||
input_active_period_valid.next = 1
|
||||
|
||||
yield clk.posedge
|
||||
|
||||
input_schedule_start_valid.next = 0
|
||||
input_schedule_period_valid.next = 0
|
||||
input_timeslot_period_valid.next = 0
|
||||
input_active_period_valid.next = 0
|
||||
|
||||
yield delay(10000)
|
||||
|
||||
yield delay(100)
|
||||
|
||||
raise StopSimulation
|
||||
|
||||
return instances()
|
||||
|
||||
def test_bench():
|
||||
sim = Simulation(bench())
|
||||
sim.run()
|
||||
|
||||
if __name__ == '__main__':
|
||||
print("Running test...")
|
||||
test_bench()
|
@ -1,147 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright 2019, The Regents of the University of California.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
|
||||
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of The Regents of the University of California.
|
||||
|
||||
*/
|
||||
|
||||
// Language: Verilog 2001
|
||||
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
/*
|
||||
* Testbench for tdma_scheduler
|
||||
*/
|
||||
module test_tdma_scheduler;
|
||||
|
||||
// Parameters
|
||||
parameter INDEX_WIDTH = 8;
|
||||
parameter SCHEDULE_START_S = 48'h0;
|
||||
parameter SCHEDULE_START_NS = 30'h0;
|
||||
parameter SCHEDULE_PERIOD_S = 48'd0;
|
||||
parameter SCHEDULE_PERIOD_NS = 30'd1000000;
|
||||
parameter TIMESLOT_PERIOD_S = 48'd0;
|
||||
parameter TIMESLOT_PERIOD_NS = 30'd100000;
|
||||
parameter ACTIVE_PERIOD_S = 48'd0;
|
||||
parameter ACTIVE_PERIOD_NS = 30'd100000;
|
||||
|
||||
// Inputs
|
||||
reg clk = 0;
|
||||
reg rst = 0;
|
||||
reg [7:0] current_test = 0;
|
||||
|
||||
reg [95:0] input_ts_96 = 0;
|
||||
reg input_ts_step = 0;
|
||||
reg enable = 0;
|
||||
reg [79:0] input_schedule_start = 0;
|
||||
reg input_schedule_start_valid = 0;
|
||||
reg [79:0] input_schedule_period = 0;
|
||||
reg input_schedule_period_valid = 0;
|
||||
reg [79:0] input_timeslot_period = 0;
|
||||
reg input_timeslot_period_valid = 0;
|
||||
reg [79:0] input_active_period = 0;
|
||||
reg input_active_period_valid = 0;
|
||||
|
||||
// Outputs
|
||||
wire locked;
|
||||
wire error;
|
||||
wire schedule_start;
|
||||
wire [INDEX_WIDTH-1:0] timeslot_index;
|
||||
wire timeslot_start;
|
||||
wire timeslot_end;
|
||||
wire timeslot_active;
|
||||
|
||||
initial begin
|
||||
// myhdl integration
|
||||
$from_myhdl(
|
||||
clk,
|
||||
rst,
|
||||
current_test,
|
||||
input_ts_96,
|
||||
input_ts_step,
|
||||
enable,
|
||||
input_schedule_start,
|
||||
input_schedule_start_valid,
|
||||
input_schedule_period,
|
||||
input_schedule_period_valid,
|
||||
input_timeslot_period,
|
||||
input_timeslot_period_valid,
|
||||
input_active_period,
|
||||
input_active_period_valid
|
||||
);
|
||||
$to_myhdl(
|
||||
locked,
|
||||
error,
|
||||
schedule_start,
|
||||
timeslot_index,
|
||||
timeslot_start,
|
||||
timeslot_end,
|
||||
timeslot_active
|
||||
);
|
||||
|
||||
// dump file
|
||||
$dumpfile("test_tdma_scheduler.lxt");
|
||||
$dumpvars(0, test_tdma_scheduler);
|
||||
end
|
||||
|
||||
tdma_scheduler #(
|
||||
.INDEX_WIDTH(INDEX_WIDTH),
|
||||
.SCHEDULE_START_S(SCHEDULE_START_S),
|
||||
.SCHEDULE_START_NS(SCHEDULE_START_NS),
|
||||
.SCHEDULE_PERIOD_S(SCHEDULE_PERIOD_S),
|
||||
.SCHEDULE_PERIOD_NS(SCHEDULE_PERIOD_NS),
|
||||
.TIMESLOT_PERIOD_S(TIMESLOT_PERIOD_S),
|
||||
.TIMESLOT_PERIOD_NS(TIMESLOT_PERIOD_NS),
|
||||
.ACTIVE_PERIOD_S(ACTIVE_PERIOD_S),
|
||||
.ACTIVE_PERIOD_NS(ACTIVE_PERIOD_NS)
|
||||
)
|
||||
UUT (
|
||||
.clk(clk),
|
||||
.rst(rst),
|
||||
.input_ts_96(input_ts_96),
|
||||
.input_ts_step(input_ts_step),
|
||||
.enable(enable),
|
||||
.input_schedule_start(input_schedule_start),
|
||||
.input_schedule_start_valid(input_schedule_start_valid),
|
||||
.input_schedule_period(input_schedule_period),
|
||||
.input_schedule_period_valid(input_schedule_period_valid),
|
||||
.input_timeslot_period(input_timeslot_period),
|
||||
.input_timeslot_period_valid(input_timeslot_period_valid),
|
||||
.input_active_period(input_active_period),
|
||||
.input_active_period_valid(input_active_period_valid),
|
||||
.locked(locked),
|
||||
.error(error),
|
||||
.schedule_start(schedule_start),
|
||||
.timeslot_index(timeslot_index),
|
||||
.timeslot_start(timeslot_start),
|
||||
.timeslot_end(timeslot_end),
|
||||
.timeslot_active(timeslot_active)
|
||||
);
|
||||
|
||||
endmodule
|
@ -1,571 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
|
||||
Copyright 2019, The Regents of the University of California.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
|
||||
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of The Regents of the University of California.
|
||||
|
||||
"""
|
||||
|
||||
from myhdl import *
|
||||
import os
|
||||
|
||||
import struct
|
||||
|
||||
import axis_ep
|
||||
import eth_ep
|
||||
import udp_ep
|
||||
|
||||
module = 'tx_checksum'
|
||||
testbench = 'test_%s_256' % module
|
||||
|
||||
srcs = []
|
||||
|
||||
srcs.append("../rtl/%s.v" % module)
|
||||
srcs.append("../lib/axis/rtl/axis_fifo.v")
|
||||
srcs.append("%s.v" % testbench)
|
||||
|
||||
src = ' '.join(srcs)
|
||||
|
||||
build_cmd = "iverilog -o %s.vvp %s" % (testbench, src)
|
||||
|
||||
def frame_checksum(frame, offset=14):
|
||||
data = bytearray()
|
||||
if isinstance(frame, eth_ep.EthFrame):
|
||||
data = frame.payload.data[offset-14:]
|
||||
elif isinstance(frame, axis_ep.AXIStreamFrame):
|
||||
data = frame.data[offset:]
|
||||
else:
|
||||
return None
|
||||
|
||||
csum = 0
|
||||
odd = False
|
||||
|
||||
for b in data:
|
||||
if odd:
|
||||
csum += b
|
||||
else:
|
||||
csum += b << 8
|
||||
odd = not odd
|
||||
|
||||
csum = (csum & 0xffff) + (csum >> 16)
|
||||
csum = (csum & 0xffff) + (csum >> 16)
|
||||
|
||||
return csum
|
||||
|
||||
def bench():
|
||||
|
||||
# Parameters
|
||||
DATA_WIDTH = 256
|
||||
KEEP_WIDTH = (DATA_WIDTH/8)
|
||||
ID_ENABLE = 0
|
||||
ID_WIDTH = 8
|
||||
DEST_ENABLE = 0
|
||||
DEST_WIDTH = 8
|
||||
USER_ENABLE = 1
|
||||
USER_WIDTH = 1
|
||||
USE_INIT_VALUE = 1
|
||||
DATA_FIFO_DEPTH = 4096
|
||||
CHECKSUM_FIFO_DEPTH = 4
|
||||
|
||||
# Inputs
|
||||
clk = Signal(bool(0))
|
||||
rst = Signal(bool(0))
|
||||
current_test = Signal(intbv(0)[8:])
|
||||
|
||||
s_axis_tdata = Signal(intbv(0)[DATA_WIDTH:])
|
||||
s_axis_tkeep = Signal(intbv(0)[KEEP_WIDTH:])
|
||||
s_axis_tvalid = Signal(bool(0))
|
||||
s_axis_tlast = Signal(bool(0))
|
||||
s_axis_tid = Signal(intbv(0)[ID_WIDTH:])
|
||||
s_axis_tdest = Signal(intbv(0)[DEST_WIDTH:])
|
||||
s_axis_tuser = Signal(intbv(0)[USER_WIDTH:])
|
||||
m_axis_tready = Signal(bool(0))
|
||||
s_axis_cmd_csum_enable = Signal(bool(0))
|
||||
s_axis_cmd_csum_start = Signal(intbv(0)[8:])
|
||||
s_axis_cmd_csum_offset = Signal(intbv(0)[8:])
|
||||
s_axis_cmd_csum_init = Signal(intbv(0)[16:])
|
||||
s_axis_cmd_valid = Signal(bool(0))
|
||||
|
||||
# Outputs
|
||||
s_axis_tready = Signal(bool(0))
|
||||
m_axis_tdata = Signal(intbv(0)[DATA_WIDTH:])
|
||||
m_axis_tkeep = Signal(intbv(0)[KEEP_WIDTH:])
|
||||
m_axis_tvalid = Signal(bool(0))
|
||||
m_axis_tlast = Signal(bool(0))
|
||||
m_axis_tid = Signal(intbv(0)[ID_WIDTH:])
|
||||
m_axis_tdest = Signal(intbv(0)[DEST_WIDTH:])
|
||||
m_axis_tuser = Signal(intbv(0)[USER_WIDTH:])
|
||||
s_axis_cmd_ready = Signal(bool(1))
|
||||
|
||||
# sources and sinks
|
||||
source_pause = Signal(bool(0))
|
||||
sink_pause = Signal(bool(0))
|
||||
|
||||
source = axis_ep.AXIStreamSource()
|
||||
|
||||
source_logic = source.create_logic(
|
||||
clk,
|
||||
rst,
|
||||
tdata=s_axis_tdata,
|
||||
tkeep=s_axis_tkeep,
|
||||
tvalid=s_axis_tvalid,
|
||||
tready=s_axis_tready,
|
||||
tlast=s_axis_tlast,
|
||||
tuser=s_axis_tuser,
|
||||
pause=source_pause,
|
||||
name='source'
|
||||
)
|
||||
|
||||
cmd_source = axis_ep.AXIStreamSource()
|
||||
|
||||
cmd_source_logic = cmd_source.create_logic(
|
||||
clk,
|
||||
rst,
|
||||
tdata=(s_axis_cmd_csum_enable, s_axis_cmd_csum_start, s_axis_cmd_csum_offset, s_axis_cmd_csum_init),
|
||||
tvalid=s_axis_cmd_valid,
|
||||
tready=s_axis_cmd_ready,
|
||||
name='cmd_source'
|
||||
)
|
||||
|
||||
sink = axis_ep.AXIStreamSink()
|
||||
|
||||
sink_logic = sink.create_logic(
|
||||
clk,
|
||||
rst,
|
||||
tdata=m_axis_tdata,
|
||||
tkeep=m_axis_tkeep,
|
||||
tvalid=m_axis_tvalid,
|
||||
tready=m_axis_tready,
|
||||
tlast=m_axis_tlast,
|
||||
tuser=m_axis_tuser,
|
||||
pause=sink_pause,
|
||||
name='sink'
|
||||
)
|
||||
|
||||
# DUT
|
||||
if os.system(build_cmd):
|
||||
raise Exception("Error running build command")
|
||||
|
||||
dut = Cosimulation(
|
||||
"vvp -m myhdl %s.vvp -lxt2" % testbench,
|
||||
clk=clk,
|
||||
rst=rst,
|
||||
current_test=current_test,
|
||||
s_axis_tdata=s_axis_tdata,
|
||||
s_axis_tkeep=s_axis_tkeep,
|
||||
s_axis_tvalid=s_axis_tvalid,
|
||||
s_axis_tready=s_axis_tready,
|
||||
s_axis_tlast=s_axis_tlast,
|
||||
s_axis_tid=s_axis_tid,
|
||||
s_axis_tdest=s_axis_tdest,
|
||||
s_axis_tuser=s_axis_tuser,
|
||||
m_axis_tdata=m_axis_tdata,
|
||||
m_axis_tkeep=m_axis_tkeep,
|
||||
m_axis_tvalid=m_axis_tvalid,
|
||||
m_axis_tready=m_axis_tready,
|
||||
m_axis_tlast=m_axis_tlast,
|
||||
m_axis_tid=m_axis_tid,
|
||||
m_axis_tdest=m_axis_tdest,
|
||||
m_axis_tuser=m_axis_tuser,
|
||||
s_axis_cmd_csum_enable=s_axis_cmd_csum_enable,
|
||||
s_axis_cmd_csum_start=s_axis_cmd_csum_start,
|
||||
s_axis_cmd_csum_offset=s_axis_cmd_csum_offset,
|
||||
s_axis_cmd_csum_init=s_axis_cmd_csum_init,
|
||||
s_axis_cmd_valid=s_axis_cmd_valid,
|
||||
s_axis_cmd_ready=s_axis_cmd_ready
|
||||
)
|
||||
|
||||
@always(delay(4))
|
||||
def clkgen():
|
||||
clk.next = not clk
|
||||
|
||||
def wait_normal():
|
||||
while s_axis_tvalid:
|
||||
yield clk.posedge
|
||||
|
||||
def wait_pause_source():
|
||||
while s_axis_tvalid or m_axis_tvalid:
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
source_pause.next = False
|
||||
yield clk.posedge
|
||||
source_pause.next = True
|
||||
yield clk.posedge
|
||||
|
||||
source_pause.next = False
|
||||
|
||||
def wait_pause_sink():
|
||||
while s_axis_tvalid or m_axis_tvalid:
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
sink_pause.next = False
|
||||
yield clk.posedge
|
||||
sink_pause.next = True
|
||||
yield clk.posedge
|
||||
|
||||
sink_pause.next = False
|
||||
|
||||
@instance
|
||||
def check():
|
||||
yield delay(100)
|
||||
yield clk.posedge
|
||||
rst.next = 1
|
||||
yield clk.posedge
|
||||
rst.next = 0
|
||||
yield clk.posedge
|
||||
yield delay(100)
|
||||
yield clk.posedge
|
||||
|
||||
# testbench stimulus
|
||||
|
||||
for payload_len in list(range(1, 128)) + list([1024, 1500]):
|
||||
yield clk.posedge
|
||||
print("test 1: test packet, length %d" % payload_len)
|
||||
current_test.next = 1
|
||||
|
||||
test_frame = eth_ep.EthFrame()
|
||||
test_frame.eth_dest_mac = 0xDAD1D2D3D4D5
|
||||
test_frame.eth_src_mac = 0x5A5152535455
|
||||
test_frame.eth_type = 0x8000
|
||||
test_frame.payload = bytearray((x%256 for x in range(payload_len)))
|
||||
|
||||
axis_frame = test_frame.build_axis()
|
||||
cmd_frame = [(False, 0, 0, 0)]
|
||||
|
||||
for wait in wait_normal, wait_pause_source, wait_pause_sink:
|
||||
source.send(axis_frame)
|
||||
cmd_source.send(cmd_frame)
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
yield wait()
|
||||
|
||||
yield sink.wait()
|
||||
rx_frame = sink.recv()
|
||||
|
||||
check_frame = eth_ep.EthFrame()
|
||||
check_frame.parse_axis(rx_frame)
|
||||
|
||||
assert check_frame == test_frame
|
||||
|
||||
assert sink.empty()
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 2: back-to-back packets, length %d" % payload_len)
|
||||
current_test.next = 2
|
||||
|
||||
test_frame1 = eth_ep.EthFrame()
|
||||
test_frame1.eth_dest_mac = 0xDAD1D2D3D4D5
|
||||
test_frame1.eth_src_mac = 0x5A5152535455
|
||||
test_frame1.eth_type = 0x8000
|
||||
test_frame1.payload = bytearray((x%256 for x in range(payload_len)))
|
||||
test_frame2 = eth_ep.EthFrame()
|
||||
test_frame2.eth_dest_mac = 0xDAD1D2D3D4D5
|
||||
test_frame2.eth_src_mac = 0x5A5152535455
|
||||
test_frame2.eth_type = 0x8000
|
||||
test_frame2.payload = bytearray((~x%256 for x in range(payload_len)))
|
||||
|
||||
axis_frame1 = test_frame1.build_axis()
|
||||
cmd_frame1 = [(False, 0, 0, 0)]
|
||||
axis_frame2 = test_frame2.build_axis()
|
||||
cmd_frame2 = [(False, 0, 0, 0)]
|
||||
|
||||
for wait in wait_normal, wait_pause_source, wait_pause_sink:
|
||||
source.send(axis_frame1)
|
||||
cmd_source.send(cmd_frame1)
|
||||
source.send(axis_frame2)
|
||||
cmd_source.send(cmd_frame2)
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
yield wait()
|
||||
|
||||
yield sink.wait()
|
||||
rx_frame = sink.recv()
|
||||
|
||||
check_frame = eth_ep.EthFrame()
|
||||
check_frame.parse_axis(rx_frame)
|
||||
|
||||
assert check_frame == test_frame1
|
||||
|
||||
yield sink.wait()
|
||||
rx_frame = sink.recv()
|
||||
|
||||
check_frame = eth_ep.EthFrame()
|
||||
check_frame.parse_axis(rx_frame)
|
||||
|
||||
assert check_frame == test_frame2
|
||||
|
||||
assert sink.empty()
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 3: test UDP packet with zero checksum, length %d" % payload_len)
|
||||
current_test.next = 3
|
||||
|
||||
test_frame = udp_ep.UDPFrame()
|
||||
test_frame.eth_dest_mac = 0xDAD1D2D3D4D5
|
||||
test_frame.eth_src_mac = 0x5A5152535455
|
||||
test_frame.eth_type = 0x0800
|
||||
test_frame.ip_version = 4
|
||||
test_frame.ip_ihl = 5
|
||||
test_frame.ip_length = None
|
||||
test_frame.ip_identification = 0
|
||||
test_frame.ip_flags = 2
|
||||
test_frame.ip_fragment_offset = 0
|
||||
test_frame.ip_ttl = 64
|
||||
test_frame.ip_protocol = 0x11
|
||||
test_frame.ip_header_checksum = None
|
||||
test_frame.ip_source_ip = 0xc0a80164
|
||||
test_frame.ip_dest_ip = 0xc0a80165
|
||||
test_frame.udp_source_port = 1
|
||||
test_frame.udp_dest_port = 2
|
||||
test_frame.udp_length = None
|
||||
test_frame.udp_checksum = None
|
||||
test_frame.payload = bytearray((x%256 for x in range(payload_len)))
|
||||
|
||||
test_frame.update_udp_length()
|
||||
test_frame.udp_checksum = 0
|
||||
pseudo_header_checksum = test_frame.calc_udp_pseudo_header_checksum()
|
||||
|
||||
axis_frame = test_frame.build_axis()
|
||||
cmd_frame = [(True, 34, 40, pseudo_header_checksum)]
|
||||
|
||||
for wait in wait_normal, wait_pause_source, wait_pause_sink:
|
||||
source.send(axis_frame)
|
||||
cmd_source.send(cmd_frame)
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
yield wait()
|
||||
|
||||
yield sink.wait()
|
||||
rx_frame = sink.recv()
|
||||
|
||||
check_frame = udp_ep.UDPFrame()
|
||||
check_frame.parse_axis(rx_frame)
|
||||
|
||||
print(hex(check_frame.udp_checksum))
|
||||
print(hex(check_frame.calc_udp_checksum()))
|
||||
|
||||
assert check_frame.verify_checksums()
|
||||
|
||||
assert sink.empty()
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 4: test UDP packet with inline pseudo header checksum, length %d" % payload_len)
|
||||
current_test.next = 4
|
||||
|
||||
test_frame = udp_ep.UDPFrame()
|
||||
test_frame.eth_dest_mac = 0xDAD1D2D3D4D5
|
||||
test_frame.eth_src_mac = 0x5A5152535455
|
||||
test_frame.eth_type = 0x0800
|
||||
test_frame.ip_version = 4
|
||||
test_frame.ip_ihl = 5
|
||||
test_frame.ip_length = None
|
||||
test_frame.ip_identification = 0
|
||||
test_frame.ip_flags = 2
|
||||
test_frame.ip_fragment_offset = 0
|
||||
test_frame.ip_ttl = 64
|
||||
test_frame.ip_protocol = 0x11
|
||||
test_frame.ip_header_checksum = None
|
||||
test_frame.ip_source_ip = 0xc0a80164
|
||||
test_frame.ip_dest_ip = 0xc0a80165
|
||||
test_frame.udp_source_port = 1
|
||||
test_frame.udp_dest_port = 2
|
||||
test_frame.udp_length = None
|
||||
test_frame.udp_checksum = None
|
||||
test_frame.payload = bytearray((x%256 for x in range(payload_len)))
|
||||
|
||||
test_frame.set_udp_pseudo_header_checksum()
|
||||
|
||||
axis_frame = test_frame.build_axis()
|
||||
cmd_frame = [(True, 34, 40, 0)]
|
||||
|
||||
for wait in wait_normal, wait_pause_source, wait_pause_sink:
|
||||
source.send(axis_frame)
|
||||
cmd_source.send(cmd_frame)
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
yield wait()
|
||||
|
||||
yield sink.wait()
|
||||
rx_frame = sink.recv()
|
||||
|
||||
check_frame = udp_ep.UDPFrame()
|
||||
check_frame.parse_axis(rx_frame)
|
||||
|
||||
print(hex(check_frame.udp_checksum))
|
||||
print(hex(check_frame.calc_udp_checksum()))
|
||||
|
||||
assert check_frame.verify_checksums()
|
||||
|
||||
assert sink.empty()
|
||||
|
||||
yield delay(100)
|
||||
|
||||
for start in list(range(0, min(payload_len+14, 64))):
|
||||
offset = 0
|
||||
yield clk.posedge
|
||||
print("test 5: test various offsets, length %d, start %d, offset %d" % (payload_len, start, offset))
|
||||
current_test.next = 5
|
||||
|
||||
test_frame = eth_ep.EthFrame()
|
||||
test_frame.eth_dest_mac = 0xDAD1D2D3D4D5
|
||||
test_frame.eth_src_mac = 0x5A5152535455
|
||||
test_frame.eth_type = 0x8000
|
||||
test_frame.payload = bytearray((x%256 for x in range(payload_len)))
|
||||
|
||||
axis_frame = test_frame.build_axis()
|
||||
cmd_frame = [(True, start, offset, 0)]
|
||||
|
||||
for wait in wait_normal, wait_pause_source, wait_pause_sink:
|
||||
source.send(axis_frame)
|
||||
cmd_source.send(cmd_frame)
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
yield wait()
|
||||
|
||||
yield sink.wait()
|
||||
rx_frame = sink.recv()
|
||||
|
||||
csum = ~frame_checksum(axis_frame, start) & 0xffff
|
||||
print(hex(csum))
|
||||
|
||||
check_data = axis_frame.data
|
||||
struct.pack_into('>H', check_data, offset, csum)
|
||||
|
||||
print(check_data)
|
||||
print(rx_frame.data)
|
||||
|
||||
yield delay(100)
|
||||
|
||||
assert check_data == rx_frame.data
|
||||
|
||||
assert sink.empty()
|
||||
|
||||
yield delay(100)
|
||||
|
||||
for offset in list(range(0, min(payload_len+14, 64)-1)):
|
||||
start = 0
|
||||
yield clk.posedge
|
||||
print("test 6: test various offsets, length %d, start %d, offset %d" % (payload_len, start, offset))
|
||||
current_test.next = 6
|
||||
|
||||
test_frame = eth_ep.EthFrame()
|
||||
test_frame.eth_dest_mac = 0xDAD1D2D3D4D5
|
||||
test_frame.eth_src_mac = 0x5A5152535455
|
||||
test_frame.eth_type = 0x8000
|
||||
test_frame.payload = bytearray((x%256 for x in range(payload_len)))
|
||||
|
||||
axis_frame = test_frame.build_axis()
|
||||
cmd_frame = [(True, start, offset, 0)]
|
||||
|
||||
for wait in wait_normal, wait_pause_source, wait_pause_sink:
|
||||
source.send(axis_frame)
|
||||
cmd_source.send(cmd_frame)
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
yield wait()
|
||||
|
||||
yield sink.wait()
|
||||
rx_frame = sink.recv()
|
||||
|
||||
csum = ~frame_checksum(axis_frame, start) & 0xffff
|
||||
print(hex(csum))
|
||||
|
||||
check_data = axis_frame.data
|
||||
struct.pack_into('>H', check_data, offset, csum)
|
||||
|
||||
print(check_data)
|
||||
print(rx_frame.data)
|
||||
|
||||
assert check_data == rx_frame.data
|
||||
|
||||
assert sink.empty()
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 7: backpressure test")
|
||||
current_test.next = 7
|
||||
|
||||
test_frame = eth_ep.EthFrame()
|
||||
test_frame.eth_dest_mac = 0xDAD1D2D3D4D5
|
||||
test_frame.eth_src_mac = 0x5A5152535455
|
||||
test_frame.eth_type = 0x8000
|
||||
test_frame.payload = bytearray((x%256 for x in range(64)))
|
||||
|
||||
axis_frame = test_frame.build_axis()
|
||||
cmd_frame = [(False, 0, 0, 0)]
|
||||
|
||||
sink_pause.next = 1
|
||||
|
||||
for k in range(10):
|
||||
source.send(axis_frame)
|
||||
cmd_source.send(cmd_frame)
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
yield delay(1000)
|
||||
|
||||
sink_pause.next = 0
|
||||
|
||||
for k in range(10):
|
||||
yield sink.wait()
|
||||
rx_frame = sink.recv()
|
||||
|
||||
check_frame = eth_ep.EthFrame()
|
||||
check_frame.parse_axis(rx_frame)
|
||||
|
||||
assert check_frame == test_frame
|
||||
|
||||
assert sink.empty()
|
||||
|
||||
yield delay(100)
|
||||
|
||||
raise StopSimulation
|
||||
|
||||
return instances()
|
||||
|
||||
def test_bench():
|
||||
sim = Simulation(bench())
|
||||
sim.run()
|
||||
|
||||
if __name__ == '__main__':
|
||||
print("Running test...")
|
||||
test_bench()
|
@ -1,163 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright 2019, The Regents of the University of California.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
|
||||
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of The Regents of the University of California.
|
||||
|
||||
*/
|
||||
|
||||
// Language: Verilog 2001
|
||||
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
/*
|
||||
* Testbench for tx_checksum
|
||||
*/
|
||||
module test_tx_checksum_256;
|
||||
|
||||
// Parameters
|
||||
parameter DATA_WIDTH = 256;
|
||||
parameter KEEP_WIDTH = (DATA_WIDTH/8);
|
||||
parameter ID_ENABLE = 0;
|
||||
parameter ID_WIDTH = 8;
|
||||
parameter DEST_ENABLE = 0;
|
||||
parameter DEST_WIDTH = 8;
|
||||
parameter USER_ENABLE = 1;
|
||||
parameter USER_WIDTH = 1;
|
||||
parameter USE_INIT_VALUE = 1;
|
||||
parameter DATA_FIFO_DEPTH = 4096;
|
||||
parameter CHECKSUM_FIFO_DEPTH = 4;
|
||||
|
||||
// Inputs
|
||||
reg clk = 0;
|
||||
reg rst = 0;
|
||||
reg [7:0] current_test = 0;
|
||||
|
||||
reg [DATA_WIDTH-1:0] s_axis_tdata = 0;
|
||||
reg [KEEP_WIDTH-1:0] s_axis_tkeep = 0;
|
||||
reg s_axis_tvalid = 0;
|
||||
reg s_axis_tlast = 0;
|
||||
reg [ID_WIDTH-1:0] s_axis_tid = 0;
|
||||
reg [DEST_WIDTH-1:0] s_axis_tdest = 0;
|
||||
reg [USER_WIDTH-1:0] s_axis_tuser = 0;
|
||||
reg m_axis_tready = 0;
|
||||
reg s_axis_cmd_csum_enable = 0;
|
||||
reg [7:0] s_axis_cmd_csum_start = 0;
|
||||
reg [7:0] s_axis_cmd_csum_offset = 0;
|
||||
reg [15:0] s_axis_cmd_csum_init = 0;
|
||||
reg s_axis_cmd_valid = 0;
|
||||
|
||||
// Outputs
|
||||
wire s_axis_tready;
|
||||
wire [DATA_WIDTH-1:0] m_axis_tdata;
|
||||
wire [KEEP_WIDTH-1:0] m_axis_tkeep;
|
||||
wire m_axis_tvalid;
|
||||
wire m_axis_tlast;
|
||||
wire [ID_WIDTH-1:0] m_axis_tid;
|
||||
wire [DEST_WIDTH-1:0] m_axis_tdest;
|
||||
wire [USER_WIDTH-1:0] m_axis_tuser;
|
||||
wire s_axis_cmd_ready;
|
||||
|
||||
initial begin
|
||||
// myhdl integration
|
||||
$from_myhdl(
|
||||
clk,
|
||||
rst,
|
||||
current_test,
|
||||
s_axis_tdata,
|
||||
s_axis_tkeep,
|
||||
s_axis_tvalid,
|
||||
s_axis_tlast,
|
||||
s_axis_tid,
|
||||
s_axis_tdest,
|
||||
s_axis_tuser,
|
||||
m_axis_tready,
|
||||
s_axis_cmd_csum_enable,
|
||||
s_axis_cmd_csum_start,
|
||||
s_axis_cmd_csum_offset,
|
||||
s_axis_cmd_csum_init,
|
||||
s_axis_cmd_valid
|
||||
);
|
||||
$to_myhdl(
|
||||
s_axis_tready,
|
||||
m_axis_tdata,
|
||||
m_axis_tkeep,
|
||||
m_axis_tvalid,
|
||||
m_axis_tlast,
|
||||
m_axis_tid,
|
||||
m_axis_tdest,
|
||||
m_axis_tuser,
|
||||
s_axis_cmd_ready
|
||||
);
|
||||
|
||||
// dump file
|
||||
$dumpfile("test_tx_checksum_256.lxt");
|
||||
$dumpvars(0, test_tx_checksum_256);
|
||||
end
|
||||
|
||||
tx_checksum #(
|
||||
.DATA_WIDTH(DATA_WIDTH),
|
||||
.KEEP_WIDTH(KEEP_WIDTH),
|
||||
.ID_ENABLE(ID_ENABLE),
|
||||
.ID_WIDTH(ID_WIDTH),
|
||||
.DEST_ENABLE(DEST_ENABLE),
|
||||
.DEST_WIDTH(DEST_WIDTH),
|
||||
.USER_ENABLE(USER_ENABLE),
|
||||
.USER_WIDTH(USER_WIDTH),
|
||||
.USE_INIT_VALUE(USE_INIT_VALUE),
|
||||
.DATA_FIFO_DEPTH(DATA_FIFO_DEPTH),
|
||||
.CHECKSUM_FIFO_DEPTH(CHECKSUM_FIFO_DEPTH)
|
||||
)
|
||||
UUT (
|
||||
.clk(clk),
|
||||
.rst(rst),
|
||||
.s_axis_tdata(s_axis_tdata),
|
||||
.s_axis_tkeep(s_axis_tkeep),
|
||||
.s_axis_tvalid(s_axis_tvalid),
|
||||
.s_axis_tready(s_axis_tready),
|
||||
.s_axis_tlast(s_axis_tlast),
|
||||
.s_axis_tid(s_axis_tid),
|
||||
.s_axis_tdest(s_axis_tdest),
|
||||
.s_axis_tuser(s_axis_tuser),
|
||||
.m_axis_tdata(m_axis_tdata),
|
||||
.m_axis_tkeep(m_axis_tkeep),
|
||||
.m_axis_tvalid(m_axis_tvalid),
|
||||
.m_axis_tready(m_axis_tready),
|
||||
.m_axis_tlast(m_axis_tlast),
|
||||
.m_axis_tid(m_axis_tid),
|
||||
.m_axis_tdest(m_axis_tdest),
|
||||
.m_axis_tuser(m_axis_tuser),
|
||||
.s_axis_cmd_csum_enable(s_axis_cmd_csum_enable),
|
||||
.s_axis_cmd_csum_start(s_axis_cmd_csum_start),
|
||||
.s_axis_cmd_csum_offset(s_axis_cmd_csum_offset),
|
||||
.s_axis_cmd_csum_init(s_axis_cmd_csum_init),
|
||||
.s_axis_cmd_valid(s_axis_cmd_valid),
|
||||
.s_axis_cmd_ready(s_axis_cmd_ready)
|
||||
);
|
||||
|
||||
endmodule
|
@ -1,571 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
|
||||
Copyright 2019, The Regents of the University of California.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
|
||||
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of The Regents of the University of California.
|
||||
|
||||
"""
|
||||
|
||||
from myhdl import *
|
||||
import os
|
||||
|
||||
import struct
|
||||
|
||||
import axis_ep
|
||||
import eth_ep
|
||||
import udp_ep
|
||||
|
||||
module = 'tx_checksum'
|
||||
testbench = 'test_%s_64' % module
|
||||
|
||||
srcs = []
|
||||
|
||||
srcs.append("../rtl/%s.v" % module)
|
||||
srcs.append("../lib/axis/rtl/axis_fifo.v")
|
||||
srcs.append("%s.v" % testbench)
|
||||
|
||||
src = ' '.join(srcs)
|
||||
|
||||
build_cmd = "iverilog -o %s.vvp %s" % (testbench, src)
|
||||
|
||||
def frame_checksum(frame, offset=14):
|
||||
data = bytearray()
|
||||
if isinstance(frame, eth_ep.EthFrame):
|
||||
data = frame.payload.data[offset-14:]
|
||||
elif isinstance(frame, axis_ep.AXIStreamFrame):
|
||||
data = frame.data[offset:]
|
||||
else:
|
||||
return None
|
||||
|
||||
csum = 0
|
||||
odd = False
|
||||
|
||||
for b in data:
|
||||
if odd:
|
||||
csum += b
|
||||
else:
|
||||
csum += b << 8
|
||||
odd = not odd
|
||||
|
||||
csum = (csum & 0xffff) + (csum >> 16)
|
||||
csum = (csum & 0xffff) + (csum >> 16)
|
||||
|
||||
return csum
|
||||
|
||||
def bench():
|
||||
|
||||
# Parameters
|
||||
DATA_WIDTH = 64
|
||||
KEEP_WIDTH = (DATA_WIDTH/8)
|
||||
ID_ENABLE = 0
|
||||
ID_WIDTH = 8
|
||||
DEST_ENABLE = 0
|
||||
DEST_WIDTH = 8
|
||||
USER_ENABLE = 1
|
||||
USER_WIDTH = 1
|
||||
USE_INIT_VALUE = 1
|
||||
DATA_FIFO_DEPTH = 4096
|
||||
CHECKSUM_FIFO_DEPTH = 4
|
||||
|
||||
# Inputs
|
||||
clk = Signal(bool(0))
|
||||
rst = Signal(bool(0))
|
||||
current_test = Signal(intbv(0)[8:])
|
||||
|
||||
s_axis_tdata = Signal(intbv(0)[DATA_WIDTH:])
|
||||
s_axis_tkeep = Signal(intbv(0)[KEEP_WIDTH:])
|
||||
s_axis_tvalid = Signal(bool(0))
|
||||
s_axis_tlast = Signal(bool(0))
|
||||
s_axis_tid = Signal(intbv(0)[ID_WIDTH:])
|
||||
s_axis_tdest = Signal(intbv(0)[DEST_WIDTH:])
|
||||
s_axis_tuser = Signal(intbv(0)[USER_WIDTH:])
|
||||
m_axis_tready = Signal(bool(0))
|
||||
s_axis_cmd_csum_enable = Signal(bool(0))
|
||||
s_axis_cmd_csum_start = Signal(intbv(0)[8:])
|
||||
s_axis_cmd_csum_offset = Signal(intbv(0)[8:])
|
||||
s_axis_cmd_csum_init = Signal(intbv(0)[16:])
|
||||
s_axis_cmd_valid = Signal(bool(0))
|
||||
|
||||
# Outputs
|
||||
s_axis_tready = Signal(bool(0))
|
||||
m_axis_tdata = Signal(intbv(0)[DATA_WIDTH:])
|
||||
m_axis_tkeep = Signal(intbv(0)[KEEP_WIDTH:])
|
||||
m_axis_tvalid = Signal(bool(0))
|
||||
m_axis_tlast = Signal(bool(0))
|
||||
m_axis_tid = Signal(intbv(0)[ID_WIDTH:])
|
||||
m_axis_tdest = Signal(intbv(0)[DEST_WIDTH:])
|
||||
m_axis_tuser = Signal(intbv(0)[USER_WIDTH:])
|
||||
s_axis_cmd_ready = Signal(bool(1))
|
||||
|
||||
# sources and sinks
|
||||
source_pause = Signal(bool(0))
|
||||
sink_pause = Signal(bool(0))
|
||||
|
||||
source = axis_ep.AXIStreamSource()
|
||||
|
||||
source_logic = source.create_logic(
|
||||
clk,
|
||||
rst,
|
||||
tdata=s_axis_tdata,
|
||||
tkeep=s_axis_tkeep,
|
||||
tvalid=s_axis_tvalid,
|
||||
tready=s_axis_tready,
|
||||
tlast=s_axis_tlast,
|
||||
tuser=s_axis_tuser,
|
||||
pause=source_pause,
|
||||
name='source'
|
||||
)
|
||||
|
||||
cmd_source = axis_ep.AXIStreamSource()
|
||||
|
||||
cmd_source_logic = cmd_source.create_logic(
|
||||
clk,
|
||||
rst,
|
||||
tdata=(s_axis_cmd_csum_enable, s_axis_cmd_csum_start, s_axis_cmd_csum_offset, s_axis_cmd_csum_init),
|
||||
tvalid=s_axis_cmd_valid,
|
||||
tready=s_axis_cmd_ready,
|
||||
name='cmd_source'
|
||||
)
|
||||
|
||||
sink = axis_ep.AXIStreamSink()
|
||||
|
||||
sink_logic = sink.create_logic(
|
||||
clk,
|
||||
rst,
|
||||
tdata=m_axis_tdata,
|
||||
tkeep=m_axis_tkeep,
|
||||
tvalid=m_axis_tvalid,
|
||||
tready=m_axis_tready,
|
||||
tlast=m_axis_tlast,
|
||||
tuser=m_axis_tuser,
|
||||
pause=sink_pause,
|
||||
name='sink'
|
||||
)
|
||||
|
||||
# DUT
|
||||
if os.system(build_cmd):
|
||||
raise Exception("Error running build command")
|
||||
|
||||
dut = Cosimulation(
|
||||
"vvp -m myhdl %s.vvp -lxt2" % testbench,
|
||||
clk=clk,
|
||||
rst=rst,
|
||||
current_test=current_test,
|
||||
s_axis_tdata=s_axis_tdata,
|
||||
s_axis_tkeep=s_axis_tkeep,
|
||||
s_axis_tvalid=s_axis_tvalid,
|
||||
s_axis_tready=s_axis_tready,
|
||||
s_axis_tlast=s_axis_tlast,
|
||||
s_axis_tid=s_axis_tid,
|
||||
s_axis_tdest=s_axis_tdest,
|
||||
s_axis_tuser=s_axis_tuser,
|
||||
m_axis_tdata=m_axis_tdata,
|
||||
m_axis_tkeep=m_axis_tkeep,
|
||||
m_axis_tvalid=m_axis_tvalid,
|
||||
m_axis_tready=m_axis_tready,
|
||||
m_axis_tlast=m_axis_tlast,
|
||||
m_axis_tid=m_axis_tid,
|
||||
m_axis_tdest=m_axis_tdest,
|
||||
m_axis_tuser=m_axis_tuser,
|
||||
s_axis_cmd_csum_enable=s_axis_cmd_csum_enable,
|
||||
s_axis_cmd_csum_start=s_axis_cmd_csum_start,
|
||||
s_axis_cmd_csum_offset=s_axis_cmd_csum_offset,
|
||||
s_axis_cmd_csum_init=s_axis_cmd_csum_init,
|
||||
s_axis_cmd_valid=s_axis_cmd_valid,
|
||||
s_axis_cmd_ready=s_axis_cmd_ready
|
||||
)
|
||||
|
||||
@always(delay(4))
|
||||
def clkgen():
|
||||
clk.next = not clk
|
||||
|
||||
def wait_normal():
|
||||
while s_axis_tvalid:
|
||||
yield clk.posedge
|
||||
|
||||
def wait_pause_source():
|
||||
while s_axis_tvalid or m_axis_tvalid:
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
source_pause.next = False
|
||||
yield clk.posedge
|
||||
source_pause.next = True
|
||||
yield clk.posedge
|
||||
|
||||
source_pause.next = False
|
||||
|
||||
def wait_pause_sink():
|
||||
while s_axis_tvalid or m_axis_tvalid:
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
sink_pause.next = False
|
||||
yield clk.posedge
|
||||
sink_pause.next = True
|
||||
yield clk.posedge
|
||||
|
||||
sink_pause.next = False
|
||||
|
||||
@instance
|
||||
def check():
|
||||
yield delay(100)
|
||||
yield clk.posedge
|
||||
rst.next = 1
|
||||
yield clk.posedge
|
||||
rst.next = 0
|
||||
yield clk.posedge
|
||||
yield delay(100)
|
||||
yield clk.posedge
|
||||
|
||||
# testbench stimulus
|
||||
|
||||
for payload_len in list(range(1, 128)) + list([1024, 1500]):
|
||||
yield clk.posedge
|
||||
print("test 1: test packet, length %d" % payload_len)
|
||||
current_test.next = 1
|
||||
|
||||
test_frame = eth_ep.EthFrame()
|
||||
test_frame.eth_dest_mac = 0xDAD1D2D3D4D5
|
||||
test_frame.eth_src_mac = 0x5A5152535455
|
||||
test_frame.eth_type = 0x8000
|
||||
test_frame.payload = bytearray((x%256 for x in range(payload_len)))
|
||||
|
||||
axis_frame = test_frame.build_axis()
|
||||
cmd_frame = [(False, 0, 0, 0)]
|
||||
|
||||
for wait in wait_normal, wait_pause_source, wait_pause_sink:
|
||||
source.send(axis_frame)
|
||||
cmd_source.send(cmd_frame)
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
yield wait()
|
||||
|
||||
yield sink.wait()
|
||||
rx_frame = sink.recv()
|
||||
|
||||
check_frame = eth_ep.EthFrame()
|
||||
check_frame.parse_axis(rx_frame)
|
||||
|
||||
assert check_frame == test_frame
|
||||
|
||||
assert sink.empty()
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 2: back-to-back packets, length %d" % payload_len)
|
||||
current_test.next = 2
|
||||
|
||||
test_frame1 = eth_ep.EthFrame()
|
||||
test_frame1.eth_dest_mac = 0xDAD1D2D3D4D5
|
||||
test_frame1.eth_src_mac = 0x5A5152535455
|
||||
test_frame1.eth_type = 0x8000
|
||||
test_frame1.payload = bytearray((x%256 for x in range(payload_len)))
|
||||
test_frame2 = eth_ep.EthFrame()
|
||||
test_frame2.eth_dest_mac = 0xDAD1D2D3D4D5
|
||||
test_frame2.eth_src_mac = 0x5A5152535455
|
||||
test_frame2.eth_type = 0x8000
|
||||
test_frame2.payload = bytearray((~x%256 for x in range(payload_len)))
|
||||
|
||||
axis_frame1 = test_frame1.build_axis()
|
||||
cmd_frame1 = [(False, 0, 0, 0)]
|
||||
axis_frame2 = test_frame2.build_axis()
|
||||
cmd_frame2 = [(False, 0, 0, 0)]
|
||||
|
||||
for wait in wait_normal, wait_pause_source, wait_pause_sink:
|
||||
source.send(axis_frame1)
|
||||
cmd_source.send(cmd_frame1)
|
||||
source.send(axis_frame2)
|
||||
cmd_source.send(cmd_frame2)
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
yield wait()
|
||||
|
||||
yield sink.wait()
|
||||
rx_frame = sink.recv()
|
||||
|
||||
check_frame = eth_ep.EthFrame()
|
||||
check_frame.parse_axis(rx_frame)
|
||||
|
||||
assert check_frame == test_frame1
|
||||
|
||||
yield sink.wait()
|
||||
rx_frame = sink.recv()
|
||||
|
||||
check_frame = eth_ep.EthFrame()
|
||||
check_frame.parse_axis(rx_frame)
|
||||
|
||||
assert check_frame == test_frame2
|
||||
|
||||
assert sink.empty()
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 3: test UDP packet with zero checksum, length %d" % payload_len)
|
||||
current_test.next = 3
|
||||
|
||||
test_frame = udp_ep.UDPFrame()
|
||||
test_frame.eth_dest_mac = 0xDAD1D2D3D4D5
|
||||
test_frame.eth_src_mac = 0x5A5152535455
|
||||
test_frame.eth_type = 0x0800
|
||||
test_frame.ip_version = 4
|
||||
test_frame.ip_ihl = 5
|
||||
test_frame.ip_length = None
|
||||
test_frame.ip_identification = 0
|
||||
test_frame.ip_flags = 2
|
||||
test_frame.ip_fragment_offset = 0
|
||||
test_frame.ip_ttl = 64
|
||||
test_frame.ip_protocol = 0x11
|
||||
test_frame.ip_header_checksum = None
|
||||
test_frame.ip_source_ip = 0xc0a80164
|
||||
test_frame.ip_dest_ip = 0xc0a80165
|
||||
test_frame.udp_source_port = 1
|
||||
test_frame.udp_dest_port = 2
|
||||
test_frame.udp_length = None
|
||||
test_frame.udp_checksum = None
|
||||
test_frame.payload = bytearray((x%256 for x in range(payload_len)))
|
||||
|
||||
test_frame.update_udp_length()
|
||||
test_frame.udp_checksum = 0
|
||||
pseudo_header_checksum = test_frame.calc_udp_pseudo_header_checksum()
|
||||
|
||||
axis_frame = test_frame.build_axis()
|
||||
cmd_frame = [(True, 34, 40, pseudo_header_checksum)]
|
||||
|
||||
for wait in wait_normal, wait_pause_source, wait_pause_sink:
|
||||
source.send(axis_frame)
|
||||
cmd_source.send(cmd_frame)
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
yield wait()
|
||||
|
||||
yield sink.wait()
|
||||
rx_frame = sink.recv()
|
||||
|
||||
check_frame = udp_ep.UDPFrame()
|
||||
check_frame.parse_axis(rx_frame)
|
||||
|
||||
print(hex(check_frame.udp_checksum))
|
||||
print(hex(check_frame.calc_udp_checksum()))
|
||||
|
||||
assert check_frame.verify_checksums()
|
||||
|
||||
assert sink.empty()
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 4: test UDP packet with inline pseudo header checksum, length %d" % payload_len)
|
||||
current_test.next = 4
|
||||
|
||||
test_frame = udp_ep.UDPFrame()
|
||||
test_frame.eth_dest_mac = 0xDAD1D2D3D4D5
|
||||
test_frame.eth_src_mac = 0x5A5152535455
|
||||
test_frame.eth_type = 0x0800
|
||||
test_frame.ip_version = 4
|
||||
test_frame.ip_ihl = 5
|
||||
test_frame.ip_length = None
|
||||
test_frame.ip_identification = 0
|
||||
test_frame.ip_flags = 2
|
||||
test_frame.ip_fragment_offset = 0
|
||||
test_frame.ip_ttl = 64
|
||||
test_frame.ip_protocol = 0x11
|
||||
test_frame.ip_header_checksum = None
|
||||
test_frame.ip_source_ip = 0xc0a80164
|
||||
test_frame.ip_dest_ip = 0xc0a80165
|
||||
test_frame.udp_source_port = 1
|
||||
test_frame.udp_dest_port = 2
|
||||
test_frame.udp_length = None
|
||||
test_frame.udp_checksum = None
|
||||
test_frame.payload = bytearray((x%256 for x in range(payload_len)))
|
||||
|
||||
test_frame.set_udp_pseudo_header_checksum()
|
||||
|
||||
axis_frame = test_frame.build_axis()
|
||||
cmd_frame = [(True, 34, 40, 0)]
|
||||
|
||||
for wait in wait_normal, wait_pause_source, wait_pause_sink:
|
||||
source.send(axis_frame)
|
||||
cmd_source.send(cmd_frame)
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
yield wait()
|
||||
|
||||
yield sink.wait()
|
||||
rx_frame = sink.recv()
|
||||
|
||||
check_frame = udp_ep.UDPFrame()
|
||||
check_frame.parse_axis(rx_frame)
|
||||
|
||||
print(hex(check_frame.udp_checksum))
|
||||
print(hex(check_frame.calc_udp_checksum()))
|
||||
|
||||
assert check_frame.verify_checksums()
|
||||
|
||||
assert sink.empty()
|
||||
|
||||
yield delay(100)
|
||||
|
||||
for start in list(range(0, min(payload_len+14, 64))):
|
||||
offset = 0
|
||||
yield clk.posedge
|
||||
print("test 5: test various offsets, length %d, start %d, offset %d" % (payload_len, start, offset))
|
||||
current_test.next = 5
|
||||
|
||||
test_frame = eth_ep.EthFrame()
|
||||
test_frame.eth_dest_mac = 0xDAD1D2D3D4D5
|
||||
test_frame.eth_src_mac = 0x5A5152535455
|
||||
test_frame.eth_type = 0x8000
|
||||
test_frame.payload = bytearray((x%256 for x in range(payload_len)))
|
||||
|
||||
axis_frame = test_frame.build_axis()
|
||||
cmd_frame = [(True, start, offset, 0)]
|
||||
|
||||
for wait in wait_normal, wait_pause_source, wait_pause_sink:
|
||||
source.send(axis_frame)
|
||||
cmd_source.send(cmd_frame)
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
yield wait()
|
||||
|
||||
yield sink.wait()
|
||||
rx_frame = sink.recv()
|
||||
|
||||
csum = ~frame_checksum(axis_frame, start) & 0xffff
|
||||
print(hex(csum))
|
||||
|
||||
check_data = axis_frame.data
|
||||
struct.pack_into('>H', check_data, offset, csum)
|
||||
|
||||
print(check_data)
|
||||
print(rx_frame.data)
|
||||
|
||||
yield delay(100)
|
||||
|
||||
assert check_data == rx_frame.data
|
||||
|
||||
assert sink.empty()
|
||||
|
||||
yield delay(100)
|
||||
|
||||
for offset in list(range(0, min(payload_len+14, 64)-1)):
|
||||
start = 0
|
||||
yield clk.posedge
|
||||
print("test 6: test various offsets, length %d, start %d, offset %d" % (payload_len, start, offset))
|
||||
current_test.next = 6
|
||||
|
||||
test_frame = eth_ep.EthFrame()
|
||||
test_frame.eth_dest_mac = 0xDAD1D2D3D4D5
|
||||
test_frame.eth_src_mac = 0x5A5152535455
|
||||
test_frame.eth_type = 0x8000
|
||||
test_frame.payload = bytearray((x%256 for x in range(payload_len)))
|
||||
|
||||
axis_frame = test_frame.build_axis()
|
||||
cmd_frame = [(True, start, offset, 0)]
|
||||
|
||||
for wait in wait_normal, wait_pause_source, wait_pause_sink:
|
||||
source.send(axis_frame)
|
||||
cmd_source.send(cmd_frame)
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
yield wait()
|
||||
|
||||
yield sink.wait()
|
||||
rx_frame = sink.recv()
|
||||
|
||||
csum = ~frame_checksum(axis_frame, start) & 0xffff
|
||||
print(hex(csum))
|
||||
|
||||
check_data = axis_frame.data
|
||||
struct.pack_into('>H', check_data, offset, csum)
|
||||
|
||||
print(check_data)
|
||||
print(rx_frame.data)
|
||||
|
||||
assert check_data == rx_frame.data
|
||||
|
||||
assert sink.empty()
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 7: backpressure test")
|
||||
current_test.next = 7
|
||||
|
||||
test_frame = eth_ep.EthFrame()
|
||||
test_frame.eth_dest_mac = 0xDAD1D2D3D4D5
|
||||
test_frame.eth_src_mac = 0x5A5152535455
|
||||
test_frame.eth_type = 0x8000
|
||||
test_frame.payload = bytearray((x%256 for x in range(64)))
|
||||
|
||||
axis_frame = test_frame.build_axis()
|
||||
cmd_frame = [(False, 0, 0, 0)]
|
||||
|
||||
sink_pause.next = 1
|
||||
|
||||
for k in range(10):
|
||||
source.send(axis_frame)
|
||||
cmd_source.send(cmd_frame)
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
yield delay(1000)
|
||||
|
||||
sink_pause.next = 0
|
||||
|
||||
for k in range(10):
|
||||
yield sink.wait()
|
||||
rx_frame = sink.recv()
|
||||
|
||||
check_frame = eth_ep.EthFrame()
|
||||
check_frame.parse_axis(rx_frame)
|
||||
|
||||
assert check_frame == test_frame
|
||||
|
||||
assert sink.empty()
|
||||
|
||||
yield delay(100)
|
||||
|
||||
raise StopSimulation
|
||||
|
||||
return instances()
|
||||
|
||||
def test_bench():
|
||||
sim = Simulation(bench())
|
||||
sim.run()
|
||||
|
||||
if __name__ == '__main__':
|
||||
print("Running test...")
|
||||
test_bench()
|
@ -1,163 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright 2019, The Regents of the University of California.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
|
||||
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of The Regents of the University of California.
|
||||
|
||||
*/
|
||||
|
||||
// Language: Verilog 2001
|
||||
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
/*
|
||||
* Testbench for tx_checksum
|
||||
*/
|
||||
module test_tx_checksum_64;
|
||||
|
||||
// Parameters
|
||||
parameter DATA_WIDTH = 64;
|
||||
parameter KEEP_WIDTH = (DATA_WIDTH/8);
|
||||
parameter ID_ENABLE = 0;
|
||||
parameter ID_WIDTH = 8;
|
||||
parameter DEST_ENABLE = 0;
|
||||
parameter DEST_WIDTH = 8;
|
||||
parameter USER_ENABLE = 1;
|
||||
parameter USER_WIDTH = 1;
|
||||
parameter USE_INIT_VALUE = 1;
|
||||
parameter DATA_FIFO_DEPTH = 4096;
|
||||
parameter CHECKSUM_FIFO_DEPTH = 4;
|
||||
|
||||
// Inputs
|
||||
reg clk = 0;
|
||||
reg rst = 0;
|
||||
reg [7:0] current_test = 0;
|
||||
|
||||
reg [DATA_WIDTH-1:0] s_axis_tdata = 0;
|
||||
reg [KEEP_WIDTH-1:0] s_axis_tkeep = 0;
|
||||
reg s_axis_tvalid = 0;
|
||||
reg s_axis_tlast = 0;
|
||||
reg [ID_WIDTH-1:0] s_axis_tid = 0;
|
||||
reg [DEST_WIDTH-1:0] s_axis_tdest = 0;
|
||||
reg [USER_WIDTH-1:0] s_axis_tuser = 0;
|
||||
reg m_axis_tready = 0;
|
||||
reg s_axis_cmd_csum_enable = 0;
|
||||
reg [7:0] s_axis_cmd_csum_start = 0;
|
||||
reg [7:0] s_axis_cmd_csum_offset = 0;
|
||||
reg [15:0] s_axis_cmd_csum_init = 0;
|
||||
reg s_axis_cmd_valid = 0;
|
||||
|
||||
// Outputs
|
||||
wire s_axis_tready;
|
||||
wire [DATA_WIDTH-1:0] m_axis_tdata;
|
||||
wire [KEEP_WIDTH-1:0] m_axis_tkeep;
|
||||
wire m_axis_tvalid;
|
||||
wire m_axis_tlast;
|
||||
wire [ID_WIDTH-1:0] m_axis_tid;
|
||||
wire [DEST_WIDTH-1:0] m_axis_tdest;
|
||||
wire [USER_WIDTH-1:0] m_axis_tuser;
|
||||
wire s_axis_cmd_ready;
|
||||
|
||||
initial begin
|
||||
// myhdl integration
|
||||
$from_myhdl(
|
||||
clk,
|
||||
rst,
|
||||
current_test,
|
||||
s_axis_tdata,
|
||||
s_axis_tkeep,
|
||||
s_axis_tvalid,
|
||||
s_axis_tlast,
|
||||
s_axis_tid,
|
||||
s_axis_tdest,
|
||||
s_axis_tuser,
|
||||
m_axis_tready,
|
||||
s_axis_cmd_csum_enable,
|
||||
s_axis_cmd_csum_start,
|
||||
s_axis_cmd_csum_offset,
|
||||
s_axis_cmd_csum_init,
|
||||
s_axis_cmd_valid
|
||||
);
|
||||
$to_myhdl(
|
||||
s_axis_tready,
|
||||
m_axis_tdata,
|
||||
m_axis_tkeep,
|
||||
m_axis_tvalid,
|
||||
m_axis_tlast,
|
||||
m_axis_tid,
|
||||
m_axis_tdest,
|
||||
m_axis_tuser,
|
||||
s_axis_cmd_ready
|
||||
);
|
||||
|
||||
// dump file
|
||||
$dumpfile("test_tx_checksum_64.lxt");
|
||||
$dumpvars(0, test_tx_checksum_64);
|
||||
end
|
||||
|
||||
tx_checksum #(
|
||||
.DATA_WIDTH(DATA_WIDTH),
|
||||
.KEEP_WIDTH(KEEP_WIDTH),
|
||||
.ID_ENABLE(ID_ENABLE),
|
||||
.ID_WIDTH(ID_WIDTH),
|
||||
.DEST_ENABLE(DEST_ENABLE),
|
||||
.DEST_WIDTH(DEST_WIDTH),
|
||||
.USER_ENABLE(USER_ENABLE),
|
||||
.USER_WIDTH(USER_WIDTH),
|
||||
.USE_INIT_VALUE(USE_INIT_VALUE),
|
||||
.DATA_FIFO_DEPTH(DATA_FIFO_DEPTH),
|
||||
.CHECKSUM_FIFO_DEPTH(CHECKSUM_FIFO_DEPTH)
|
||||
)
|
||||
UUT (
|
||||
.clk(clk),
|
||||
.rst(rst),
|
||||
.s_axis_tdata(s_axis_tdata),
|
||||
.s_axis_tkeep(s_axis_tkeep),
|
||||
.s_axis_tvalid(s_axis_tvalid),
|
||||
.s_axis_tready(s_axis_tready),
|
||||
.s_axis_tlast(s_axis_tlast),
|
||||
.s_axis_tid(s_axis_tid),
|
||||
.s_axis_tdest(s_axis_tdest),
|
||||
.s_axis_tuser(s_axis_tuser),
|
||||
.m_axis_tdata(m_axis_tdata),
|
||||
.m_axis_tkeep(m_axis_tkeep),
|
||||
.m_axis_tvalid(m_axis_tvalid),
|
||||
.m_axis_tready(m_axis_tready),
|
||||
.m_axis_tlast(m_axis_tlast),
|
||||
.m_axis_tid(m_axis_tid),
|
||||
.m_axis_tdest(m_axis_tdest),
|
||||
.m_axis_tuser(m_axis_tuser),
|
||||
.s_axis_cmd_csum_enable(s_axis_cmd_csum_enable),
|
||||
.s_axis_cmd_csum_start(s_axis_cmd_csum_start),
|
||||
.s_axis_cmd_csum_offset(s_axis_cmd_csum_offset),
|
||||
.s_axis_cmd_csum_init(s_axis_cmd_csum_init),
|
||||
.s_axis_cmd_valid(s_axis_cmd_valid),
|
||||
.s_axis_cmd_ready(s_axis_cmd_ready)
|
||||
);
|
||||
|
||||
endmodule
|
112
fpga/common/tb/tx_checksum/Makefile
Normal file
112
fpga/common/tb/tx_checksum/Makefile
Normal file
@ -0,0 +1,112 @@
|
||||
# Copyright 2020, The Regents of the University of California.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
#
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
|
||||
# IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
|
||||
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
# OF SUCH DAMAGE.
|
||||
#
|
||||
# The views and conclusions contained in the software and documentation are those
|
||||
# of the authors and should not be interpreted as representing official policies,
|
||||
# either expressed or implied, of The Regents of the University of California.
|
||||
|
||||
TOPLEVEL_LANG = verilog
|
||||
|
||||
SIM ?= icarus
|
||||
WAVES ?= 0
|
||||
|
||||
COCOTB_HDL_TIMEUNIT = 1ns
|
||||
COCOTB_HDL_TIMEPRECISION = 1ps
|
||||
|
||||
DUT = tx_checksum
|
||||
TOPLEVEL = $(DUT)
|
||||
MODULE = test_$(DUT)
|
||||
VERILOG_SOURCES += ../../rtl/$(DUT).v
|
||||
VERILOG_SOURCES += ../../lib/axis/rtl/axis_fifo.v
|
||||
|
||||
# module parameters
|
||||
export PARAM_DATA_WIDTH ?= 64
|
||||
export PARAM_KEEP_WIDTH ?= $(shell expr $(PARAM_DATA_WIDTH) / 8 )
|
||||
export PARAM_ID_ENABLE = 0
|
||||
export PARAM_ID_WIDTH = 8
|
||||
export PARAM_DEST_ENABLE = 0
|
||||
export PARAM_DEST_WIDTH = 8
|
||||
export PARAM_USER_ENABLE = 1
|
||||
export PARAM_USER_WIDTH = 1
|
||||
export PARAM_USE_INIT_VALUE = 1
|
||||
export PARAM_DATA_FIFO_DEPTH = 16384
|
||||
export PARAM_CHECKSUM_FIFO_DEPTH = 4
|
||||
|
||||
SIM_BUILD ?= sim_build_$(MODULE)-$(PARAM_DATA_WIDTH)
|
||||
|
||||
ifeq ($(SIM), icarus)
|
||||
PLUSARGS += -fst
|
||||
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).DATA_WIDTH=$(PARAM_DATA_WIDTH)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).KEEP_WIDTH=$(PARAM_KEEP_WIDTH)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).ID_ENABLE=$(PARAM_ID_ENABLE)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).ID_WIDTH=$(PARAM_ID_WIDTH)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).DEST_ENABLE=$(PARAM_DEST_ENABLE)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).DEST_WIDTH=$(PARAM_DEST_WIDTH)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).USER_ENABLE=$(PARAM_USER_ENABLE)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).USER_WIDTH=$(PARAM_USER_WIDTH)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).USE_INIT_VALUE=$(PARAM_USE_INIT_VALUE)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).DATA_FIFO_DEPTH=$(PARAM_DATA_FIFO_DEPTH)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).CHECKSUM_FIFO_DEPTH=$(PARAM_CHECKSUM_FIFO_DEPTH)
|
||||
|
||||
ifeq ($(WAVES), 1)
|
||||
VERILOG_SOURCES += iverilog_dump.v
|
||||
COMPILE_ARGS += -s iverilog_dump
|
||||
endif
|
||||
else ifeq ($(SIM), verilator)
|
||||
COMPILE_ARGS += -Wno-SELRANGE -Wno-WIDTH
|
||||
|
||||
COMPILE_ARGS += -GDATA_WIDTH=$(PARAM_DATA_WIDTH)
|
||||
COMPILE_ARGS += -GKEEP_WIDTH=$(PARAM_KEEP_WIDTH)
|
||||
COMPILE_ARGS += -GID_ENABLE=$(PARAM_ID_ENABLE)
|
||||
COMPILE_ARGS += -GID_WIDTH=$(PARAM_ID_WIDTH)
|
||||
COMPILE_ARGS += -GDEST_ENABLE=$(PARAM_DEST_ENABLE)
|
||||
COMPILE_ARGS += -GDEST_WIDTH=$(PARAM_DEST_WIDTH)
|
||||
COMPILE_ARGS += -GUSER_ENABLE=$(PARAM_USER_ENABLE)
|
||||
COMPILE_ARGS += -GUSER_WIDTH=$(PARAM_USER_WIDTH)
|
||||
COMPILE_ARGS += -GUSE_INIT_VALUE=$(PARAM_USE_INIT_VALUE)
|
||||
COMPILE_ARGS += -GDATA_FIFO_DEPTH=$(PARAM_DATA_FIFO_DEPTH)
|
||||
COMPILE_ARGS += -GCHECKSUM_FIFO_DEPTH=$(PARAM_CHECKSUM_FIFO_DEPTH)
|
||||
|
||||
ifeq ($(WAVES), 1)
|
||||
COMPILE_ARGS += --trace-fst
|
||||
endif
|
||||
endif
|
||||
|
||||
iverilog_dump.v:
|
||||
echo 'module iverilog_dump();' > $@
|
||||
echo 'initial begin' >> $@
|
||||
echo ' $$dumpfile("$(TOPLEVEL).fst");' >> $@
|
||||
echo ' $$dumpvars(0, $(TOPLEVEL));' >> $@
|
||||
echo 'end' >> $@
|
||||
echo 'endmodule' >> $@
|
||||
|
||||
clean::
|
||||
@rm -rf sim_build_*
|
||||
@rm -rf iverilog_dump.v
|
||||
@rm -rf dump.fst $(TOPLEVEL).fst
|
||||
|
||||
include $(shell cocotb-config --makefiles)/Makefile.sim
|
||||
|
332
fpga/common/tb/tx_checksum/test_tx_checksum.py
Normal file
332
fpga/common/tb/tx_checksum/test_tx_checksum.py
Normal file
@ -0,0 +1,332 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
|
||||
Copyright 2020, The Regents of the University of California.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
|
||||
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of The Regents of the University of California.
|
||||
|
||||
"""
|
||||
|
||||
import itertools
|
||||
import logging
|
||||
import os
|
||||
import struct
|
||||
|
||||
import scapy.utils
|
||||
from scapy.layers.l2 import Ether
|
||||
from scapy.layers.inet import IP, UDP
|
||||
|
||||
import cocotb_test.simulator
|
||||
import pytest
|
||||
|
||||
import cocotb
|
||||
from cocotb.clock import Clock
|
||||
from cocotb.triggers import RisingEdge
|
||||
from cocotb.regression import TestFactory
|
||||
|
||||
from cocotbext.axi import AxiStreamFrame, AxiStreamSource, AxiStreamSink
|
||||
from cocotbext.axi.stream import define_stream
|
||||
|
||||
|
||||
CsumCmdTransaction, CsumCmdSource, CsumCmdSink, CsumCmdMonitor = define_stream("CsumCmd",
|
||||
signals=["csum_enable", "csum_start", "csum_offset", "csum_init", "valid"],
|
||||
optional_signals=["ready"]
|
||||
)
|
||||
|
||||
|
||||
class TB(object):
|
||||
def __init__(self, dut):
|
||||
self.dut = dut
|
||||
|
||||
self.log = logging.getLogger("cocotb.tb")
|
||||
self.log.setLevel(logging.DEBUG)
|
||||
|
||||
cocotb.fork(Clock(dut.clk, 4, units="ns").start())
|
||||
|
||||
self.source = AxiStreamSource(dut, "s_axis", dut.clk, dut.rst)
|
||||
self.sink = AxiStreamSink(dut, "m_axis", dut.clk, dut.rst)
|
||||
|
||||
self.cmd_source = CsumCmdSource(dut, "s_axis_cmd", dut.clk, dut.rst)
|
||||
|
||||
def set_idle_generator(self, generator=None):
|
||||
if generator:
|
||||
self.source.set_pause_generator(generator())
|
||||
|
||||
def set_backpressure_generator(self, generator=None):
|
||||
if generator:
|
||||
self.sink.set_pause_generator(generator())
|
||||
|
||||
async def reset(self):
|
||||
self.dut.rst.setimmediatevalue(0)
|
||||
await RisingEdge(self.dut.clk)
|
||||
await RisingEdge(self.dut.clk)
|
||||
self.dut.rst <= 1
|
||||
await RisingEdge(self.dut.clk)
|
||||
await RisingEdge(self.dut.clk)
|
||||
self.dut.rst <= 0
|
||||
await RisingEdge(self.dut.clk)
|
||||
await RisingEdge(self.dut.clk)
|
||||
|
||||
|
||||
async def run_test(dut, payload_lengths=None, payload_data=None, idle_inserter=None, backpressure_inserter=None):
|
||||
|
||||
tb = TB(dut)
|
||||
|
||||
await tb.reset()
|
||||
|
||||
tb.set_idle_generator(idle_inserter)
|
||||
tb.set_backpressure_generator(backpressure_inserter)
|
||||
|
||||
test_pkts = []
|
||||
test_frames = []
|
||||
|
||||
ip_id = 1
|
||||
|
||||
for payload in [payload_data(x) for x in payload_lengths()]:
|
||||
eth = Ether(src='5A:51:52:53:54:55', dst='DA:D1:D2:D3:D4:D5')
|
||||
ip = IP(src='192.168.1.100', dst='192.168.1.101', id=ip_id)
|
||||
udp = UDP(sport=1234, dport=4321)
|
||||
test_pkt = eth / ip / udp / payload
|
||||
|
||||
ip_id = (ip_id + 1) & 0xffff
|
||||
|
||||
# don't compute checksum
|
||||
test_pkts.append(test_pkt.copy())
|
||||
test_frame = AxiStreamFrame(test_pkt.build())
|
||||
test_frames.append(test_frame)
|
||||
|
||||
tb.source.send(test_frame)
|
||||
tb.cmd_source.send(CsumCmdTransaction(csum_enable=0, csum_start=34, csum_offset=40, csum_init=0))
|
||||
|
||||
# inline partial checksum
|
||||
test_pkts.append(test_pkt.copy())
|
||||
|
||||
pkt = test_pkt.copy()
|
||||
partial_csum = scapy.utils.checksum(bytes(pkt[UDP]))
|
||||
pkt[UDP].chksum = partial_csum
|
||||
|
||||
test_frame = AxiStreamFrame(pkt.build())
|
||||
test_frames.append(test_frame)
|
||||
|
||||
tb.source.send(test_frame)
|
||||
tb.cmd_source.send(CsumCmdTransaction(csum_enable=1, csum_start=34, csum_offset=40, csum_init=0))
|
||||
|
||||
# partial checksum in command
|
||||
test_pkts.append(test_pkt.copy())
|
||||
|
||||
pkt = test_pkt.copy()
|
||||
partial_csum = scapy.utils.checksum(bytes(pkt[UDP]))
|
||||
pkt[UDP].chksum = 0
|
||||
|
||||
test_frame = AxiStreamFrame(pkt.build())
|
||||
test_frames.append(test_frame)
|
||||
|
||||
tb.source.send(test_frame)
|
||||
tb.cmd_source.send(CsumCmdTransaction(csum_enable=1, csum_start=34, csum_offset=40, csum_init=partial_csum))
|
||||
|
||||
for test_pkt, test_frame in zip(test_pkts, test_frames):
|
||||
await tb.sink.wait()
|
||||
rx_frame = tb.sink.recv()
|
||||
|
||||
rx_pkt = Ether(bytes(rx_frame))
|
||||
|
||||
tb.log.info("RX packet: %s", repr(rx_pkt))
|
||||
|
||||
check_pkt = Ether(test_pkt.build())
|
||||
|
||||
tb.log.info("RX packet UDP checksum: 0x%04x (expected 0x%04x)", rx_pkt[UDP].chksum, check_pkt[UDP].chksum)
|
||||
|
||||
assert check_pkt == rx_pkt
|
||||
|
||||
assert tb.sink.empty()
|
||||
|
||||
await RisingEdge(dut.clk)
|
||||
await RisingEdge(dut.clk)
|
||||
|
||||
|
||||
async def run_test_offsets(dut, payload_lengths=None, payload_data=None, idle_inserter=None, backpressure_inserter=None):
|
||||
|
||||
tb = TB(dut)
|
||||
|
||||
await tb.reset()
|
||||
|
||||
tb.set_idle_generator(idle_inserter)
|
||||
tb.set_backpressure_generator(backpressure_inserter)
|
||||
|
||||
test_pkts = []
|
||||
test_frames = []
|
||||
check_frames = []
|
||||
|
||||
ip_id = 1
|
||||
|
||||
for payload in [payload_data(x) for x in payload_lengths()]:
|
||||
eth = Ether(src='5A:51:52:53:54:55', dst='DA:D1:D2:D3:D4:D5')
|
||||
test_pkt = eth / payload
|
||||
|
||||
ip_id = (ip_id + 1) & 0xffff
|
||||
|
||||
for start in range(0, min(len(payload)+14, 32)):
|
||||
offset = 0
|
||||
test_pkts.append(test_pkt.copy())
|
||||
test_frame = AxiStreamFrame(test_pkt.build())
|
||||
test_frames.append(test_frame)
|
||||
|
||||
tb.source.send(test_frame)
|
||||
tb.cmd_source.send(CsumCmdTransaction(csum_enable=1, csum_start=start, csum_offset=offset, csum_init=0))
|
||||
|
||||
csum = scapy.utils.checksum(bytes(test_pkt)[start:])
|
||||
|
||||
check_frame = bytearray(test_frame.tdata)
|
||||
struct.pack_into('>H', check_frame, offset, csum)
|
||||
|
||||
check_frames.append(check_frame)
|
||||
|
||||
for offset in range(0, min(len(payload)+14, 32)-1):
|
||||
start = 0
|
||||
test_pkts.append(test_pkt.copy())
|
||||
test_frame = AxiStreamFrame(test_pkt.build())
|
||||
test_frames.append(test_frame)
|
||||
|
||||
tb.source.send(test_frame)
|
||||
tb.cmd_source.send(CsumCmdTransaction(csum_enable=1, csum_start=start, csum_offset=offset, csum_init=0))
|
||||
|
||||
csum = scapy.utils.checksum(bytes(test_pkt)[start:])
|
||||
|
||||
check_frame = bytearray(test_frame.tdata)
|
||||
struct.pack_into('>H', check_frame, offset, csum)
|
||||
|
||||
check_frames.append(check_frame)
|
||||
|
||||
for test_pkt, test_frame, check_frame in zip(test_pkts, test_frames, check_frames):
|
||||
await tb.sink.wait()
|
||||
rx_frame = tb.sink.recv()
|
||||
|
||||
rx_pkt = Ether(bytes(rx_frame))
|
||||
|
||||
tb.log.info("RX packet: %s", repr(rx_pkt))
|
||||
|
||||
assert rx_frame.tdata == check_frame
|
||||
|
||||
assert tb.sink.empty()
|
||||
|
||||
await RisingEdge(dut.clk)
|
||||
await RisingEdge(dut.clk)
|
||||
|
||||
|
||||
def cycle_pause():
|
||||
return itertools.cycle([1, 1, 1, 0])
|
||||
|
||||
|
||||
def size_list():
|
||||
return list(range(1, 128)) + [512, 1472, 9172] + [18]*10
|
||||
|
||||
|
||||
def size_list2():
|
||||
return list(range(1, 64))
|
||||
|
||||
|
||||
def incrementing_payload(length):
|
||||
return bytes(itertools.islice(itertools.cycle(range(256)), length))
|
||||
|
||||
|
||||
if cocotb.SIM_NAME:
|
||||
|
||||
# for test in [run_test, run_test_offsets]:
|
||||
|
||||
# factory = TestFactory(run_test)
|
||||
# factory.add_option("payload_lengths", [size_list])
|
||||
# factory.add_option("payload_data", [incrementing_payload])
|
||||
# factory.add_option("idle_inserter", [None, cycle_pause])
|
||||
# factory.add_option("backpressure_inserter", [None, cycle_pause])
|
||||
# factory.generate_tests()
|
||||
|
||||
factory = TestFactory(run_test)
|
||||
factory.add_option("payload_lengths", [size_list])
|
||||
factory.add_option("payload_data", [incrementing_payload])
|
||||
factory.add_option("idle_inserter", [None, cycle_pause])
|
||||
factory.add_option("backpressure_inserter", [None, cycle_pause])
|
||||
factory.generate_tests()
|
||||
|
||||
factory = TestFactory(run_test_offsets)
|
||||
factory.add_option("payload_lengths", [size_list2])
|
||||
factory.add_option("payload_data", [incrementing_payload])
|
||||
factory.add_option("idle_inserter", [None, cycle_pause])
|
||||
factory.add_option("backpressure_inserter", [None, cycle_pause])
|
||||
factory.generate_tests()
|
||||
|
||||
|
||||
# cocotb-test
|
||||
|
||||
tests_dir = os.path.dirname(__file__)
|
||||
rtl_dir = os.path.abspath(os.path.join(tests_dir, '..', '..', 'rtl'))
|
||||
lib_dir = os.path.abspath(os.path.join(rtl_dir, '..', 'lib'))
|
||||
axi_rtl_dir = os.path.abspath(os.path.join(lib_dir, 'axi', 'rtl'))
|
||||
axis_rtl_dir = os.path.abspath(os.path.join(lib_dir, 'axis', 'rtl'))
|
||||
eth_rtl_dir = os.path.abspath(os.path.join(lib_dir, 'eth', 'rtl'))
|
||||
pcie_rtl_dir = os.path.abspath(os.path.join(lib_dir, 'pcie', 'rtl'))
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data_width", [64, 256])
|
||||
def test_tx_checksum(request, data_width):
|
||||
dut = "tx_checksum"
|
||||
module = os.path.splitext(os.path.basename(__file__))[0]
|
||||
toplevel = dut
|
||||
|
||||
verilog_sources = [
|
||||
os.path.join(rtl_dir, f"{dut}.v"),
|
||||
os.path.join(axis_rtl_dir, "axis_fifo.v"),
|
||||
]
|
||||
|
||||
parameters = {}
|
||||
|
||||
parameters['DATA_WIDTH'] = data_width
|
||||
parameters['KEEP_WIDTH'] = parameters['DATA_WIDTH'] // 8
|
||||
parameters['ID_ENABLE'] = 0
|
||||
parameters['ID_WIDTH'] = 8
|
||||
parameters['DEST_ENABLE'] = 0
|
||||
parameters['DEST_WIDTH'] = 8
|
||||
parameters['USER_ENABLE'] = 1
|
||||
parameters['USER_WIDTH'] = 1
|
||||
parameters['USE_INIT_VALUE'] = 1
|
||||
parameters['DATA_FIFO_DEPTH'] = 16384
|
||||
parameters['CHECKSUM_FIFO_DEPTH'] = 4
|
||||
|
||||
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(
|
||||
python_search=[tests_dir],
|
||||
verilog_sources=verilog_sources,
|
||||
toplevel=toplevel,
|
||||
module=module,
|
||||
parameters=parameters,
|
||||
sim_build=sim_build,
|
||||
extra_env=extra_env,
|
||||
)
|
@ -1 +0,0 @@
|
||||
../lib/eth/tb/udp_ep.py
|
@ -1 +0,0 @@
|
||||
../lib/eth/tb/xgmii_ep.py
|
@ -1 +0,0 @@
|
||||
../lib/eth/tb/axis_ep.py
|
@ -1 +0,0 @@
|
||||
../lib/eth/tb/eth_ep.py
|
153
fpga/mqnic/ADM_PCIE_9V3/fpga_100g/tb/fpga_core/Makefile
Normal file
153
fpga/mqnic/ADM_PCIE_9V3/fpga_100g/tb/fpga_core/Makefile
Normal file
@ -0,0 +1,153 @@
|
||||
# Copyright 2020, The Regents of the University of California.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
#
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
|
||||
# IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
|
||||
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
# OF SUCH DAMAGE.
|
||||
#
|
||||
# The views and conclusions contained in the software and documentation are those
|
||||
# of the authors and should not be interpreted as representing official policies,
|
||||
# either expressed or implied, of The Regents of the University of California.
|
||||
|
||||
TOPLEVEL_LANG = verilog
|
||||
|
||||
SIM ?= icarus
|
||||
WAVES ?= 0
|
||||
|
||||
COCOTB_HDL_TIMEUNIT = 1ns
|
||||
COCOTB_HDL_TIMEPRECISION = 1ps
|
||||
|
||||
DUT = fpga_core
|
||||
TOPLEVEL = $(DUT)
|
||||
MODULE = test_$(DUT)
|
||||
VERILOG_SOURCES += ../../rtl/$(DUT).v
|
||||
VERILOG_SOURCES += ../../rtl/common/mqnic_interface.v
|
||||
VERILOG_SOURCES += ../../rtl/common/mqnic_port.v
|
||||
VERILOG_SOURCES += ../../rtl/common/cpl_write.v
|
||||
VERILOG_SOURCES += ../../rtl/common/cpl_op_mux.v
|
||||
VERILOG_SOURCES += ../../rtl/common/desc_fetch.v
|
||||
VERILOG_SOURCES += ../../rtl/common/desc_op_mux.v
|
||||
VERILOG_SOURCES += ../../rtl/common/queue_manager.v
|
||||
VERILOG_SOURCES += ../../rtl/common/cpl_queue_manager.v
|
||||
VERILOG_SOURCES += ../../rtl/common/tx_engine.v
|
||||
VERILOG_SOURCES += ../../rtl/common/rx_engine.v
|
||||
VERILOG_SOURCES += ../../rtl/common/tx_checksum.v
|
||||
VERILOG_SOURCES += ../../rtl/common/rx_hash.v
|
||||
VERILOG_SOURCES += ../../rtl/common/rx_checksum.v
|
||||
VERILOG_SOURCES += ../../rtl/common/tx_scheduler_rr.v
|
||||
VERILOG_SOURCES += ../../rtl/common/event_mux.v
|
||||
VERILOG_SOURCES += ../../rtl/common/tdma_scheduler.v
|
||||
VERILOG_SOURCES += ../../rtl/common/tdma_ber.v
|
||||
VERILOG_SOURCES += ../../rtl/common/tdma_ber_ch.v
|
||||
VERILOG_SOURCES += ../../lib/eth/rtl/ptp_clock.v
|
||||
VERILOG_SOURCES += ../../lib/eth/rtl/ptp_clock_cdc.v
|
||||
VERILOG_SOURCES += ../../lib/eth/rtl/ptp_perout.v
|
||||
VERILOG_SOURCES += ../../lib/eth/rtl/ptp_ts_extract.v
|
||||
VERILOG_SOURCES += ../../lib/axi/rtl/axil_interconnect.v
|
||||
VERILOG_SOURCES += ../../lib/axi/rtl/arbiter.v
|
||||
VERILOG_SOURCES += ../../lib/axi/rtl/priority_encoder.v
|
||||
VERILOG_SOURCES += ../../lib/axis/rtl/axis_adapter.v
|
||||
VERILOG_SOURCES += ../../lib/axis/rtl/axis_arb_mux.v
|
||||
VERILOG_SOURCES += ../../lib/axis/rtl/axis_async_fifo.v
|
||||
VERILOG_SOURCES += ../../lib/axis/rtl/axis_async_fifo_adapter.v
|
||||
VERILOG_SOURCES += ../../lib/axis/rtl/axis_fifo.v
|
||||
VERILOG_SOURCES += ../../lib/axis/rtl/axis_register.v
|
||||
VERILOG_SOURCES += ../../lib/pcie/rtl/pcie_us_axil_master.v
|
||||
VERILOG_SOURCES += ../../lib/pcie/rtl/dma_if_pcie_us.v
|
||||
VERILOG_SOURCES += ../../lib/pcie/rtl/dma_if_pcie_us_rd.v
|
||||
VERILOG_SOURCES += ../../lib/pcie/rtl/dma_if_pcie_us_wr.v
|
||||
VERILOG_SOURCES += ../../lib/pcie/rtl/dma_if_mux.v
|
||||
VERILOG_SOURCES += ../../lib/pcie/rtl/dma_if_mux_rd.v
|
||||
VERILOG_SOURCES += ../../lib/pcie/rtl/dma_if_mux_wr.v
|
||||
VERILOG_SOURCES += ../../lib/pcie/rtl/dma_psdpram.v
|
||||
VERILOG_SOURCES += ../../lib/pcie/rtl/dma_client_axis_sink.v
|
||||
VERILOG_SOURCES += ../../lib/pcie/rtl/dma_client_axis_source.v
|
||||
VERILOG_SOURCES += ../../lib/pcie/rtl/pcie_us_cfg.v
|
||||
VERILOG_SOURCES += ../../lib/pcie/rtl/pcie_us_msi.v
|
||||
VERILOG_SOURCES += ../../lib/pcie/rtl/pcie_tag_manager.v
|
||||
VERILOG_SOURCES += ../../lib/pcie/rtl/pulse_merge.v
|
||||
|
||||
# module parameters
|
||||
export PARAM_AXIS_PCIE_DATA_WIDTH ?= 512
|
||||
export PARAM_AXIS_PCIE_KEEP_WIDTH ?= $(shell expr $(PARAM_AXIS_PCIE_DATA_WIDTH) / 32 )
|
||||
export PARAM_AXIS_PCIE_RQ_USER_WIDTH ?= $(if $(filter-out 512,$(PARAM_AXIS_PCIE_DATA_WIDTH)),62,137)
|
||||
export PARAM_AXIS_PCIE_RC_USER_WIDTH ?= $(if $(filter-out 512,$(PARAM_AXIS_PCIE_DATA_WIDTH)),75,161)
|
||||
export PARAM_AXIS_PCIE_CQ_USER_WIDTH ?= $(if $(filter-out 512,$(PARAM_AXIS_PCIE_DATA_WIDTH)),88,183)
|
||||
export PARAM_AXIS_PCIE_CC_USER_WIDTH ?= $(if $(filter-out 512,$(PARAM_AXIS_PCIE_DATA_WIDTH)),33,81)
|
||||
export PARAM_RQ_SEQ_NUM_WIDTH ?= 6
|
||||
export PARAM_BAR0_APERTURE ?= 24
|
||||
export PARAM_AXIS_ETH_DATA_WIDTH = 512
|
||||
export PARAM_AXIS_ETH_KEEP_WIDTH = $(shell expr $(PARAM_AXIS_ETH_DATA_WIDTH) / 8 )
|
||||
|
||||
SIM_BUILD ?= sim_build_$(MODULE)
|
||||
|
||||
ifeq ($(SIM), icarus)
|
||||
PLUSARGS += -fst
|
||||
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).AXIS_PCIE_DATA_WIDTH=$(PARAM_AXIS_PCIE_DATA_WIDTH)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).AXIS_PCIE_KEEP_WIDTH=$(PARAM_AXIS_PCIE_KEEP_WIDTH)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).AXIS_PCIE_RQ_USER_WIDTH=$(PARAM_AXIS_PCIE_RQ_USER_WIDTH)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).AXIS_PCIE_RC_USER_WIDTH=$(PARAM_AXIS_PCIE_RC_USER_WIDTH)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).AXIS_PCIE_CQ_USER_WIDTH=$(PARAM_AXIS_PCIE_CQ_USER_WIDTH)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).AXIS_PCIE_CC_USER_WIDTH=$(PARAM_AXIS_PCIE_CC_USER_WIDTH)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).RQ_SEQ_NUM_WIDTH=$(PARAM_RQ_SEQ_NUM_WIDTH)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).BAR0_APERTURE=$(PARAM_BAR0_APERTURE)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).AXIS_ETH_DATA_WIDTH=$(PARAM_AXIS_ETH_DATA_WIDTH)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).AXIS_ETH_KEEP_WIDTH=$(PARAM_AXIS_ETH_KEEP_WIDTH)
|
||||
|
||||
ifeq ($(WAVES), 1)
|
||||
VERILOG_SOURCES += iverilog_dump.v
|
||||
COMPILE_ARGS += -s iverilog_dump
|
||||
endif
|
||||
else ifeq ($(SIM), verilator)
|
||||
COMPILE_ARGS += -Wno-SELRANGE -Wno-WIDTH
|
||||
|
||||
COMPILE_ARGS += -GAXIS_PCIE_DATA_WIDTH=$(PARAM_AXIS_PCIE_DATA_WIDTH)
|
||||
COMPILE_ARGS += -GAXIS_PCIE_KEEP_WIDTH=$(PARAM_AXIS_PCIE_KEEP_WIDTH)
|
||||
COMPILE_ARGS += -GAXIS_PCIE_RQ_USER_WIDTH=$(PARAM_AXIS_PCIE_RQ_USER_WIDTH)
|
||||
COMPILE_ARGS += -GAXIS_PCIE_RC_USER_WIDTH=$(PARAM_AXIS_PCIE_RC_USER_WIDTH)
|
||||
COMPILE_ARGS += -GAXIS_PCIE_CQ_USER_WIDTH=$(PARAM_AXIS_PCIE_CQ_USER_WIDTH)
|
||||
COMPILE_ARGS += -GAXIS_PCIE_CC_USER_WIDTH=$(PARAM_AXIS_PCIE_CC_USER_WIDTH)
|
||||
COMPILE_ARGS += -GRQ_SEQ_NUM_WIDTH=$(PARAM_RQ_SEQ_NUM_WIDTH)
|
||||
COMPILE_ARGS += -GBAR0_APERTURE=$(PARAM_BAR0_APERTURE)
|
||||
COMPILE_ARGS += -GAXIS_ETH_DATA_WIDTH=$(PARAM_AXIS_ETH_DATA_WIDTH)
|
||||
COMPILE_ARGS += -GAXIS_ETH_KEEP_WIDTH=$(PARAM_AXIS_ETH_KEEP_WIDTH)
|
||||
|
||||
ifeq ($(WAVES), 1)
|
||||
COMPILE_ARGS += --trace-fst
|
||||
endif
|
||||
endif
|
||||
|
||||
iverilog_dump.v:
|
||||
echo 'module iverilog_dump();' > $@
|
||||
echo 'initial begin' >> $@
|
||||
echo ' $$dumpfile("$(TOPLEVEL).fst");' >> $@
|
||||
echo ' $$dumpvars(0, $(TOPLEVEL));' >> $@
|
||||
echo 'end' >> $@
|
||||
echo 'endmodule' >> $@
|
||||
|
||||
clean::
|
||||
@rm -rf sim_build_*
|
||||
@rm -rf iverilog_dump.v
|
||||
@rm -rf dump.fst $(TOPLEVEL).fst
|
||||
|
||||
include $(shell cocotb-config --makefiles)/Makefile.sim
|
||||
|
1
fpga/mqnic/ADM_PCIE_9V3/fpga_100g/tb/fpga_core/mqnic.py
Symbolic link
1
fpga/mqnic/ADM_PCIE_9V3/fpga_100g/tb/fpga_core/mqnic.py
Symbolic link
@ -0,0 +1 @@
|
||||
../../../../../common/tb/mqnic.py
|
587
fpga/mqnic/ADM_PCIE_9V3/fpga_100g/tb/fpga_core/test_fpga_core.py
Normal file
587
fpga/mqnic/ADM_PCIE_9V3/fpga_100g/tb/fpga_core/test_fpga_core.py
Normal file
@ -0,0 +1,587 @@
|
||||
"""
|
||||
|
||||
Copyright 2020, The Regents of the University of California.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
|
||||
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of The Regents of the University of California.
|
||||
|
||||
"""
|
||||
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
|
||||
import scapy.utils
|
||||
from scapy.layers.l2 import Ether
|
||||
from scapy.layers.inet import IP, UDP
|
||||
|
||||
import cocotb_test.simulator
|
||||
|
||||
import cocotb
|
||||
from cocotb.log import SimLog
|
||||
from cocotb.clock import Clock
|
||||
from cocotb.triggers import RisingEdge, FallingEdge, Timer
|
||||
|
||||
from cocotbext.pcie.core import RootComplex
|
||||
from cocotbext.pcie.xilinx.us import UltraScalePlusPcieDevice
|
||||
|
||||
from cocotbext.axi import AxiStreamSource, AxiStreamSink
|
||||
|
||||
try:
|
||||
import mqnic
|
||||
except ImportError:
|
||||
# attempt import from current directory
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__)))
|
||||
try:
|
||||
import mqnic
|
||||
finally:
|
||||
del sys.path[0]
|
||||
|
||||
|
||||
class TB(object):
|
||||
def __init__(self, dut):
|
||||
self.dut = dut
|
||||
|
||||
self.BAR0_APERTURE = int(os.getenv("PARAM_BAR0_APERTURE"))
|
||||
|
||||
self.log = SimLog("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_cc_straddle=False,
|
||||
rq_rc_straddle=False,
|
||||
rc_4tlp_straddle=False,
|
||||
enable_pf1=False,
|
||||
enable_client_tag=True,
|
||||
enable_extended_tag=True,
|
||||
enable_parity=False,
|
||||
enable_rx_msg_interface=False,
|
||||
enable_sriov=False,
|
||||
enable_extended_configuration=False,
|
||||
|
||||
enable_pf0_msi=True,
|
||||
enable_pf1_msi=False,
|
||||
|
||||
# signals
|
||||
# Clock and Reset Interface
|
||||
user_clk=dut.clk_250mhz,
|
||||
user_reset=dut.rst_250mhz,
|
||||
# user_lnk_up
|
||||
# sys_clk
|
||||
# sys_clk_gt
|
||||
# sys_reset
|
||||
# phy_rdy_out
|
||||
|
||||
# Requester reQuest Interface
|
||||
rq_entity=dut,
|
||||
rq_name="m_axis_rq",
|
||||
pcie_rq_seq_num0=dut.s_axis_rq_seq_num_0,
|
||||
pcie_rq_seq_num_vld0=dut.s_axis_rq_seq_num_valid_0,
|
||||
pcie_rq_seq_num1=dut.s_axis_rq_seq_num_1,
|
||||
pcie_rq_seq_num_vld1=dut.s_axis_rq_seq_num_valid_1,
|
||||
# pcie_rq_tag0
|
||||
# pcie_rq_tag1
|
||||
# pcie_rq_tag_av
|
||||
# pcie_rq_tag_vld0
|
||||
# pcie_rq_tag_vld1
|
||||
|
||||
# Requester Completion Interface
|
||||
rc_entity=dut,
|
||||
rc_name="s_axis_rc",
|
||||
|
||||
# Completer reQuest Interface
|
||||
cq_entity=dut,
|
||||
cq_name="s_axis_cq",
|
||||
# pcie_cq_np_req
|
||||
# pcie_cq_np_req_count
|
||||
|
||||
# Completer Completion Interface
|
||||
cc_entity=dut,
|
||||
cc_name="m_axis_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
|
||||
# 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
|
||||
# cfg_interrupt_msix_mask
|
||||
# cfg_interrupt_msix_vf_enable
|
||||
# cfg_interrupt_msix_vf_mask
|
||||
# cfg_interrupt_msix_address
|
||||
# cfg_interrupt_msix_data
|
||||
# cfg_interrupt_msix_int
|
||||
# cfg_interrupt_msix_vec_pending
|
||||
# cfg_interrupt_msix_vec_pending_status
|
||||
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.driver = mqnic.Driver(self.rc)
|
||||
|
||||
self.dev.functions[0].msi_multiple_message_capable = 5
|
||||
|
||||
self.dev.functions[0].configure_bar(0, 2**self.BAR0_APERTURE, ext=True, prefetch=True)
|
||||
|
||||
# Ethernet
|
||||
cocotb.fork(Clock(dut.qsfp_0_rx_clk, 3.102, units="ns").start())
|
||||
self.qsfp_0_source = AxiStreamSource(dut, "qsfp_0_rx_axis", dut.qsfp_0_rx_clk, dut.qsfp_0_rx_rst)
|
||||
cocotb.fork(Clock(dut.qsfp_0_tx_clk, 3.102, units="ns").start())
|
||||
self.qsfp_0_sink = AxiStreamSink(dut, "qsfp_0_tx_axis", dut.qsfp_0_tx_clk, dut.qsfp_0_tx_rst)
|
||||
|
||||
cocotb.fork(Clock(dut.qsfp_1_rx_clk, 3.102, units="ns").start())
|
||||
self.qsfp_1_source = AxiStreamSource(dut, "qsfp_1_rx_axis", dut.qsfp_1_rx_clk, dut.qsfp_1_rx_rst)
|
||||
cocotb.fork(Clock(dut.qsfp_1_tx_clk, 3.102, units="ns").start())
|
||||
self.qsfp_1_sink = AxiStreamSink(dut, "qsfp_1_tx_axis", dut.qsfp_1_tx_clk, dut.qsfp_1_tx_rst)
|
||||
|
||||
dut.user_sw.setimmediatevalue(0)
|
||||
|
||||
dut.qsfp_0_modprs_l.setimmediatevalue(0)
|
||||
dut.qsfp_1_modprs_l.setimmediatevalue(0)
|
||||
|
||||
dut.qsfp_int_l.setimmediatevalue(1)
|
||||
dut.qsfp_i2c_scl_i.setimmediatevalue(1)
|
||||
dut.qsfp_i2c_sda_i.setimmediatevalue(1)
|
||||
|
||||
dut.eeprom_i2c_scl_i.setimmediatevalue(1)
|
||||
dut.eeprom_i2c_sda_i.setimmediatevalue(1)
|
||||
|
||||
dut.qspi_0_dq_i.setimmediatevalue(0)
|
||||
dut.qspi_1_dq_i.setimmediatevalue(0)
|
||||
|
||||
self.loopback_enable = False
|
||||
cocotb.fork(self._run_loopback())
|
||||
|
||||
async def init(self):
|
||||
|
||||
self.dut.qsfp_0_rx_rst.setimmediatevalue(0)
|
||||
self.dut.qsfp_0_tx_rst.setimmediatevalue(0)
|
||||
self.dut.qsfp_1_rx_rst.setimmediatevalue(0)
|
||||
self.dut.qsfp_1_tx_rst.setimmediatevalue(0)
|
||||
|
||||
await RisingEdge(self.dut.clk_250mhz)
|
||||
await RisingEdge(self.dut.clk_250mhz)
|
||||
|
||||
self.dut.qsfp_0_rx_rst.setimmediatevalue(1)
|
||||
self.dut.qsfp_0_tx_rst.setimmediatevalue(1)
|
||||
self.dut.qsfp_1_rx_rst.setimmediatevalue(1)
|
||||
self.dut.qsfp_1_tx_rst.setimmediatevalue(1)
|
||||
|
||||
await FallingEdge(self.dut.rst_250mhz)
|
||||
await Timer(100, 'ns')
|
||||
|
||||
await RisingEdge(self.dut.clk_250mhz)
|
||||
await RisingEdge(self.dut.clk_250mhz)
|
||||
|
||||
self.dut.qsfp_0_rx_rst.setimmediatevalue(0)
|
||||
self.dut.qsfp_0_tx_rst.setimmediatevalue(0)
|
||||
self.dut.qsfp_1_rx_rst.setimmediatevalue(0)
|
||||
self.dut.qsfp_1_tx_rst.setimmediatevalue(0)
|
||||
|
||||
await self.rc.enumerate(enable_bus_mastering=True, configure_msi=True)
|
||||
|
||||
async def _run_loopback(self):
|
||||
while True:
|
||||
await RisingEdge(self.dut.clk_250mhz)
|
||||
|
||||
if self.loopback_enable:
|
||||
if not self.qsfp_0_sink.empty():
|
||||
self.qsfp_0_source.send(self.qsfp_0_sink.recv())
|
||||
if not self.qsfp_1_sink.empty():
|
||||
self.qsfp_1_source.send(self.qsfp_1_sink.recv())
|
||||
|
||||
|
||||
@cocotb.test()
|
||||
async def run_test_nic(dut):
|
||||
|
||||
tb = TB(dut)
|
||||
|
||||
await tb.init()
|
||||
|
||||
tb.log.info("Init driver")
|
||||
await tb.driver.init_dev(tb.dev.functions[0].pcie_id)
|
||||
await tb.driver.interfaces[0].open()
|
||||
# await driver.interfaces[1].open()
|
||||
|
||||
# enable queues
|
||||
tb.log.info("Enable queues")
|
||||
await tb.rc.mem_write_dword(tb.driver.interfaces[0].ports[0].hw_addr+mqnic.MQNIC_PORT_REG_SCHED_ENABLE, 0x00000001)
|
||||
for k in range(tb.driver.interfaces[0].tx_queue_count):
|
||||
await tb.rc.mem_write_dword(tb.driver.interfaces[0].ports[0].schedulers[0].hw_addr+4*k, 0x00000003)
|
||||
|
||||
# wait for all writes to complete
|
||||
await tb.rc.mem_read(tb.driver.hw_addr, 4)
|
||||
tb.log.info("Init complete")
|
||||
|
||||
tb.log.info("Send and receive single packet")
|
||||
|
||||
data = bytearray([x % 256 for x in range(1024)])
|
||||
|
||||
await tb.driver.interfaces[0].start_xmit(data, 0)
|
||||
|
||||
await tb.qsfp_0_sink.wait()
|
||||
|
||||
pkt = tb.qsfp_0_sink.recv()
|
||||
tb.log.info("Packet: %s", pkt)
|
||||
|
||||
tb.qsfp_0_source.send(pkt)
|
||||
|
||||
await tb.driver.interfaces[0].wait()
|
||||
|
||||
pkt = tb.driver.interfaces[0].recv()
|
||||
|
||||
tb.log.info("Packet: %s", pkt)
|
||||
assert pkt.rx_checksum == ~scapy.utils.checksum(bytes(pkt.data[14:])) & 0xffff
|
||||
|
||||
# await tb.driver.interfaces[1].start_xmit(data, 0)
|
||||
|
||||
# await tb.qsfp_1_0_sink.wait()
|
||||
|
||||
# pkt = tb.qsfp_1_0_sink.recv()
|
||||
# tb.log.info("Packet: %s", pkt)
|
||||
|
||||
# tb.qsfp_1_0_source.send(pkt)
|
||||
|
||||
# await tb.driver.interfaces[1].wait()
|
||||
|
||||
# pkt = tb.driver.interfaces[1].recv()
|
||||
|
||||
# tb.log.info("Packet: %s", pkt)
|
||||
# assert pkt.rx_checksum == ~scapy.utils.checksum(bytes(pkt.data[14:])) & 0xffff
|
||||
|
||||
tb.log.info("RX and TX checksum tests")
|
||||
|
||||
payload = bytes([x % 256 for x in range(256)])
|
||||
eth = Ether(src='5A:51:52:53:54:55', dst='DA:D1:D2:D3:D4:D5')
|
||||
ip = IP(src='192.168.1.100', dst='192.168.1.101')
|
||||
udp = UDP(sport=1, dport=2)
|
||||
test_pkt = eth / ip / udp / payload
|
||||
|
||||
test_pkt2 = test_pkt.copy()
|
||||
test_pkt2[UDP].chksum = scapy.utils.checksum(bytes(test_pkt2[UDP]))
|
||||
|
||||
await tb.driver.interfaces[0].start_xmit(test_pkt2.build(), 0, 34, 6)
|
||||
|
||||
await tb.qsfp_0_sink.wait()
|
||||
|
||||
pkt = tb.qsfp_0_sink.recv()
|
||||
tb.log.info("Packet: %s", pkt)
|
||||
|
||||
tb.qsfp_0_source.send(pkt)
|
||||
|
||||
await tb.driver.interfaces[0].wait()
|
||||
|
||||
pkt = tb.driver.interfaces[0].recv()
|
||||
|
||||
tb.log.info("Packet: %s", pkt)
|
||||
assert pkt.rx_checksum == ~scapy.utils.checksum(bytes(pkt.data[14:])) & 0xffff
|
||||
assert Ether(pkt.data).build() == test_pkt.build()
|
||||
|
||||
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 tb.driver.interfaces[0].start_xmit(p, 0)
|
||||
|
||||
for k in range(count):
|
||||
await tb.driver.interfaces[0].wait()
|
||||
pkt = tb.driver.interfaces[0].recv()
|
||||
|
||||
tb.log.info("Packet: %s", pkt)
|
||||
assert pkt.data == pkts[k]
|
||||
assert pkt.rx_checksum == ~scapy.utils.checksum(bytes(pkt.data[14:])) & 0xffff
|
||||
|
||||
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 tb.driver.interfaces[0].start_xmit(p, 0)
|
||||
|
||||
for k in range(count):
|
||||
await tb.driver.interfaces[0].wait()
|
||||
pkt = tb.driver.interfaces[0].recv()
|
||||
|
||||
tb.log.info("Packet: %s", pkt)
|
||||
assert pkt.data == pkts[k]
|
||||
assert pkt.rx_checksum == ~scapy.utils.checksum(bytes(pkt.data[14:])) & 0xffff
|
||||
|
||||
tb.loopback_enable = False
|
||||
|
||||
tb.log.info("Jumbo frames")
|
||||
|
||||
count = 64
|
||||
|
||||
pkts = [bytearray([(x+k) % 256 for x in range(9014)]) for k in range(count)]
|
||||
|
||||
tb.loopback_enable = True
|
||||
|
||||
for p in pkts:
|
||||
await tb.driver.interfaces[0].start_xmit(p, 0)
|
||||
|
||||
for k in range(count):
|
||||
await tb.driver.interfaces[0].wait()
|
||||
pkt = tb.driver.interfaces[0].recv()
|
||||
|
||||
tb.log.info("Packet: %s", pkt)
|
||||
assert pkt.data == pkts[k]
|
||||
assert pkt.rx_checksum == ~scapy.utils.checksum(bytes(pkt.data[14:])) & 0xffff
|
||||
|
||||
tb.loopback_enable = False
|
||||
|
||||
await RisingEdge(dut.clk_250mhz)
|
||||
await RisingEdge(dut.clk_250mhz)
|
||||
|
||||
|
||||
# cocotb-test
|
||||
|
||||
tests_dir = os.path.dirname(__file__)
|
||||
rtl_dir = os.path.abspath(os.path.join(tests_dir, '..', '..', 'rtl'))
|
||||
lib_dir = os.path.abspath(os.path.join(rtl_dir, '..', 'lib'))
|
||||
axi_rtl_dir = os.path.abspath(os.path.join(lib_dir, 'axi', 'rtl'))
|
||||
axis_rtl_dir = os.path.abspath(os.path.join(lib_dir, 'axis', 'rtl'))
|
||||
eth_rtl_dir = os.path.abspath(os.path.join(lib_dir, 'eth', 'rtl'))
|
||||
pcie_rtl_dir = os.path.abspath(os.path.join(lib_dir, 'pcie', 'rtl'))
|
||||
|
||||
|
||||
def test_fpga_core(request):
|
||||
dut = "fpga_core"
|
||||
module = os.path.splitext(os.path.basename(__file__))[0]
|
||||
toplevel = dut
|
||||
|
||||
verilog_sources = [
|
||||
os.path.join(rtl_dir, f"{dut}.v"),
|
||||
os.path.join(rtl_dir, "common", "mqnic_interface.v"),
|
||||
os.path.join(rtl_dir, "common", "mqnic_port.v"),
|
||||
os.path.join(rtl_dir, "common", "cpl_write.v"),
|
||||
os.path.join(rtl_dir, "common", "cpl_op_mux.v"),
|
||||
os.path.join(rtl_dir, "common", "desc_fetch.v"),
|
||||
os.path.join(rtl_dir, "common", "desc_op_mux.v"),
|
||||
os.path.join(rtl_dir, "common", "queue_manager.v"),
|
||||
os.path.join(rtl_dir, "common", "cpl_queue_manager.v"),
|
||||
os.path.join(rtl_dir, "common", "tx_engine.v"),
|
||||
os.path.join(rtl_dir, "common", "rx_engine.v"),
|
||||
os.path.join(rtl_dir, "common", "tx_checksum.v"),
|
||||
os.path.join(rtl_dir, "common", "rx_hash.v"),
|
||||
os.path.join(rtl_dir, "common", "rx_checksum.v"),
|
||||
os.path.join(rtl_dir, "common", "tx_scheduler_rr.v"),
|
||||
os.path.join(rtl_dir, "common", "event_mux.v"),
|
||||
os.path.join(rtl_dir, "common", "tdma_scheduler.v"),
|
||||
os.path.join(rtl_dir, "common", "tdma_ber.v"),
|
||||
os.path.join(rtl_dir, "common", "tdma_ber_ch.v"),
|
||||
os.path.join(eth_rtl_dir, "ptp_clock.v"),
|
||||
os.path.join(eth_rtl_dir, "ptp_clock_cdc.v"),
|
||||
os.path.join(eth_rtl_dir, "ptp_perout.v"),
|
||||
os.path.join(eth_rtl_dir, "ptp_ts_extract.v"),
|
||||
os.path.join(axi_rtl_dir, "axil_interconnect.v"),
|
||||
os.path.join(axi_rtl_dir, "arbiter.v"),
|
||||
os.path.join(axi_rtl_dir, "priority_encoder.v"),
|
||||
os.path.join(axis_rtl_dir, "axis_adapter.v"),
|
||||
os.path.join(axis_rtl_dir, "axis_arb_mux.v"),
|
||||
os.path.join(axis_rtl_dir, "axis_async_fifo.v"),
|
||||
os.path.join(axis_rtl_dir, "axis_async_fifo_adapter.v"),
|
||||
os.path.join(axis_rtl_dir, "axis_fifo.v"),
|
||||
os.path.join(axis_rtl_dir, "axis_register.v"),
|
||||
os.path.join(pcie_rtl_dir, "pcie_us_axil_master.v"),
|
||||
os.path.join(pcie_rtl_dir, "dma_if_pcie_us.v"),
|
||||
os.path.join(pcie_rtl_dir, "dma_if_pcie_us_rd.v"),
|
||||
os.path.join(pcie_rtl_dir, "dma_if_pcie_us_wr.v"),
|
||||
os.path.join(pcie_rtl_dir, "dma_if_mux.v"),
|
||||
os.path.join(pcie_rtl_dir, "dma_if_mux_rd.v"),
|
||||
os.path.join(pcie_rtl_dir, "dma_if_mux_wr.v"),
|
||||
os.path.join(pcie_rtl_dir, "dma_psdpram.v"),
|
||||
os.path.join(pcie_rtl_dir, "dma_client_axis_sink.v"),
|
||||
os.path.join(pcie_rtl_dir, "dma_client_axis_source.v"),
|
||||
os.path.join(pcie_rtl_dir, "pcie_us_cfg.v"),
|
||||
os.path.join(pcie_rtl_dir, "pcie_us_msi.v"),
|
||||
os.path.join(pcie_rtl_dir, "pcie_tag_manager.v"),
|
||||
os.path.join(pcie_rtl_dir, "pulse_merge.v"),
|
||||
]
|
||||
|
||||
parameters = {}
|
||||
|
||||
parameters['AXIS_PCIE_DATA_WIDTH'] = 512
|
||||
parameters['AXIS_PCIE_KEEP_WIDTH'] = int(parameters['AXIS_PCIE_DATA_WIDTH']/32)
|
||||
parameters['AXIS_PCIE_RQ_USER_WIDTH'] = 62 if parameters['AXIS_PCIE_DATA_WIDTH'] < 512 else 137
|
||||
parameters['AXIS_PCIE_RC_USER_WIDTH'] = 75 if parameters['AXIS_PCIE_DATA_WIDTH'] < 512 else 161
|
||||
parameters['AXIS_PCIE_CQ_USER_WIDTH'] = 88 if parameters['AXIS_PCIE_DATA_WIDTH'] < 512 else 183
|
||||
parameters['AXIS_PCIE_CC_USER_WIDTH'] = 33 if parameters['AXIS_PCIE_DATA_WIDTH'] < 512 else 81
|
||||
parameters['RQ_SEQ_NUM_WIDTH'] = 6
|
||||
parameters['BAR0_APERTURE'] = 24
|
||||
parameters['AXIS_ETH_DATA_WIDTH'] = 512
|
||||
parameters['AXIS_ETH_KEEP_WIDTH'] = parameters['AXIS_ETH_DATA_WIDTH'] // 8
|
||||
|
||||
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(
|
||||
python_search=[tests_dir],
|
||||
verilog_sources=verilog_sources,
|
||||
toplevel=toplevel,
|
||||
module=module,
|
||||
parameters=parameters,
|
||||
sim_build=sim_build,
|
||||
extra_env=extra_env,
|
||||
)
|
@ -1 +0,0 @@
|
||||
../lib/eth/tb/ip_ep.py
|
@ -1 +0,0 @@
|
||||
../../../../common/tb/mqnic.py
|
@ -1 +0,0 @@
|
||||
../lib/pcie/tb/pcie.py
|
@ -1 +0,0 @@
|
||||
../lib/pcie/tb/pcie_us.py
|
@ -1 +0,0 @@
|
||||
../lib/pcie/tb/pcie_usp.py
|
@ -1,957 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
|
||||
Copyright 2019, The Regents of the University of California.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
|
||||
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of The Regents of the University of California.
|
||||
|
||||
"""
|
||||
|
||||
from myhdl import *
|
||||
import os
|
||||
|
||||
import pcie
|
||||
import pcie_usp
|
||||
import axis_ep
|
||||
import eth_ep
|
||||
import udp_ep
|
||||
|
||||
import struct
|
||||
|
||||
import mqnic
|
||||
|
||||
module = 'fpga_core'
|
||||
testbench = 'test_%s' % module
|
||||
|
||||
srcs = []
|
||||
|
||||
srcs.append("../rtl/%s.v" % module)
|
||||
srcs.append("../rtl/common/mqnic_interface.v")
|
||||
srcs.append("../rtl/common/mqnic_port.v")
|
||||
srcs.append("../rtl/common/cpl_write.v")
|
||||
srcs.append("../rtl/common/cpl_op_mux.v")
|
||||
srcs.append("../rtl/common/desc_fetch.v")
|
||||
srcs.append("../rtl/common/desc_op_mux.v")
|
||||
srcs.append("../rtl/common/queue_manager.v")
|
||||
srcs.append("../rtl/common/cpl_queue_manager.v")
|
||||
srcs.append("../rtl/common/tx_engine.v")
|
||||
srcs.append("../rtl/common/rx_engine.v")
|
||||
srcs.append("../rtl/common/tx_checksum.v")
|
||||
srcs.append("../rtl/common/rx_hash.v")
|
||||
srcs.append("../rtl/common/rx_checksum.v")
|
||||
srcs.append("../rtl/common/tx_scheduler_rr.v")
|
||||
srcs.append("../rtl/common/event_mux.v")
|
||||
srcs.append("../rtl/common/tdma_scheduler.v")
|
||||
srcs.append("../lib/eth/rtl/ptp_clock.v")
|
||||
srcs.append("../lib/eth/rtl/ptp_clock_cdc.v")
|
||||
srcs.append("../lib/eth/rtl/ptp_perout.v")
|
||||
srcs.append("../lib/eth/rtl/ptp_ts_extract.v")
|
||||
srcs.append("../lib/axi/rtl/axil_interconnect.v")
|
||||
srcs.append("../lib/axi/rtl/arbiter.v")
|
||||
srcs.append("../lib/axi/rtl/priority_encoder.v")
|
||||
srcs.append("../lib/axis/rtl/axis_adapter.v")
|
||||
srcs.append("../lib/axis/rtl/axis_async_fifo.v")
|
||||
srcs.append("../lib/axis/rtl/axis_fifo.v")
|
||||
srcs.append("../lib/axis/rtl/axis_register.v")
|
||||
srcs.append("../lib/pcie/rtl/pcie_us_axil_master.v")
|
||||
srcs.append("../lib/pcie/rtl/dma_if_pcie_us.v")
|
||||
srcs.append("../lib/pcie/rtl/dma_if_pcie_us_rd.v")
|
||||
srcs.append("../lib/pcie/rtl/dma_if_pcie_us_wr.v")
|
||||
srcs.append("../lib/pcie/rtl/dma_if_mux.v")
|
||||
srcs.append("../lib/pcie/rtl/dma_if_mux_rd.v")
|
||||
srcs.append("../lib/pcie/rtl/dma_if_mux_wr.v")
|
||||
srcs.append("../lib/pcie/rtl/dma_psdpram.v")
|
||||
srcs.append("../lib/pcie/rtl/dma_client_axis_sink.v")
|
||||
srcs.append("../lib/pcie/rtl/dma_client_axis_source.v")
|
||||
srcs.append("../lib/pcie/rtl/pcie_us_cfg.v")
|
||||
srcs.append("../lib/pcie/rtl/pcie_us_msi.v")
|
||||
srcs.append("../lib/pcie/rtl/pcie_tag_manager.v")
|
||||
srcs.append("../lib/pcie/rtl/pulse_merge.v")
|
||||
srcs.append("%s.v" % testbench)
|
||||
|
||||
src = ' '.join(srcs)
|
||||
|
||||
build_cmd = "iverilog -o %s.vvp %s" % (testbench, src)
|
||||
|
||||
def frame_checksum(frame):
|
||||
data = frame[14:]
|
||||
|
||||
csum = 0
|
||||
odd = False
|
||||
|
||||
for b in data:
|
||||
if odd:
|
||||
csum += b
|
||||
else:
|
||||
csum += b << 8
|
||||
odd = not odd
|
||||
|
||||
csum = (csum & 0xffff) + (csum >> 16)
|
||||
csum = (csum & 0xffff) + (csum >> 16)
|
||||
|
||||
return csum
|
||||
|
||||
def bench():
|
||||
|
||||
# Parameters
|
||||
AXIS_PCIE_DATA_WIDTH = 512
|
||||
AXIS_PCIE_KEEP_WIDTH = (AXIS_PCIE_DATA_WIDTH/32)
|
||||
AXIS_PCIE_RC_USER_WIDTH = 161
|
||||
AXIS_PCIE_RQ_USER_WIDTH = 137
|
||||
AXIS_PCIE_CQ_USER_WIDTH = 183
|
||||
AXIS_PCIE_CC_USER_WIDTH = 81
|
||||
RQ_SEQ_NUM_WIDTH = 6
|
||||
BAR0_APERTURE = 24
|
||||
AXIS_ETH_DATA_WIDTH = 512
|
||||
AXIS_ETH_KEEP_WIDTH = AXIS_ETH_DATA_WIDTH/8
|
||||
|
||||
# Inputs
|
||||
clk = Signal(bool(0))
|
||||
rst = Signal(bool(0))
|
||||
current_test = Signal(intbv(0)[8:])
|
||||
|
||||
clk_250mhz = Signal(bool(0))
|
||||
rst_250mhz = Signal(bool(0))
|
||||
user_sw = Signal(intbv(0)[2:])
|
||||
m_axis_rq_tready = Signal(bool(0))
|
||||
s_axis_rc_tdata = Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:])
|
||||
s_axis_rc_tkeep = Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:])
|
||||
s_axis_rc_tlast = Signal(bool(0))
|
||||
s_axis_rc_tuser = Signal(intbv(0)[AXIS_PCIE_RC_USER_WIDTH:])
|
||||
s_axis_rc_tvalid = Signal(bool(0))
|
||||
s_axis_cq_tdata = Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:])
|
||||
s_axis_cq_tkeep = Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:])
|
||||
s_axis_cq_tlast = Signal(bool(0))
|
||||
s_axis_cq_tuser = Signal(intbv(0)[AXIS_PCIE_CQ_USER_WIDTH:])
|
||||
s_axis_cq_tvalid = Signal(bool(0))
|
||||
m_axis_cc_tready = Signal(bool(0))
|
||||
s_axis_rq_seq_num_0 = Signal(intbv(0)[RQ_SEQ_NUM_WIDTH:])
|
||||
s_axis_rq_seq_num_valid_0 = Signal(bool(0))
|
||||
s_axis_rq_seq_num_1 = Signal(intbv(0)[RQ_SEQ_NUM_WIDTH:])
|
||||
s_axis_rq_seq_num_valid_1 = Signal(bool(0))
|
||||
pcie_tfc_nph_av = Signal(intbv(15)[4:])
|
||||
pcie_tfc_npd_av = Signal(intbv(15)[4:])
|
||||
cfg_max_payload = Signal(intbv(0)[2:])
|
||||
cfg_max_read_req = Signal(intbv(0)[3:])
|
||||
cfg_mgmt_read_data = Signal(intbv(0)[32:])
|
||||
cfg_mgmt_read_write_done = Signal(bool(0))
|
||||
cfg_fc_ph = Signal(intbv(0)[8:])
|
||||
cfg_fc_pd = Signal(intbv(0)[12:])
|
||||
cfg_fc_nph = Signal(intbv(0)[8:])
|
||||
cfg_fc_npd = Signal(intbv(0)[12:])
|
||||
cfg_fc_cplh = Signal(intbv(0)[8:])
|
||||
cfg_fc_cpld = Signal(intbv(0)[12:])
|
||||
cfg_interrupt_msi_enable = Signal(intbv(0)[4:])
|
||||
cfg_interrupt_msi_mmenable = Signal(intbv(0)[12:])
|
||||
cfg_interrupt_msi_mask_update = Signal(bool(0))
|
||||
cfg_interrupt_msi_data = Signal(intbv(0)[32:])
|
||||
cfg_interrupt_msi_sent = Signal(bool(0))
|
||||
cfg_interrupt_msi_fail = Signal(bool(0))
|
||||
qsfp_0_tx_clk = Signal(bool(0))
|
||||
qsfp_0_tx_rst = Signal(bool(0))
|
||||
qsfp_0_rx_clk = Signal(bool(0))
|
||||
qsfp_0_rx_rst = Signal(bool(0))
|
||||
qsfp_0_tx_axis_tready = Signal(bool(0))
|
||||
qsfp_0_rx_axis_tdata = Signal(intbv(0)[AXIS_ETH_DATA_WIDTH:])
|
||||
qsfp_0_rx_axis_tkeep = Signal(intbv(0)[AXIS_ETH_KEEP_WIDTH:])
|
||||
qsfp_0_rx_axis_tvalid = Signal(bool(0))
|
||||
qsfp_0_rx_axis_tlast = Signal(bool(0))
|
||||
qsfp_0_rx_axis_tuser = Signal(bool(0))
|
||||
qsfp_0_modprs_l = Signal(bool(0))
|
||||
qsfp_1_tx_clk = Signal(bool(0))
|
||||
qsfp_1_tx_rst = Signal(bool(0))
|
||||
qsfp_1_rx_clk = Signal(bool(0))
|
||||
qsfp_1_rx_rst = Signal(bool(0))
|
||||
qsfp_1_tx_axis_tready = Signal(bool(0))
|
||||
qsfp_1_rx_axis_tdata = Signal(intbv(0)[AXIS_ETH_DATA_WIDTH:])
|
||||
qsfp_1_rx_axis_tkeep = Signal(intbv(0)[AXIS_ETH_KEEP_WIDTH:])
|
||||
qsfp_1_rx_axis_tvalid = Signal(bool(0))
|
||||
qsfp_1_rx_axis_tlast = Signal(bool(0))
|
||||
qsfp_1_rx_axis_tuser = Signal(bool(0))
|
||||
qsfp_1_modprs_l = Signal(bool(0))
|
||||
qsfp_int_l = Signal(bool(0))
|
||||
qsfp_i2c_scl_i = Signal(bool(1))
|
||||
qsfp_i2c_sda_i = Signal(bool(1))
|
||||
eeprom_i2c_scl_i = Signal(bool(1))
|
||||
eeprom_i2c_sda_i = Signal(bool(1))
|
||||
qspi_0_dq_i = Signal(intbv(0)[4:])
|
||||
qspi_1_dq_i = Signal(intbv(0)[4:])
|
||||
|
||||
# Outputs
|
||||
user_led_g = Signal(intbv(0)[2:])
|
||||
user_led_r = Signal(bool(0))
|
||||
front_led = Signal(intbv(0)[2:])
|
||||
m_axis_rq_tdata = Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:])
|
||||
m_axis_rq_tkeep = Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:])
|
||||
m_axis_rq_tlast = Signal(bool(0))
|
||||
m_axis_rq_tuser = Signal(intbv(0)[AXIS_PCIE_RQ_USER_WIDTH:])
|
||||
m_axis_rq_tvalid = Signal(bool(0))
|
||||
s_axis_rc_tready = Signal(bool(0))
|
||||
s_axis_cq_tready = Signal(bool(0))
|
||||
m_axis_cc_tdata = Signal(intbv(0)[AXIS_PCIE_DATA_WIDTH:])
|
||||
m_axis_cc_tkeep = Signal(intbv(0)[AXIS_PCIE_KEEP_WIDTH:])
|
||||
m_axis_cc_tlast = Signal(bool(0))
|
||||
m_axis_cc_tuser = Signal(intbv(0)[AXIS_PCIE_CC_USER_WIDTH:])
|
||||
m_axis_cc_tvalid = Signal(bool(0))
|
||||
status_error_cor = Signal(bool(0))
|
||||
status_error_uncor = Signal(bool(0))
|
||||
cfg_mgmt_addr = Signal(intbv(0)[10:])
|
||||
cfg_mgmt_function_number = Signal(intbv(0)[8:])
|
||||
cfg_mgmt_write = Signal(bool(0))
|
||||
cfg_mgmt_write_data = Signal(intbv(0)[32:])
|
||||
cfg_mgmt_byte_enable = Signal(intbv(0)[4:])
|
||||
cfg_mgmt_read = Signal(bool(0))
|
||||
cfg_fc_sel = Signal(intbv(4)[3:])
|
||||
cfg_interrupt_msi_int = Signal(intbv(0)[32:])
|
||||
cfg_interrupt_msi_pending_status = Signal(intbv(0)[32:])
|
||||
cfg_interrupt_msi_select = Signal(intbv(0)[2:])
|
||||
cfg_interrupt_msi_pending_status_function_num = Signal(intbv(0)[2:])
|
||||
cfg_interrupt_msi_pending_status_data_enable = Signal(bool(0))
|
||||
cfg_interrupt_msi_attr = Signal(intbv(0)[3:])
|
||||
cfg_interrupt_msi_tph_present = Signal(bool(0))
|
||||
cfg_interrupt_msi_tph_type = Signal(intbv(0)[2:])
|
||||
cfg_interrupt_msi_tph_st_tag = Signal(intbv(0)[8:])
|
||||
cfg_interrupt_msi_function_number = Signal(intbv(0)[8:])
|
||||
qsfp_0_tx_axis_tdata = Signal(intbv(0)[AXIS_ETH_DATA_WIDTH:])
|
||||
qsfp_0_tx_axis_tkeep = Signal(intbv(0)[AXIS_ETH_KEEP_WIDTH:])
|
||||
qsfp_0_tx_axis_tvalid = Signal(bool(0))
|
||||
qsfp_0_tx_axis_tlast = Signal(bool(0))
|
||||
qsfp_0_tx_axis_tuser = Signal(bool(0))
|
||||
qsfp_0_sel_l = Signal(bool(1))
|
||||
qsfp_1_tx_axis_tdata = Signal(intbv(0)[AXIS_ETH_DATA_WIDTH:])
|
||||
qsfp_1_tx_axis_tkeep = Signal(intbv(0)[AXIS_ETH_KEEP_WIDTH:])
|
||||
qsfp_1_tx_axis_tvalid = Signal(bool(0))
|
||||
qsfp_1_tx_axis_tlast = Signal(bool(0))
|
||||
qsfp_1_tx_axis_tuser = Signal(bool(0))
|
||||
qsfp_1_sel_l = Signal(bool(1))
|
||||
qsfp_reset_l = Signal(bool(1))
|
||||
qsfp_i2c_scl_o = Signal(bool(1))
|
||||
qsfp_i2c_scl_t = Signal(bool(1))
|
||||
qsfp_i2c_sda_o = Signal(bool(1))
|
||||
qsfp_i2c_sda_t = Signal(bool(1))
|
||||
eeprom_i2c_scl_o = Signal(bool(1))
|
||||
eeprom_i2c_scl_t = Signal(bool(1))
|
||||
eeprom_i2c_sda_o = Signal(bool(1))
|
||||
eeprom_i2c_sda_t = Signal(bool(1))
|
||||
eeprom_wp = Signal(bool(1))
|
||||
fpga_boot = Signal(bool(0))
|
||||
qspi_clk = Signal(bool(0))
|
||||
qspi_0_dq_o = Signal(intbv(0)[4:])
|
||||
qspi_0_dq_oe = Signal(intbv(0)[4:])
|
||||
qspi_0_cs = Signal(bool(1))
|
||||
qspi_1_dq_o = Signal(intbv(0)[4:])
|
||||
qspi_1_dq_oe = Signal(intbv(0)[4:])
|
||||
qspi_1_cs = Signal(bool(1))
|
||||
|
||||
# sources and sinks
|
||||
qsfp_0_source = axis_ep.AXIStreamSource()
|
||||
qsfp_0_source_pause = Signal(bool(False))
|
||||
|
||||
qsfp_0_source_logic = qsfp_0_source.create_logic(
|
||||
qsfp_0_rx_clk,
|
||||
qsfp_0_rx_rst,
|
||||
tdata=qsfp_0_rx_axis_tdata,
|
||||
tkeep=qsfp_0_rx_axis_tkeep,
|
||||
tvalid=qsfp_0_rx_axis_tvalid,
|
||||
tlast=qsfp_0_rx_axis_tlast,
|
||||
tuser=qsfp_0_rx_axis_tuser,
|
||||
pause=qsfp_0_source_pause,
|
||||
name='qsfp_0_source'
|
||||
)
|
||||
|
||||
qsfp_0_sink = axis_ep.AXIStreamSink()
|
||||
qsfp_0_sink_pause = Signal(bool(False))
|
||||
|
||||
qsfp_0_sink_logic = qsfp_0_sink.create_logic(
|
||||
qsfp_0_tx_clk,
|
||||
qsfp_0_tx_rst,
|
||||
tdata=qsfp_0_tx_axis_tdata,
|
||||
tkeep=qsfp_0_tx_axis_tkeep,
|
||||
tvalid=qsfp_0_tx_axis_tvalid,
|
||||
tready=qsfp_0_tx_axis_tready,
|
||||
tlast=qsfp_0_tx_axis_tlast,
|
||||
tuser=qsfp_0_tx_axis_tuser,
|
||||
pause=qsfp_0_sink_pause,
|
||||
name='qsfp_0_sink'
|
||||
)
|
||||
|
||||
qsfp_1_source = axis_ep.AXIStreamSource()
|
||||
qsfp_1_source_pause = Signal(bool(False))
|
||||
|
||||
qsfp_1_source_logic = qsfp_1_source.create_logic(
|
||||
qsfp_1_rx_clk,
|
||||
qsfp_1_rx_rst,
|
||||
tdata=qsfp_1_rx_axis_tdata,
|
||||
tkeep=qsfp_1_rx_axis_tkeep,
|
||||
tvalid=qsfp_1_rx_axis_tvalid,
|
||||
tlast=qsfp_1_rx_axis_tlast,
|
||||
tuser=qsfp_1_rx_axis_tuser,
|
||||
pause=qsfp_1_source_pause,
|
||||
name='qsfp_1_source'
|
||||
)
|
||||
|
||||
qsfp_1_sink = axis_ep.AXIStreamSink()
|
||||
qsfp_1_sink_pause = Signal(bool(False))
|
||||
|
||||
qsfp_1_sink_logic = qsfp_1_sink.create_logic(
|
||||
qsfp_1_tx_clk,
|
||||
qsfp_1_tx_rst,
|
||||
tdata=qsfp_1_tx_axis_tdata,
|
||||
tkeep=qsfp_1_tx_axis_tkeep,
|
||||
tvalid=qsfp_1_tx_axis_tvalid,
|
||||
tready=qsfp_1_tx_axis_tready,
|
||||
tlast=qsfp_1_tx_axis_tlast,
|
||||
tuser=qsfp_1_tx_axis_tuser,
|
||||
pause=qsfp_1_sink_pause,
|
||||
name='qsfp_1_sink'
|
||||
)
|
||||
|
||||
# Clock and Reset Interface
|
||||
user_clk=Signal(bool(0))
|
||||
user_reset=Signal(bool(0))
|
||||
sys_clk=Signal(bool(0))
|
||||
sys_reset=Signal(bool(0))
|
||||
|
||||
# PCIe devices
|
||||
rc = pcie.RootComplex()
|
||||
|
||||
rc.max_payload_size = 0x1 # 256 bytes
|
||||
rc.max_read_request_size = 0x5 # 4096 bytes
|
||||
|
||||
driver = mqnic.Driver(rc)
|
||||
|
||||
dev = pcie_usp.UltrascalePlusPCIe()
|
||||
|
||||
dev.pcie_generation = 3
|
||||
dev.pcie_link_width = 16
|
||||
dev.user_clk_frequency = 250e6
|
||||
|
||||
dev.functions[0].msi_multiple_message_capable = 5
|
||||
|
||||
dev.functions[0].configure_bar(0, 2**BAR0_APERTURE, ext=True, prefetch=True)
|
||||
|
||||
rc.make_port().connect(dev)
|
||||
|
||||
cq_pause = Signal(bool(0))
|
||||
cc_pause = Signal(bool(0))
|
||||
rq_pause = Signal(bool(0))
|
||||
rc_pause = Signal(bool(0))
|
||||
|
||||
pcie_logic = dev.create_logic(
|
||||
# Completer reQuest Interface
|
||||
m_axis_cq_tdata=s_axis_cq_tdata,
|
||||
m_axis_cq_tuser=s_axis_cq_tuser,
|
||||
m_axis_cq_tlast=s_axis_cq_tlast,
|
||||
m_axis_cq_tkeep=s_axis_cq_tkeep,
|
||||
m_axis_cq_tvalid=s_axis_cq_tvalid,
|
||||
m_axis_cq_tready=s_axis_cq_tready,
|
||||
#pcie_cq_np_req=pcie_cq_np_req,
|
||||
pcie_cq_np_req=Signal(intbv(3)[2:]),
|
||||
#pcie_cq_np_req_count=pcie_cq_np_req_count,
|
||||
|
||||
# Completer Completion Interface
|
||||
s_axis_cc_tdata=m_axis_cc_tdata,
|
||||
s_axis_cc_tuser=m_axis_cc_tuser,
|
||||
s_axis_cc_tlast=m_axis_cc_tlast,
|
||||
s_axis_cc_tkeep=m_axis_cc_tkeep,
|
||||
s_axis_cc_tvalid=m_axis_cc_tvalid,
|
||||
s_axis_cc_tready=m_axis_cc_tready,
|
||||
|
||||
# Requester reQuest Interface
|
||||
s_axis_rq_tdata=m_axis_rq_tdata,
|
||||
s_axis_rq_tuser=m_axis_rq_tuser,
|
||||
s_axis_rq_tlast=m_axis_rq_tlast,
|
||||
s_axis_rq_tkeep=m_axis_rq_tkeep,
|
||||
s_axis_rq_tvalid=m_axis_rq_tvalid,
|
||||
s_axis_rq_tready=m_axis_rq_tready,
|
||||
pcie_rq_seq_num0=s_axis_rq_seq_num_0,
|
||||
pcie_rq_seq_num_vld0=s_axis_rq_seq_num_valid_0,
|
||||
pcie_rq_seq_num1=s_axis_rq_seq_num_1,
|
||||
pcie_rq_seq_num_vld1=s_axis_rq_seq_num_valid_1,
|
||||
#pcie_rq_tag0=pcie_rq_tag0,
|
||||
#pcie_rq_tag1=pcie_rq_tag1,
|
||||
#pcie_rq_tag_av=pcie_rq_tag_av,
|
||||
#pcie_rq_tag_vld0=pcie_rq_tag_vld0,
|
||||
#pcie_rq_tag_vld1=pcie_rq_tag_vld1,
|
||||
|
||||
# Requester Completion Interface
|
||||
m_axis_rc_tdata=s_axis_rc_tdata,
|
||||
m_axis_rc_tuser=s_axis_rc_tuser,
|
||||
m_axis_rc_tlast=s_axis_rc_tlast,
|
||||
m_axis_rc_tkeep=s_axis_rc_tkeep,
|
||||
m_axis_rc_tvalid=s_axis_rc_tvalid,
|
||||
m_axis_rc_tready=s_axis_rc_tready,
|
||||
|
||||
# Transmit Flow Control Interface
|
||||
#pcie_tfc_nph_av=pcie_tfc_nph_av,
|
||||
#pcie_tfc_npd_av=pcie_tfc_npd_av,
|
||||
|
||||
# Configuration Management Interface
|
||||
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_mgmt_debug_access=cfg_mgmt_debug_access,
|
||||
|
||||
# Configuration Status Interface
|
||||
#cfg_phy_link_down=cfg_phy_link_down,
|
||||
#cfg_phy_link_status=cfg_phy_link_status,
|
||||
#cfg_negotiated_width=cfg_negotiated_width,
|
||||
#cfg_current_speed=cfg_current_speed,
|
||||
cfg_max_payload=cfg_max_payload,
|
||||
cfg_max_read_req=cfg_max_read_req,
|
||||
#cfg_function_status=cfg_function_status,
|
||||
#cfg_vf_status=cfg_vf_status,
|
||||
#cfg_function_power_state=cfg_function_power_state,
|
||||
#cfg_vf_power_state=cfg_vf_power_state,
|
||||
#cfg_link_power_state=cfg_link_power_state,
|
||||
#cfg_err_cor_out=cfg_err_cor_out,
|
||||
#cfg_err_nonfatal_out=cfg_err_nonfatal_out,
|
||||
#cfg_err_fatal_out=cfg_err_fatal_out,
|
||||
#cfg_local_err_out=cfg_local_err_out,
|
||||
#cfg_local_err_valid=cfg_local_err_valid,
|
||||
#cfg_rx_pm_state=cfg_rx_pm_state,
|
||||
#cfg_tx_pm_state=cfg_tx_pm_state,
|
||||
#cfg_ltssm_state=cfg_ltssm_state,
|
||||
#cfg_rcb_status=cfg_rcb_status,
|
||||
#cfg_obff_enable=cfg_obff_enable,
|
||||
#cfg_pl_status_change=cfg_pl_status_change,
|
||||
#cfg_tph_requester_enable=cfg_tph_requester_enable,
|
||||
#cfg_tph_st_mode=cfg_tph_st_mode,
|
||||
#cfg_vf_tph_requester_enable=cfg_vf_tph_requester_enable,
|
||||
#cfg_vf_tph_st_mode=cfg_vf_tph_st_mode,
|
||||
|
||||
# Configuration Received Message Interface
|
||||
#cfg_msg_received=cfg_msg_received,
|
||||
#cfg_msg_received_data=cfg_msg_received_data,
|
||||
#cfg_msg_received_type=cfg_msg_received_type,
|
||||
|
||||
# Configuration Transmit Message Interface
|
||||
#cfg_msg_transmit=cfg_msg_transmit,
|
||||
#cfg_msg_transmit_type=cfg_msg_transmit_type,
|
||||
#cfg_msg_transmit_data=cfg_msg_transmit_data,
|
||||
#cfg_msg_transmit_done=cfg_msg_transmit_done,
|
||||
|
||||
# Configuration Flow Control Interface
|
||||
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,
|
||||
|
||||
# Configuration Control Interface
|
||||
#cfg_hot_reset_in=cfg_hot_reset_in,
|
||||
#cfg_hot_reset_out=cfg_hot_reset_out,
|
||||
#cfg_config_space_enable=cfg_config_space_enable,
|
||||
#cfg_dsn=cfg_dsn,
|
||||
#cfg_ds_port_number=cfg_ds_port_number,
|
||||
#cfg_ds_bus_number=cfg_ds_bus_number,
|
||||
#cfg_ds_device_number=cfg_ds_device_number,
|
||||
#cfg_ds_function_number=cfg_ds_function_number,
|
||||
#cfg_power_state_change_ack=cfg_power_state_change_ack,
|
||||
#cfg_power_state_change_interrupt=cfg_power_state_change_interrupt,
|
||||
cfg_err_cor_in=status_error_cor,
|
||||
cfg_err_uncor_in=status_error_uncor,
|
||||
#cfg_flr_done=cfg_flr_done,
|
||||
#cfg_vf_flr_done=cfg_vf_flr_done,
|
||||
#cfg_flr_in_process=cfg_flr_in_process,
|
||||
#cfg_vf_flr_in_process=cfg_vf_flr_in_process,
|
||||
#cfg_req_pm_transition_l23_ready=cfg_req_pm_transition_l23_ready,
|
||||
#cfg_link_training_enable=cfg_link_training_enable,
|
||||
|
||||
# Configuration Interrupt Controller Interface
|
||||
#cfg_interrupt_int=cfg_interrupt_int,
|
||||
#cfg_interrupt_sent=cfg_interrupt_sent,
|
||||
#cfg_interrupt_pending=cfg_interrupt_pending,
|
||||
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_msix_enable=cfg_interrupt_msix_enable,
|
||||
#cfg_interrupt_msix_mask=cfg_interrupt_msix_mask,
|
||||
#cfg_interrupt_msix_vf_enable=cfg_interrupt_msix_vf_enable,
|
||||
#cfg_interrupt_msix_vf_mask=cfg_interrupt_msix_vf_mask,
|
||||
#cfg_interrupt_msix_address=cfg_interrupt_msix_address,
|
||||
#cfg_interrupt_msix_data=cfg_interrupt_msix_data,
|
||||
#cfg_interrupt_msix_int=cfg_interrupt_msix_int,
|
||||
#cfg_interrupt_msix_vec_pending=cfg_interrupt_msix_vec_pending,
|
||||
#cfg_interrupt_msix_vec_pending_status=cfg_interrupt_msix_vec_pending_status,
|
||||
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,
|
||||
|
||||
# Configuration Extend Interface
|
||||
#cfg_ext_read_received=cfg_ext_read_received,
|
||||
#cfg_ext_write_received=cfg_ext_write_received,
|
||||
#cfg_ext_register_number=cfg_ext_register_number,
|
||||
#cfg_ext_function_number=cfg_ext_function_number,
|
||||
#cfg_ext_write_data=cfg_ext_write_data,
|
||||
#cfg_ext_write_byte_enable=cfg_ext_write_byte_enable,
|
||||
#cfg_ext_read_data=cfg_ext_read_data,
|
||||
#cfg_ext_read_data_valid=cfg_ext_read_data_valid,
|
||||
|
||||
# Clock and Reset Interface
|
||||
user_clk=user_clk,
|
||||
user_reset=user_reset,
|
||||
sys_clk=sys_clk,
|
||||
sys_clk_gt=sys_clk,
|
||||
sys_reset=sys_reset,
|
||||
#phy_rdy_out=phy_rdy_out,
|
||||
|
||||
cq_pause=cq_pause,
|
||||
cc_pause=cc_pause,
|
||||
rq_pause=rq_pause,
|
||||
rc_pause=rc_pause
|
||||
)
|
||||
|
||||
# DUT
|
||||
if os.system(build_cmd):
|
||||
raise Exception("Error running build command")
|
||||
|
||||
dut = Cosimulation(
|
||||
"vvp -m myhdl %s.vvp -lxt2" % testbench,
|
||||
clk=clk,
|
||||
rst=rst,
|
||||
current_test=current_test,
|
||||
clk_250mhz=user_clk,
|
||||
rst_250mhz=user_reset,
|
||||
user_led_g=user_led_g,
|
||||
user_led_r=user_led_r,
|
||||
front_led=front_led,
|
||||
user_sw=user_sw,
|
||||
m_axis_rq_tdata=m_axis_rq_tdata,
|
||||
m_axis_rq_tkeep=m_axis_rq_tkeep,
|
||||
m_axis_rq_tlast=m_axis_rq_tlast,
|
||||
m_axis_rq_tready=m_axis_rq_tready,
|
||||
m_axis_rq_tuser=m_axis_rq_tuser,
|
||||
m_axis_rq_tvalid=m_axis_rq_tvalid,
|
||||
s_axis_rc_tdata=s_axis_rc_tdata,
|
||||
s_axis_rc_tkeep=s_axis_rc_tkeep,
|
||||
s_axis_rc_tlast=s_axis_rc_tlast,
|
||||
s_axis_rc_tready=s_axis_rc_tready,
|
||||
s_axis_rc_tuser=s_axis_rc_tuser,
|
||||
s_axis_rc_tvalid=s_axis_rc_tvalid,
|
||||
s_axis_cq_tdata=s_axis_cq_tdata,
|
||||
s_axis_cq_tkeep=s_axis_cq_tkeep,
|
||||
s_axis_cq_tlast=s_axis_cq_tlast,
|
||||
s_axis_cq_tready=s_axis_cq_tready,
|
||||
s_axis_cq_tuser=s_axis_cq_tuser,
|
||||
s_axis_cq_tvalid=s_axis_cq_tvalid,
|
||||
m_axis_cc_tdata=m_axis_cc_tdata,
|
||||
m_axis_cc_tkeep=m_axis_cc_tkeep,
|
||||
m_axis_cc_tlast=m_axis_cc_tlast,
|
||||
m_axis_cc_tready=m_axis_cc_tready,
|
||||
m_axis_cc_tuser=m_axis_cc_tuser,
|
||||
m_axis_cc_tvalid=m_axis_cc_tvalid,
|
||||
s_axis_rq_seq_num_0=s_axis_rq_seq_num_0,
|
||||
s_axis_rq_seq_num_valid_0=s_axis_rq_seq_num_valid_0,
|
||||
s_axis_rq_seq_num_1=s_axis_rq_seq_num_1,
|
||||
s_axis_rq_seq_num_valid_1=s_axis_rq_seq_num_valid_1,
|
||||
pcie_tfc_nph_av=pcie_tfc_nph_av,
|
||||
pcie_tfc_npd_av=pcie_tfc_npd_av,
|
||||
cfg_max_payload=cfg_max_payload,
|
||||
cfg_max_read_req=cfg_max_read_req,
|
||||
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_int=cfg_interrupt_msi_int,
|
||||
cfg_interrupt_msi_sent=cfg_interrupt_msi_sent,
|
||||
cfg_interrupt_msi_fail=cfg_interrupt_msi_fail,
|
||||
cfg_interrupt_msi_mmenable=cfg_interrupt_msi_mmenable,
|
||||
cfg_interrupt_msi_pending_status=cfg_interrupt_msi_pending_status,
|
||||
cfg_interrupt_msi_mask_update=cfg_interrupt_msi_mask_update,
|
||||
cfg_interrupt_msi_select=cfg_interrupt_msi_select,
|
||||
cfg_interrupt_msi_data=cfg_interrupt_msi_data,
|
||||
cfg_interrupt_msi_pending_status_function_num=cfg_interrupt_msi_pending_status_function_num,
|
||||
cfg_interrupt_msi_pending_status_data_enable=cfg_interrupt_msi_pending_status_data_enable,
|
||||
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,
|
||||
status_error_cor=status_error_cor,
|
||||
status_error_uncor=status_error_uncor,
|
||||
qsfp_0_tx_clk=qsfp_0_tx_clk,
|
||||
qsfp_0_tx_rst=qsfp_0_tx_rst,
|
||||
qsfp_0_tx_axis_tdata=qsfp_0_tx_axis_tdata,
|
||||
qsfp_0_tx_axis_tkeep=qsfp_0_tx_axis_tkeep,
|
||||
qsfp_0_tx_axis_tvalid=qsfp_0_tx_axis_tvalid,
|
||||
qsfp_0_tx_axis_tready=qsfp_0_tx_axis_tready,
|
||||
qsfp_0_tx_axis_tlast=qsfp_0_tx_axis_tlast,
|
||||
qsfp_0_tx_axis_tuser=qsfp_0_tx_axis_tuser,
|
||||
qsfp_0_rx_clk=qsfp_0_rx_clk,
|
||||
qsfp_0_rx_rst=qsfp_0_rx_rst,
|
||||
qsfp_0_rx_axis_tdata=qsfp_0_rx_axis_tdata,
|
||||
qsfp_0_rx_axis_tkeep=qsfp_0_rx_axis_tkeep,
|
||||
qsfp_0_rx_axis_tvalid=qsfp_0_rx_axis_tvalid,
|
||||
qsfp_0_rx_axis_tlast=qsfp_0_rx_axis_tlast,
|
||||
qsfp_0_rx_axis_tuser=qsfp_0_rx_axis_tuser,
|
||||
qsfp_0_modprs_l=qsfp_0_modprs_l,
|
||||
qsfp_0_sel_l=qsfp_0_sel_l,
|
||||
qsfp_1_tx_clk=qsfp_1_tx_clk,
|
||||
qsfp_1_tx_rst=qsfp_1_tx_rst,
|
||||
qsfp_1_tx_axis_tdata=qsfp_1_tx_axis_tdata,
|
||||
qsfp_1_tx_axis_tkeep=qsfp_1_tx_axis_tkeep,
|
||||
qsfp_1_tx_axis_tvalid=qsfp_1_tx_axis_tvalid,
|
||||
qsfp_1_tx_axis_tready=qsfp_1_tx_axis_tready,
|
||||
qsfp_1_tx_axis_tlast=qsfp_1_tx_axis_tlast,
|
||||
qsfp_1_tx_axis_tuser=qsfp_1_tx_axis_tuser,
|
||||
qsfp_1_rx_clk=qsfp_1_rx_clk,
|
||||
qsfp_1_rx_rst=qsfp_1_rx_rst,
|
||||
qsfp_1_rx_axis_tdata=qsfp_1_rx_axis_tdata,
|
||||
qsfp_1_rx_axis_tkeep=qsfp_1_rx_axis_tkeep,
|
||||
qsfp_1_rx_axis_tvalid=qsfp_1_rx_axis_tvalid,
|
||||
qsfp_1_rx_axis_tlast=qsfp_1_rx_axis_tlast,
|
||||
qsfp_1_rx_axis_tuser=qsfp_1_rx_axis_tuser,
|
||||
qsfp_1_modprs_l=qsfp_1_modprs_l,
|
||||
qsfp_1_sel_l=qsfp_1_sel_l,
|
||||
qsfp_reset_l=qsfp_reset_l,
|
||||
qsfp_int_l=qsfp_int_l,
|
||||
qsfp_i2c_scl_i=qsfp_i2c_scl_i,
|
||||
qsfp_i2c_scl_o=qsfp_i2c_scl_o,
|
||||
qsfp_i2c_scl_t=qsfp_i2c_scl_t,
|
||||
qsfp_i2c_sda_i=qsfp_i2c_sda_i,
|
||||
qsfp_i2c_sda_o=qsfp_i2c_sda_o,
|
||||
qsfp_i2c_sda_t=qsfp_i2c_sda_t,
|
||||
eeprom_i2c_scl_i=eeprom_i2c_scl_i,
|
||||
eeprom_i2c_scl_o=eeprom_i2c_scl_o,
|
||||
eeprom_i2c_scl_t=eeprom_i2c_scl_t,
|
||||
eeprom_i2c_sda_i=eeprom_i2c_sda_i,
|
||||
eeprom_i2c_sda_o=eeprom_i2c_sda_o,
|
||||
eeprom_i2c_sda_t=eeprom_i2c_sda_t,
|
||||
eeprom_wp=eeprom_wp,
|
||||
fpga_boot=fpga_boot,
|
||||
qspi_clk=qspi_clk,
|
||||
qspi_0_dq_i=qspi_0_dq_i,
|
||||
qspi_0_dq_o=qspi_0_dq_o,
|
||||
qspi_0_dq_oe=qspi_0_dq_oe,
|
||||
qspi_0_cs=qspi_0_cs,
|
||||
qspi_1_dq_i=qspi_1_dq_i,
|
||||
qspi_1_dq_o=qspi_1_dq_o,
|
||||
qspi_1_dq_oe=qspi_1_dq_oe,
|
||||
qspi_1_cs=qspi_1_cs
|
||||
)
|
||||
|
||||
@always(delay(5))
|
||||
def clkgen():
|
||||
clk.next = not clk
|
||||
|
||||
@always(delay(2))
|
||||
def qsfp_clkgen():
|
||||
qsfp_0_tx_clk.next = not qsfp_0_tx_clk
|
||||
qsfp_0_rx_clk.next = not qsfp_0_rx_clk
|
||||
qsfp_1_tx_clk.next = not qsfp_1_tx_clk
|
||||
qsfp_1_rx_clk.next = not qsfp_1_rx_clk
|
||||
|
||||
@always_comb
|
||||
def clk_logic():
|
||||
sys_clk.next = clk
|
||||
sys_reset.next = not rst
|
||||
|
||||
loopback_enable = Signal(bool(0))
|
||||
|
||||
@instance
|
||||
def loopback():
|
||||
while True:
|
||||
|
||||
yield clk.posedge
|
||||
|
||||
if loopback_enable:
|
||||
if not qsfp_0_sink.empty():
|
||||
pkt = qsfp_0_sink.recv()
|
||||
qsfp_0_source.send(pkt)
|
||||
if not qsfp_1_sink.empty():
|
||||
pkt = qsfp_1_sink.recv()
|
||||
qsfp_1_source.send(pkt)
|
||||
|
||||
@instance
|
||||
def check():
|
||||
yield delay(100)
|
||||
yield clk.posedge
|
||||
rst.next = 1
|
||||
qsfp_0_tx_rst.next = 1
|
||||
qsfp_0_rx_rst.next = 1
|
||||
qsfp_1_tx_rst.next = 1
|
||||
qsfp_1_rx_rst.next = 1
|
||||
yield clk.posedge
|
||||
yield delay(100)
|
||||
rst.next = 0
|
||||
qsfp_0_tx_rst.next = 0
|
||||
qsfp_0_rx_rst.next = 0
|
||||
qsfp_1_tx_rst.next = 0
|
||||
qsfp_1_rx_rst.next = 0
|
||||
yield clk.posedge
|
||||
yield delay(100)
|
||||
yield clk.posedge
|
||||
|
||||
# testbench stimulus
|
||||
|
||||
current_tag = 1
|
||||
|
||||
yield clk.posedge
|
||||
print("test 1: enumeration")
|
||||
current_test.next = 1
|
||||
|
||||
yield rc.enumerate(enable_bus_mastering=True, configure_msi=True)
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 2: init NIC")
|
||||
current_test.next = 2
|
||||
|
||||
yield from driver.init_dev(dev.functions[0].get_id())
|
||||
yield from driver.interfaces[0].open()
|
||||
#yield from driver.interfaces[1].open()
|
||||
|
||||
# enable queues
|
||||
yield from rc.mem_write_dword(driver.interfaces[0].ports[0].hw_addr+mqnic.MQNIC_PORT_REG_SCHED_ENABLE, 0x00000001)
|
||||
for k in range(driver.interfaces[0].tx_queue_count):
|
||||
yield from rc.mem_write_dword(driver.interfaces[0].ports[0].schedulers[0].hw_addr+4*k, 0x00000003)
|
||||
|
||||
yield from rc.mem_read(driver.hw_addr, 4) # wait for all writes to complete
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 3: send and receive a packet")
|
||||
current_test.next = 3
|
||||
|
||||
# test bad packet
|
||||
#qsfp_0_source.send(b'\x55\x55\x55\x55\x55\xd5'+bytearray(range(128)))
|
||||
|
||||
data = bytearray([x%256 for x in range(1024)])
|
||||
|
||||
yield from driver.interfaces[0].start_xmit(data, 0)
|
||||
|
||||
yield qsfp_0_sink.wait()
|
||||
|
||||
pkt = qsfp_0_sink.recv()
|
||||
print(pkt)
|
||||
|
||||
qsfp_0_source.send(pkt)
|
||||
|
||||
yield driver.interfaces[0].wait()
|
||||
|
||||
pkt = driver.interfaces[0].recv()
|
||||
|
||||
print(pkt)
|
||||
assert frame_checksum(pkt.data) == pkt.rx_checksum
|
||||
|
||||
# yield from driver.interfaces[1].start_xmit(data, 0)
|
||||
|
||||
# yield qsfp_1_sink.wait()
|
||||
|
||||
# pkt = qsfp_1_sink.recv()
|
||||
# print(pkt)
|
||||
|
||||
# qsfp_1_source.send(pkt)
|
||||
|
||||
# yield driver.interfaces[1].wait()
|
||||
|
||||
# pkt = driver.interfaces[1].recv()
|
||||
|
||||
# print(pkt)
|
||||
# assert frame_checksum(pkt.data) == pkt.rx_checksum
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 4: checksum tests")
|
||||
current_test.next = 4
|
||||
|
||||
test_frame = udp_ep.UDPFrame()
|
||||
test_frame.eth_dest_mac = 0xDAD1D2D3D4D5
|
||||
test_frame.eth_src_mac = 0x5A5152535455
|
||||
test_frame.eth_type = 0x0800
|
||||
test_frame.ip_version = 4
|
||||
test_frame.ip_ihl = 5
|
||||
test_frame.ip_length = None
|
||||
test_frame.ip_identification = 0
|
||||
test_frame.ip_flags = 2
|
||||
test_frame.ip_fragment_offset = 0
|
||||
test_frame.ip_ttl = 64
|
||||
test_frame.ip_protocol = 0x11
|
||||
test_frame.ip_header_checksum = None
|
||||
test_frame.ip_source_ip = 0xc0a80164
|
||||
test_frame.ip_dest_ip = 0xc0a80165
|
||||
test_frame.udp_source_port = 1
|
||||
test_frame.udp_dest_port = 2
|
||||
test_frame.udp_length = None
|
||||
test_frame.udp_checksum = None
|
||||
test_frame.payload = bytearray((x%256 for x in range(256)))
|
||||
|
||||
test_frame.set_udp_pseudo_header_checksum()
|
||||
|
||||
axis_frame = test_frame.build_axis()
|
||||
|
||||
yield from driver.interfaces[0].start_xmit(axis_frame.data, 0, 34, 6)
|
||||
|
||||
yield qsfp_0_sink.wait()
|
||||
|
||||
pkt = qsfp_0_sink.recv()
|
||||
print(pkt)
|
||||
|
||||
qsfp_0_source.send(pkt)
|
||||
|
||||
yield driver.interfaces[0].wait()
|
||||
|
||||
pkt = driver.interfaces[0].recv()
|
||||
|
||||
print(pkt)
|
||||
|
||||
assert pkt.rx_checksum == frame_checksum(pkt.data)
|
||||
|
||||
check_frame = udp_ep.UDPFrame()
|
||||
check_frame.parse_axis(pkt.data)
|
||||
|
||||
assert check_frame.verify_checksums()
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 5: multiple small packets")
|
||||
current_test.next = 5
|
||||
|
||||
count = 64
|
||||
|
||||
pkts = [bytearray([(x+k)%256 for x in range(64)]) for k in range(count)]
|
||||
|
||||
loopback_enable.next = True
|
||||
|
||||
for p in pkts:
|
||||
yield from driver.interfaces[0].start_xmit(p, 0)
|
||||
|
||||
for k in range(count):
|
||||
pkt = driver.interfaces[0].recv()
|
||||
|
||||
if not pkt:
|
||||
yield driver.interfaces[0].wait()
|
||||
pkt = driver.interfaces[0].recv()
|
||||
|
||||
print(pkt)
|
||||
assert pkt.data == pkts[k]
|
||||
assert frame_checksum(pkt.data) == pkt.rx_checksum
|
||||
|
||||
loopback_enable.next = False
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 6: multiple large packets")
|
||||
current_test.next = 6
|
||||
|
||||
count = 64
|
||||
|
||||
pkts = [bytearray([(x+k)%256 for x in range(1514)]) for k in range(count)]
|
||||
|
||||
loopback_enable.next = True
|
||||
|
||||
for p in pkts:
|
||||
yield from driver.interfaces[0].start_xmit(p, 0)
|
||||
|
||||
for k in range(count):
|
||||
pkt = driver.interfaces[0].recv()
|
||||
|
||||
if not pkt:
|
||||
yield driver.interfaces[0].wait()
|
||||
pkt = driver.interfaces[0].recv()
|
||||
|
||||
print(pkt)
|
||||
assert pkt.data == pkts[k]
|
||||
assert frame_checksum(pkt.data) == pkt.rx_checksum
|
||||
|
||||
loopback_enable.next = False
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 7: jumbo frames")
|
||||
current_test.next = 7
|
||||
|
||||
count = 64
|
||||
|
||||
pkts = [bytearray([(x+k)%256 for x in range(9014)]) for k in range(count)]
|
||||
|
||||
loopback_enable.next = True
|
||||
|
||||
for p in pkts:
|
||||
yield from driver.interfaces[0].start_xmit(p, 0)
|
||||
|
||||
for k in range(count):
|
||||
pkt = driver.interfaces[0].recv()
|
||||
|
||||
if not pkt:
|
||||
yield driver.interfaces[0].wait()
|
||||
pkt = driver.interfaces[0].recv()
|
||||
|
||||
print(pkt)
|
||||
assert pkt.data == pkts[k]
|
||||
assert frame_checksum(pkt.data) == pkt.rx_checksum
|
||||
|
||||
loopback_enable.next = False
|
||||
|
||||
raise StopSimulation
|
||||
|
||||
return instances()
|
||||
|
||||
def test_bench():
|
||||
sim = Simulation(bench())
|
||||
sim.run()
|
||||
|
||||
if __name__ == '__main__':
|
||||
print("Running test...")
|
||||
test_bench()
|
@ -1,481 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright 2019, The Regents of the University of California.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
|
||||
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of The Regents of the University of California.
|
||||
|
||||
*/
|
||||
|
||||
// Language: Verilog 2001
|
||||
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
/*
|
||||
* Testbench for fpga_core
|
||||
*/
|
||||
module test_fpga_core;
|
||||
|
||||
// Parameters
|
||||
parameter AXIS_PCIE_DATA_WIDTH = 512;
|
||||
parameter AXIS_PCIE_KEEP_WIDTH = (AXIS_PCIE_DATA_WIDTH/32);
|
||||
parameter AXIS_PCIE_RC_USER_WIDTH = 161;
|
||||
parameter AXIS_PCIE_RQ_USER_WIDTH = 137;
|
||||
parameter AXIS_PCIE_CQ_USER_WIDTH = 183;
|
||||
parameter AXIS_PCIE_CC_USER_WIDTH = 81;
|
||||
parameter RQ_SEQ_NUM_WIDTH = 6;
|
||||
parameter BAR0_APERTURE = 24;
|
||||
parameter AXIS_ETH_DATA_WIDTH = 512;
|
||||
parameter AXIS_ETH_KEEP_WIDTH = AXIS_ETH_DATA_WIDTH/8;
|
||||
|
||||
// Inputs
|
||||
reg clk = 0;
|
||||
reg rst = 0;
|
||||
reg [7:0] current_test = 0;
|
||||
|
||||
reg clk_250mhz = 0;
|
||||
reg rst_250mhz = 0;
|
||||
reg [1:0] user_sw = 0;
|
||||
reg m_axis_rq_tready = 0;
|
||||
reg [AXIS_PCIE_DATA_WIDTH-1:0] s_axis_rc_tdata = 0;
|
||||
reg [AXIS_PCIE_KEEP_WIDTH-1:0] s_axis_rc_tkeep = 0;
|
||||
reg s_axis_rc_tlast = 0;
|
||||
reg [AXIS_PCIE_RC_USER_WIDTH-1:0] s_axis_rc_tuser = 0;
|
||||
reg s_axis_rc_tvalid = 0;
|
||||
reg [AXIS_PCIE_DATA_WIDTH-1:0] s_axis_cq_tdata = 0;
|
||||
reg [AXIS_PCIE_KEEP_WIDTH-1:0] s_axis_cq_tkeep = 0;
|
||||
reg s_axis_cq_tlast = 0;
|
||||
reg [AXIS_PCIE_CQ_USER_WIDTH-1:0] s_axis_cq_tuser = 0;
|
||||
reg s_axis_cq_tvalid = 0;
|
||||
reg m_axis_cc_tready = 0;
|
||||
reg [RQ_SEQ_NUM_WIDTH-1:0] s_axis_rq_seq_num_0 = 0;
|
||||
reg s_axis_rq_seq_num_valid_0 = 0;
|
||||
reg [RQ_SEQ_NUM_WIDTH-1:0] s_axis_rq_seq_num_1 = 0;
|
||||
reg s_axis_rq_seq_num_valid_1 = 0;
|
||||
reg [3:0] pcie_tfc_nph_av = 0;
|
||||
reg [3:0] pcie_tfc_npd_av = 0;
|
||||
reg [2:0] cfg_max_payload = 0;
|
||||
reg [2:0] cfg_max_read_req = 0;
|
||||
reg [31:0] cfg_mgmt_read_data = 0;
|
||||
reg cfg_mgmt_read_write_done = 0;
|
||||
reg [7:0] cfg_fc_ph = 0;
|
||||
reg [11:0] cfg_fc_pd = 0;
|
||||
reg [7:0] cfg_fc_nph = 0;
|
||||
reg [11:0] cfg_fc_npd = 0;
|
||||
reg [7:0] cfg_fc_cplh = 0;
|
||||
reg [11:0] cfg_fc_cpld = 0;
|
||||
reg [3:0] cfg_interrupt_msi_enable = 0;
|
||||
reg [11:0] cfg_interrupt_msi_mmenable = 0;
|
||||
reg cfg_interrupt_msi_mask_update = 0;
|
||||
reg [31:0] cfg_interrupt_msi_data = 0;
|
||||
reg cfg_interrupt_msi_sent = 0;
|
||||
reg cfg_interrupt_msi_fail = 0;
|
||||
reg qsfp_0_tx_clk = 0;
|
||||
reg qsfp_0_tx_rst = 0;
|
||||
reg qsfp_0_tx_axis_tready = 0;
|
||||
reg qsfp_0_rx_clk = 0;
|
||||
reg qsfp_0_rx_rst = 0;
|
||||
reg [AXIS_ETH_DATA_WIDTH-1:0] qsfp_0_rx_axis_tdata = 0;
|
||||
reg [AXIS_ETH_KEEP_WIDTH-1:0] qsfp_0_rx_axis_tkeep = 0;
|
||||
reg qsfp_0_rx_axis_tvalid = 0;
|
||||
reg qsfp_0_rx_axis_tlast = 0;
|
||||
reg qsfp_0_rx_axis_tuser = 0;
|
||||
reg qsfp_0_modprs_l = 0;
|
||||
reg qsfp_1_tx_clk = 0;
|
||||
reg qsfp_1_tx_rst = 0;
|
||||
reg qsfp_1_tx_axis_tready = 0;
|
||||
reg qsfp_1_rx_clk = 0;
|
||||
reg qsfp_1_rx_rst = 0;
|
||||
reg [AXIS_ETH_DATA_WIDTH-1:0] qsfp_1_rx_axis_tdata = 0;
|
||||
reg [AXIS_ETH_KEEP_WIDTH-1:0] qsfp_1_rx_axis_tkeep = 0;
|
||||
reg qsfp_1_rx_axis_tvalid = 0;
|
||||
reg qsfp_1_rx_axis_tlast = 0;
|
||||
reg qsfp_1_rx_axis_tuser = 0;
|
||||
reg qsfp_1_modprs_l = 0;
|
||||
reg qsfp_int_l = 0;
|
||||
reg qsfp_i2c_scl_i = 1;
|
||||
reg qsfp_i2c_sda_i = 1;
|
||||
reg eeprom_i2c_scl_i = 1;
|
||||
reg eeprom_i2c_sda_i = 1;
|
||||
reg [3:0] qspi_0_dq_i = 0;
|
||||
reg [3:0] qspi_1_dq_i = 0;
|
||||
|
||||
// Outputs
|
||||
wire [1:0] user_led_g;
|
||||
wire user_led_r;
|
||||
wire [1:0] front_led;
|
||||
wire [AXIS_PCIE_DATA_WIDTH-1:0] m_axis_rq_tdata;
|
||||
wire [AXIS_PCIE_KEEP_WIDTH-1:0] m_axis_rq_tkeep;
|
||||
wire m_axis_rq_tlast;
|
||||
wire [AXIS_PCIE_RQ_USER_WIDTH-1:0] m_axis_rq_tuser;
|
||||
wire m_axis_rq_tvalid;
|
||||
wire s_axis_rc_tready;
|
||||
wire s_axis_cq_tready;
|
||||
wire [AXIS_PCIE_DATA_WIDTH-1:0] m_axis_cc_tdata;
|
||||
wire [AXIS_PCIE_KEEP_WIDTH-1:0] m_axis_cc_tkeep;
|
||||
wire m_axis_cc_tlast;
|
||||
wire [AXIS_PCIE_CC_USER_WIDTH-1:0] m_axis_cc_tuser;
|
||||
wire m_axis_cc_tvalid;
|
||||
wire [9:0] cfg_mgmt_addr;
|
||||
wire [7:0] cfg_mgmt_function_number;
|
||||
wire cfg_mgmt_write;
|
||||
wire [31:0] cfg_mgmt_write_data;
|
||||
wire [3:0] cfg_mgmt_byte_enable;
|
||||
wire cfg_mgmt_read;
|
||||
wire [2:0] cfg_fc_sel;
|
||||
wire [3:0] cfg_interrupt_msi_select;
|
||||
wire [31:0] cfg_interrupt_msi_int;
|
||||
wire [31:0] cfg_interrupt_msi_pending_status;
|
||||
wire cfg_interrupt_msi_pending_status_data_enable;
|
||||
wire [3:0] cfg_interrupt_msi_pending_status_function_num;
|
||||
wire [2:0] cfg_interrupt_msi_attr;
|
||||
wire cfg_interrupt_msi_tph_present;
|
||||
wire [1:0] cfg_interrupt_msi_tph_type;
|
||||
wire [8:0] cfg_interrupt_msi_tph_st_tag;
|
||||
wire [3:0] cfg_interrupt_msi_function_number;
|
||||
wire status_error_cor;
|
||||
wire status_error_uncor;
|
||||
wire [AXIS_ETH_DATA_WIDTH-1:0] qsfp_0_tx_axis_tdata;
|
||||
wire [AXIS_ETH_KEEP_WIDTH-1:0] qsfp_0_tx_axis_tkeep;
|
||||
wire qsfp_0_tx_axis_tvalid;
|
||||
wire qsfp_0_tx_axis_tlast;
|
||||
wire qsfp_0_tx_axis_tuser;
|
||||
wire qsfp_0_sel_l;
|
||||
wire [AXIS_ETH_DATA_WIDTH-1:0] qsfp_1_tx_axis_tdata;
|
||||
wire [AXIS_ETH_KEEP_WIDTH-1:0] qsfp_1_tx_axis_tkeep;
|
||||
wire qsfp_1_tx_axis_tvalid;
|
||||
wire qsfp_1_tx_axis_tlast;
|
||||
wire qsfp_1_tx_axis_tuser;
|
||||
wire qsfp_1_sel_l;
|
||||
wire qsfp_reset_l;
|
||||
wire qsfp_i2c_scl_o;
|
||||
wire qsfp_i2c_scl_t;
|
||||
wire qsfp_i2c_sda_o;
|
||||
wire qsfp_i2c_sda_t;
|
||||
wire eeprom_i2c_scl_o;
|
||||
wire eeprom_i2c_scl_t;
|
||||
wire eeprom_i2c_sda_o;
|
||||
wire eeprom_i2c_sda_t;
|
||||
wire eeprom_wp;
|
||||
wire fpga_boot;
|
||||
wire qspi_clk;
|
||||
wire [3:0] qspi_0_dq_o;
|
||||
wire [3:0] qspi_0_dq_oe;
|
||||
wire qspi_0_cs;
|
||||
wire [3:0] qspi_1_dq_o;
|
||||
wire [3:0] qspi_1_dq_oe;
|
||||
wire qspi_1_cs;
|
||||
|
||||
initial begin
|
||||
// myhdl integration
|
||||
$from_myhdl(
|
||||
clk_250mhz,
|
||||
rst_250mhz,
|
||||
current_test,
|
||||
user_sw,
|
||||
m_axis_rq_tready,
|
||||
s_axis_rc_tdata,
|
||||
s_axis_rc_tkeep,
|
||||
s_axis_rc_tlast,
|
||||
s_axis_rc_tuser,
|
||||
s_axis_rc_tvalid,
|
||||
s_axis_cq_tdata,
|
||||
s_axis_cq_tkeep,
|
||||
s_axis_cq_tlast,
|
||||
s_axis_cq_tuser,
|
||||
s_axis_cq_tvalid,
|
||||
m_axis_cc_tready,
|
||||
s_axis_rq_seq_num_0,
|
||||
s_axis_rq_seq_num_valid_0,
|
||||
s_axis_rq_seq_num_1,
|
||||
s_axis_rq_seq_num_valid_1,
|
||||
pcie_tfc_nph_av,
|
||||
pcie_tfc_npd_av,
|
||||
cfg_max_payload,
|
||||
cfg_max_read_req,
|
||||
cfg_mgmt_read_data,
|
||||
cfg_mgmt_read_write_done,
|
||||
cfg_fc_ph,
|
||||
cfg_fc_pd,
|
||||
cfg_fc_nph,
|
||||
cfg_fc_npd,
|
||||
cfg_fc_cplh,
|
||||
cfg_fc_cpld,
|
||||
cfg_interrupt_msi_enable,
|
||||
cfg_interrupt_msi_mmenable,
|
||||
cfg_interrupt_msi_mask_update,
|
||||
cfg_interrupt_msi_data,
|
||||
cfg_interrupt_msi_sent,
|
||||
cfg_interrupt_msi_fail,
|
||||
qsfp_0_tx_clk,
|
||||
qsfp_0_tx_rst,
|
||||
qsfp_0_tx_axis_tready,
|
||||
qsfp_0_rx_clk,
|
||||
qsfp_0_rx_rst,
|
||||
qsfp_0_rx_axis_tdata,
|
||||
qsfp_0_rx_axis_tkeep,
|
||||
qsfp_0_rx_axis_tvalid,
|
||||
qsfp_0_rx_axis_tlast,
|
||||
qsfp_0_rx_axis_tuser,
|
||||
qsfp_0_modprs_l,
|
||||
qsfp_1_tx_clk,
|
||||
qsfp_1_tx_rst,
|
||||
qsfp_1_tx_axis_tready,
|
||||
qsfp_1_rx_clk,
|
||||
qsfp_1_rx_rst,
|
||||
qsfp_1_rx_axis_tdata,
|
||||
qsfp_1_rx_axis_tkeep,
|
||||
qsfp_1_rx_axis_tvalid,
|
||||
qsfp_1_rx_axis_tlast,
|
||||
qsfp_1_rx_axis_tuser,
|
||||
qsfp_1_modprs_l,
|
||||
qsfp_int_l,
|
||||
qsfp_i2c_scl_i,
|
||||
qsfp_i2c_sda_i,
|
||||
eeprom_i2c_scl_i,
|
||||
eeprom_i2c_sda_i,
|
||||
qspi_0_dq_i,
|
||||
qspi_1_dq_i
|
||||
);
|
||||
$to_myhdl(
|
||||
user_led_g,
|
||||
user_led_r,
|
||||
front_led,
|
||||
m_axis_rq_tdata,
|
||||
m_axis_rq_tkeep,
|
||||
m_axis_rq_tlast,
|
||||
m_axis_rq_tuser,
|
||||
m_axis_rq_tvalid,
|
||||
s_axis_rc_tready,
|
||||
s_axis_cq_tready,
|
||||
m_axis_cc_tdata,
|
||||
m_axis_cc_tkeep,
|
||||
m_axis_cc_tlast,
|
||||
m_axis_cc_tuser,
|
||||
m_axis_cc_tvalid,
|
||||
cfg_mgmt_addr,
|
||||
cfg_mgmt_function_number,
|
||||
cfg_mgmt_write,
|
||||
cfg_mgmt_write_data,
|
||||
cfg_mgmt_byte_enable,
|
||||
cfg_mgmt_read,
|
||||
cfg_fc_sel,
|
||||
cfg_interrupt_msi_select,
|
||||
cfg_interrupt_msi_int,
|
||||
cfg_interrupt_msi_pending_status,
|
||||
cfg_interrupt_msi_pending_status_data_enable,
|
||||
cfg_interrupt_msi_pending_status_function_num,
|
||||
cfg_interrupt_msi_attr,
|
||||
cfg_interrupt_msi_tph_present,
|
||||
cfg_interrupt_msi_tph_type,
|
||||
cfg_interrupt_msi_tph_st_tag,
|
||||
cfg_interrupt_msi_function_number,
|
||||
status_error_cor,
|
||||
status_error_uncor,
|
||||
qsfp_0_tx_axis_tdata,
|
||||
qsfp_0_tx_axis_tkeep,
|
||||
qsfp_0_tx_axis_tvalid,
|
||||
qsfp_0_tx_axis_tlast,
|
||||
qsfp_0_tx_axis_tuser,
|
||||
qsfp_0_sel_l,
|
||||
qsfp_1_tx_axis_tdata,
|
||||
qsfp_1_tx_axis_tkeep,
|
||||
qsfp_1_tx_axis_tvalid,
|
||||
qsfp_1_tx_axis_tlast,
|
||||
qsfp_1_tx_axis_tuser,
|
||||
qsfp_1_sel_l,
|
||||
qsfp_reset_l,
|
||||
qsfp_i2c_scl_o,
|
||||
qsfp_i2c_scl_t,
|
||||
qsfp_i2c_sda_o,
|
||||
qsfp_i2c_sda_t,
|
||||
eeprom_i2c_scl_o,
|
||||
eeprom_i2c_scl_t,
|
||||
eeprom_i2c_sda_o,
|
||||
eeprom_i2c_sda_t,
|
||||
eeprom_wp,
|
||||
fpga_boot,
|
||||
qspi_clk,
|
||||
qspi_0_dq_o,
|
||||
qspi_0_dq_oe,
|
||||
qspi_0_cs,
|
||||
qspi_1_dq_o,
|
||||
qspi_1_dq_oe,
|
||||
qspi_1_cs
|
||||
);
|
||||
|
||||
// dump file
|
||||
$dumpfile("test_fpga_core.lxt");
|
||||
$dumpvars(0, test_fpga_core);
|
||||
end
|
||||
|
||||
fpga_core #(
|
||||
.AXIS_PCIE_DATA_WIDTH(AXIS_PCIE_DATA_WIDTH),
|
||||
.AXIS_PCIE_KEEP_WIDTH(AXIS_PCIE_KEEP_WIDTH),
|
||||
.AXIS_PCIE_RC_USER_WIDTH(AXIS_PCIE_RC_USER_WIDTH),
|
||||
.AXIS_PCIE_RQ_USER_WIDTH(AXIS_PCIE_RQ_USER_WIDTH),
|
||||
.AXIS_PCIE_CQ_USER_WIDTH(AXIS_PCIE_CQ_USER_WIDTH),
|
||||
.AXIS_PCIE_CC_USER_WIDTH(AXIS_PCIE_CC_USER_WIDTH),
|
||||
.RQ_SEQ_NUM_WIDTH(RQ_SEQ_NUM_WIDTH),
|
||||
.BAR0_APERTURE(BAR0_APERTURE),
|
||||
.AXIS_ETH_DATA_WIDTH(AXIS_ETH_DATA_WIDTH),
|
||||
.AXIS_ETH_KEEP_WIDTH(AXIS_ETH_KEEP_WIDTH)
|
||||
)
|
||||
UUT (
|
||||
.clk_250mhz(clk_250mhz),
|
||||
.rst_250mhz(rst_250mhz),
|
||||
.user_led_g(user_led_g),
|
||||
.user_led_r(user_led_r),
|
||||
.front_led(front_led),
|
||||
.user_sw(user_sw),
|
||||
.m_axis_rq_tdata(m_axis_rq_tdata),
|
||||
.m_axis_rq_tkeep(m_axis_rq_tkeep),
|
||||
.m_axis_rq_tlast(m_axis_rq_tlast),
|
||||
.m_axis_rq_tready(m_axis_rq_tready),
|
||||
.m_axis_rq_tuser(m_axis_rq_tuser),
|
||||
.m_axis_rq_tvalid(m_axis_rq_tvalid),
|
||||
.s_axis_rc_tdata(s_axis_rc_tdata),
|
||||
.s_axis_rc_tkeep(s_axis_rc_tkeep),
|
||||
.s_axis_rc_tlast(s_axis_rc_tlast),
|
||||
.s_axis_rc_tready(s_axis_rc_tready),
|
||||
.s_axis_rc_tuser(s_axis_rc_tuser),
|
||||
.s_axis_rc_tvalid(s_axis_rc_tvalid),
|
||||
.s_axis_cq_tdata(s_axis_cq_tdata),
|
||||
.s_axis_cq_tkeep(s_axis_cq_tkeep),
|
||||
.s_axis_cq_tlast(s_axis_cq_tlast),
|
||||
.s_axis_cq_tready(s_axis_cq_tready),
|
||||
.s_axis_cq_tuser(s_axis_cq_tuser),
|
||||
.s_axis_cq_tvalid(s_axis_cq_tvalid),
|
||||
.m_axis_cc_tdata(m_axis_cc_tdata),
|
||||
.m_axis_cc_tkeep(m_axis_cc_tkeep),
|
||||
.m_axis_cc_tlast(m_axis_cc_tlast),
|
||||
.m_axis_cc_tready(m_axis_cc_tready),
|
||||
.m_axis_cc_tuser(m_axis_cc_tuser),
|
||||
.m_axis_cc_tvalid(m_axis_cc_tvalid),
|
||||
.s_axis_rq_seq_num_0(s_axis_rq_seq_num_0),
|
||||
.s_axis_rq_seq_num_valid_0(s_axis_rq_seq_num_valid_0),
|
||||
.s_axis_rq_seq_num_1(s_axis_rq_seq_num_1),
|
||||
.s_axis_rq_seq_num_valid_1(s_axis_rq_seq_num_valid_1),
|
||||
.pcie_tfc_nph_av(pcie_tfc_nph_av),
|
||||
.pcie_tfc_npd_av(pcie_tfc_npd_av),
|
||||
.cfg_max_payload(cfg_max_payload),
|
||||
.cfg_max_read_req(cfg_max_read_req),
|
||||
.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),
|
||||
.status_error_cor(status_error_cor),
|
||||
.status_error_uncor(status_error_uncor),
|
||||
.qsfp_0_tx_clk(qsfp_0_tx_clk),
|
||||
.qsfp_0_tx_rst(qsfp_0_tx_rst),
|
||||
.qsfp_0_tx_axis_tdata(qsfp_0_tx_axis_tdata),
|
||||
.qsfp_0_tx_axis_tkeep(qsfp_0_tx_axis_tkeep),
|
||||
.qsfp_0_tx_axis_tvalid(qsfp_0_tx_axis_tvalid),
|
||||
.qsfp_0_tx_axis_tready(qsfp_0_tx_axis_tready),
|
||||
.qsfp_0_tx_axis_tlast(qsfp_0_tx_axis_tlast),
|
||||
.qsfp_0_tx_axis_tuser(qsfp_0_tx_axis_tuser),
|
||||
.qsfp_0_rx_clk(qsfp_0_rx_clk),
|
||||
.qsfp_0_rx_rst(qsfp_0_rx_rst),
|
||||
.qsfp_0_rx_axis_tdata(qsfp_0_rx_axis_tdata),
|
||||
.qsfp_0_rx_axis_tkeep(qsfp_0_rx_axis_tkeep),
|
||||
.qsfp_0_rx_axis_tvalid(qsfp_0_rx_axis_tvalid),
|
||||
.qsfp_0_rx_axis_tlast(qsfp_0_rx_axis_tlast),
|
||||
.qsfp_0_rx_axis_tuser(qsfp_0_rx_axis_tuser),
|
||||
.qsfp_0_modprs_l(qsfp_0_modprs_l),
|
||||
.qsfp_0_sel_l(qsfp_0_sel_l),
|
||||
.qsfp_1_tx_clk(qsfp_1_tx_clk),
|
||||
.qsfp_1_tx_rst(qsfp_1_tx_rst),
|
||||
.qsfp_1_tx_axis_tdata(qsfp_1_tx_axis_tdata),
|
||||
.qsfp_1_tx_axis_tkeep(qsfp_1_tx_axis_tkeep),
|
||||
.qsfp_1_tx_axis_tvalid(qsfp_1_tx_axis_tvalid),
|
||||
.qsfp_1_tx_axis_tready(qsfp_1_tx_axis_tready),
|
||||
.qsfp_1_tx_axis_tlast(qsfp_1_tx_axis_tlast),
|
||||
.qsfp_1_tx_axis_tuser(qsfp_1_tx_axis_tuser),
|
||||
.qsfp_1_rx_clk(qsfp_1_rx_clk),
|
||||
.qsfp_1_rx_rst(qsfp_1_rx_rst),
|
||||
.qsfp_1_rx_axis_tdata(qsfp_1_rx_axis_tdata),
|
||||
.qsfp_1_rx_axis_tkeep(qsfp_1_rx_axis_tkeep),
|
||||
.qsfp_1_rx_axis_tvalid(qsfp_1_rx_axis_tvalid),
|
||||
.qsfp_1_rx_axis_tlast(qsfp_1_rx_axis_tlast),
|
||||
.qsfp_1_rx_axis_tuser(qsfp_1_rx_axis_tuser),
|
||||
.qsfp_1_modprs_l(qsfp_1_modprs_l),
|
||||
.qsfp_1_sel_l(qsfp_1_sel_l),
|
||||
.qsfp_reset_l(qsfp_reset_l),
|
||||
.qsfp_int_l(qsfp_int_l),
|
||||
.qsfp_i2c_scl_i(qsfp_i2c_scl_i),
|
||||
.qsfp_i2c_scl_o(qsfp_i2c_scl_o),
|
||||
.qsfp_i2c_scl_t(qsfp_i2c_scl_t),
|
||||
.qsfp_i2c_sda_i(qsfp_i2c_sda_i),
|
||||
.qsfp_i2c_sda_o(qsfp_i2c_sda_o),
|
||||
.qsfp_i2c_sda_t(qsfp_i2c_sda_t),
|
||||
.eeprom_i2c_scl_i(eeprom_i2c_scl_i),
|
||||
.eeprom_i2c_scl_o(eeprom_i2c_scl_o),
|
||||
.eeprom_i2c_scl_t(eeprom_i2c_scl_t),
|
||||
.eeprom_i2c_sda_i(eeprom_i2c_sda_i),
|
||||
.eeprom_i2c_sda_o(eeprom_i2c_sda_o),
|
||||
.eeprom_i2c_sda_t(eeprom_i2c_sda_t),
|
||||
.eeprom_wp(eeprom_wp),
|
||||
.fpga_boot(fpga_boot),
|
||||
.qspi_clk(qspi_clk),
|
||||
.qspi_0_dq_i(qspi_0_dq_i),
|
||||
.qspi_0_dq_o(qspi_0_dq_o),
|
||||
.qspi_0_dq_oe(qspi_0_dq_oe),
|
||||
.qspi_0_cs(qspi_0_cs),
|
||||
.qspi_1_dq_i(qspi_1_dq_i),
|
||||
.qspi_1_dq_o(qspi_1_dq_o),
|
||||
.qspi_1_dq_oe(qspi_1_dq_oe),
|
||||
.qspi_1_cs(qspi_1_cs)
|
||||
);
|
||||
|
||||
endmodule
|
@ -1 +0,0 @@
|
||||
../lib/eth/tb/udp_ep.py
|
@ -1 +0,0 @@
|
||||
../lib/eth/tb/axis_ep.py
|
@ -1 +0,0 @@
|
||||
../lib/eth/tb/eth_ep.py
|
152
fpga/mqnic/ADM_PCIE_9V3/fpga_10g/tb/fpga_core/Makefile
Normal file
152
fpga/mqnic/ADM_PCIE_9V3/fpga_10g/tb/fpga_core/Makefile
Normal file
@ -0,0 +1,152 @@
|
||||
# Copyright 2020, The Regents of the University of California.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
#
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
|
||||
# IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
|
||||
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
# OF SUCH DAMAGE.
|
||||
#
|
||||
# The views and conclusions contained in the software and documentation are those
|
||||
# of the authors and should not be interpreted as representing official policies,
|
||||
# either expressed or implied, of The Regents of the University of California.
|
||||
|
||||
TOPLEVEL_LANG = verilog
|
||||
|
||||
SIM ?= icarus
|
||||
WAVES ?= 0
|
||||
|
||||
COCOTB_HDL_TIMEUNIT = 1ns
|
||||
COCOTB_HDL_TIMEPRECISION = 1ps
|
||||
|
||||
DUT = fpga_core
|
||||
TOPLEVEL = $(DUT)
|
||||
MODULE = test_$(DUT)
|
||||
VERILOG_SOURCES += ../../rtl/$(DUT).v
|
||||
VERILOG_SOURCES += ../../rtl/common/mqnic_interface.v
|
||||
VERILOG_SOURCES += ../../rtl/common/mqnic_port.v
|
||||
VERILOG_SOURCES += ../../rtl/common/cpl_write.v
|
||||
VERILOG_SOURCES += ../../rtl/common/cpl_op_mux.v
|
||||
VERILOG_SOURCES += ../../rtl/common/desc_fetch.v
|
||||
VERILOG_SOURCES += ../../rtl/common/desc_op_mux.v
|
||||
VERILOG_SOURCES += ../../rtl/common/queue_manager.v
|
||||
VERILOG_SOURCES += ../../rtl/common/cpl_queue_manager.v
|
||||
VERILOG_SOURCES += ../../rtl/common/tx_engine.v
|
||||
VERILOG_SOURCES += ../../rtl/common/rx_engine.v
|
||||
VERILOG_SOURCES += ../../rtl/common/tx_checksum.v
|
||||
VERILOG_SOURCES += ../../rtl/common/rx_hash.v
|
||||
VERILOG_SOURCES += ../../rtl/common/rx_checksum.v
|
||||
VERILOG_SOURCES += ../../rtl/common/tx_scheduler_rr.v
|
||||
VERILOG_SOURCES += ../../rtl/common/event_mux.v
|
||||
VERILOG_SOURCES += ../../rtl/common/tdma_scheduler.v
|
||||
VERILOG_SOURCES += ../../rtl/common/tdma_ber.v
|
||||
VERILOG_SOURCES += ../../rtl/common/tdma_ber_ch.v
|
||||
VERILOG_SOURCES += ../../lib/eth/rtl/eth_mac_10g_fifo.v
|
||||
VERILOG_SOURCES += ../../lib/eth/rtl/eth_mac_10g.v
|
||||
VERILOG_SOURCES += ../../lib/eth/rtl/axis_xgmii_rx_64.v
|
||||
VERILOG_SOURCES += ../../lib/eth/rtl/axis_xgmii_tx_64.v
|
||||
VERILOG_SOURCES += ../../lib/eth/rtl/lfsr.v
|
||||
VERILOG_SOURCES += ../../lib/eth/rtl/ptp_clock.v
|
||||
VERILOG_SOURCES += ../../lib/eth/rtl/ptp_clock_cdc.v
|
||||
VERILOG_SOURCES += ../../lib/eth/rtl/ptp_perout.v
|
||||
VERILOG_SOURCES += ../../lib/eth/rtl/ptp_ts_extract.v
|
||||
VERILOG_SOURCES += ../../lib/axi/rtl/axil_interconnect.v
|
||||
VERILOG_SOURCES += ../../lib/axi/rtl/arbiter.v
|
||||
VERILOG_SOURCES += ../../lib/axi/rtl/priority_encoder.v
|
||||
VERILOG_SOURCES += ../../lib/axis/rtl/axis_adapter.v
|
||||
VERILOG_SOURCES += ../../lib/axis/rtl/axis_arb_mux.v
|
||||
VERILOG_SOURCES += ../../lib/axis/rtl/axis_async_fifo.v
|
||||
VERILOG_SOURCES += ../../lib/axis/rtl/axis_async_fifo_adapter.v
|
||||
VERILOG_SOURCES += ../../lib/axis/rtl/axis_fifo.v
|
||||
VERILOG_SOURCES += ../../lib/axis/rtl/axis_register.v
|
||||
VERILOG_SOURCES += ../../lib/pcie/rtl/pcie_us_axil_master.v
|
||||
VERILOG_SOURCES += ../../lib/pcie/rtl/dma_if_pcie_us.v
|
||||
VERILOG_SOURCES += ../../lib/pcie/rtl/dma_if_pcie_us_rd.v
|
||||
VERILOG_SOURCES += ../../lib/pcie/rtl/dma_if_pcie_us_wr.v
|
||||
VERILOG_SOURCES += ../../lib/pcie/rtl/dma_if_mux.v
|
||||
VERILOG_SOURCES += ../../lib/pcie/rtl/dma_if_mux_rd.v
|
||||
VERILOG_SOURCES += ../../lib/pcie/rtl/dma_if_mux_wr.v
|
||||
VERILOG_SOURCES += ../../lib/pcie/rtl/dma_psdpram.v
|
||||
VERILOG_SOURCES += ../../lib/pcie/rtl/dma_client_axis_sink.v
|
||||
VERILOG_SOURCES += ../../lib/pcie/rtl/dma_client_axis_source.v
|
||||
VERILOG_SOURCES += ../../lib/pcie/rtl/pcie_us_cfg.v
|
||||
VERILOG_SOURCES += ../../lib/pcie/rtl/pcie_us_msi.v
|
||||
VERILOG_SOURCES += ../../lib/pcie/rtl/pcie_tag_manager.v
|
||||
VERILOG_SOURCES += ../../lib/pcie/rtl/pulse_merge.v
|
||||
|
||||
# module parameters
|
||||
export PARAM_AXIS_PCIE_DATA_WIDTH ?= 512
|
||||
export PARAM_AXIS_PCIE_KEEP_WIDTH ?= $(shell expr $(PARAM_AXIS_PCIE_DATA_WIDTH) / 32 )
|
||||
export PARAM_AXIS_PCIE_RQ_USER_WIDTH ?= $(if $(filter-out 512,$(PARAM_AXIS_PCIE_DATA_WIDTH)),62,137)
|
||||
export PARAM_AXIS_PCIE_RC_USER_WIDTH ?= $(if $(filter-out 512,$(PARAM_AXIS_PCIE_DATA_WIDTH)),75,161)
|
||||
export PARAM_AXIS_PCIE_CQ_USER_WIDTH ?= $(if $(filter-out 512,$(PARAM_AXIS_PCIE_DATA_WIDTH)),88,183)
|
||||
export PARAM_AXIS_PCIE_CC_USER_WIDTH ?= $(if $(filter-out 512,$(PARAM_AXIS_PCIE_DATA_WIDTH)),33,81)
|
||||
export PARAM_RQ_SEQ_NUM_WIDTH ?= 6
|
||||
export PARAM_BAR0_APERTURE ?= 24
|
||||
|
||||
SIM_BUILD ?= sim_build_$(MODULE)
|
||||
|
||||
ifeq ($(SIM), icarus)
|
||||
PLUSARGS += -fst
|
||||
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).AXIS_PCIE_DATA_WIDTH=$(PARAM_AXIS_PCIE_DATA_WIDTH)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).AXIS_PCIE_KEEP_WIDTH=$(PARAM_AXIS_PCIE_KEEP_WIDTH)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).AXIS_PCIE_RQ_USER_WIDTH=$(PARAM_AXIS_PCIE_RQ_USER_WIDTH)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).AXIS_PCIE_RC_USER_WIDTH=$(PARAM_AXIS_PCIE_RC_USER_WIDTH)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).AXIS_PCIE_CQ_USER_WIDTH=$(PARAM_AXIS_PCIE_CQ_USER_WIDTH)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).AXIS_PCIE_CC_USER_WIDTH=$(PARAM_AXIS_PCIE_CC_USER_WIDTH)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).RQ_SEQ_NUM_WIDTH=$(PARAM_RQ_SEQ_NUM_WIDTH)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).BAR0_APERTURE=$(PARAM_BAR0_APERTURE)
|
||||
|
||||
ifeq ($(WAVES), 1)
|
||||
VERILOG_SOURCES += iverilog_dump.v
|
||||
COMPILE_ARGS += -s iverilog_dump
|
||||
endif
|
||||
else ifeq ($(SIM), verilator)
|
||||
COMPILE_ARGS += -Wno-SELRANGE -Wno-WIDTH
|
||||
|
||||
COMPILE_ARGS += -GAXIS_PCIE_DATA_WIDTH=$(PARAM_AXIS_PCIE_DATA_WIDTH)
|
||||
COMPILE_ARGS += -GAXIS_PCIE_KEEP_WIDTH=$(PARAM_AXIS_PCIE_KEEP_WIDTH)
|
||||
COMPILE_ARGS += -GAXIS_PCIE_RQ_USER_WIDTH=$(PARAM_AXIS_PCIE_RQ_USER_WIDTH)
|
||||
COMPILE_ARGS += -GAXIS_PCIE_RC_USER_WIDTH=$(PARAM_AXIS_PCIE_RC_USER_WIDTH)
|
||||
COMPILE_ARGS += -GAXIS_PCIE_CQ_USER_WIDTH=$(PARAM_AXIS_PCIE_CQ_USER_WIDTH)
|
||||
COMPILE_ARGS += -GAXIS_PCIE_CC_USER_WIDTH=$(PARAM_AXIS_PCIE_CC_USER_WIDTH)
|
||||
COMPILE_ARGS += -GRQ_SEQ_NUM_WIDTH=$(PARAM_RQ_SEQ_NUM_WIDTH)
|
||||
COMPILE_ARGS += -GBAR0_APERTURE=$(PARAM_BAR0_APERTURE)
|
||||
|
||||
ifeq ($(WAVES), 1)
|
||||
COMPILE_ARGS += --trace-fst
|
||||
endif
|
||||
endif
|
||||
|
||||
iverilog_dump.v:
|
||||
echo 'module iverilog_dump();' > $@
|
||||
echo 'initial begin' >> $@
|
||||
echo ' $$dumpfile("$(TOPLEVEL).fst");' >> $@
|
||||
echo ' $$dumpvars(0, $(TOPLEVEL));' >> $@
|
||||
echo 'end' >> $@
|
||||
echo 'endmodule' >> $@
|
||||
|
||||
clean::
|
||||
@rm -rf sim_build_*
|
||||
@rm -rf iverilog_dump.v
|
||||
@rm -rf dump.fst $(TOPLEVEL).fst
|
||||
|
||||
include $(shell cocotb-config --makefiles)/Makefile.sim
|
||||
|
1
fpga/mqnic/ADM_PCIE_9V3/fpga_10g/tb/fpga_core/mqnic.py
Symbolic link
1
fpga/mqnic/ADM_PCIE_9V3/fpga_10g/tb/fpga_core/mqnic.py
Symbolic link
@ -0,0 +1 @@
|
||||
../../../../../common/tb/mqnic.py
|
657
fpga/mqnic/ADM_PCIE_9V3/fpga_10g/tb/fpga_core/test_fpga_core.py
Normal file
657
fpga/mqnic/ADM_PCIE_9V3/fpga_10g/tb/fpga_core/test_fpga_core.py
Normal file
@ -0,0 +1,657 @@
|
||||
"""
|
||||
|
||||
Copyright 2020, The Regents of the University of California.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
|
||||
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of The Regents of the University of California.
|
||||
|
||||
"""
|
||||
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
|
||||
import scapy.utils
|
||||
from scapy.layers.l2 import Ether
|
||||
from scapy.layers.inet import IP, UDP
|
||||
|
||||
import cocotb_test.simulator
|
||||
|
||||
import cocotb
|
||||
from cocotb.log import SimLog
|
||||
from cocotb.clock import Clock
|
||||
from cocotb.triggers import RisingEdge, FallingEdge, Timer
|
||||
|
||||
from cocotbext.pcie.core import RootComplex
|
||||
from cocotbext.pcie.xilinx.us import UltraScalePlusPcieDevice
|
||||
|
||||
from cocotbext.eth import XgmiiSource, XgmiiSink
|
||||
|
||||
try:
|
||||
import mqnic
|
||||
except ImportError:
|
||||
# attempt import from current directory
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__)))
|
||||
try:
|
||||
import mqnic
|
||||
finally:
|
||||
del sys.path[0]
|
||||
|
||||
|
||||
class TB(object):
|
||||
def __init__(self, dut):
|
||||
self.dut = dut
|
||||
|
||||
self.BAR0_APERTURE = int(os.getenv("PARAM_BAR0_APERTURE"))
|
||||
|
||||
self.log = SimLog("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_cc_straddle=False,
|
||||
rq_rc_straddle=False,
|
||||
rc_4tlp_straddle=False,
|
||||
enable_pf1=False,
|
||||
enable_client_tag=True,
|
||||
enable_extended_tag=True,
|
||||
enable_parity=False,
|
||||
enable_rx_msg_interface=False,
|
||||
enable_sriov=False,
|
||||
enable_extended_configuration=False,
|
||||
|
||||
enable_pf0_msi=True,
|
||||
enable_pf1_msi=False,
|
||||
|
||||
# signals
|
||||
# Clock and Reset Interface
|
||||
user_clk=dut.clk_250mhz,
|
||||
user_reset=dut.rst_250mhz,
|
||||
# user_lnk_up
|
||||
# sys_clk
|
||||
# sys_clk_gt
|
||||
# sys_reset
|
||||
# phy_rdy_out
|
||||
|
||||
# Requester reQuest Interface
|
||||
rq_entity=dut,
|
||||
rq_name="m_axis_rq",
|
||||
pcie_rq_seq_num0=dut.s_axis_rq_seq_num_0,
|
||||
pcie_rq_seq_num_vld0=dut.s_axis_rq_seq_num_valid_0,
|
||||
pcie_rq_seq_num1=dut.s_axis_rq_seq_num_1,
|
||||
pcie_rq_seq_num_vld1=dut.s_axis_rq_seq_num_valid_1,
|
||||
# pcie_rq_tag0
|
||||
# pcie_rq_tag1
|
||||
# pcie_rq_tag_av
|
||||
# pcie_rq_tag_vld0
|
||||
# pcie_rq_tag_vld1
|
||||
|
||||
# Requester Completion Interface
|
||||
rc_entity=dut,
|
||||
rc_name="s_axis_rc",
|
||||
|
||||
# Completer reQuest Interface
|
||||
cq_entity=dut,
|
||||
cq_name="s_axis_cq",
|
||||
# pcie_cq_np_req
|
||||
# pcie_cq_np_req_count
|
||||
|
||||
# Completer Completion Interface
|
||||
cc_entity=dut,
|
||||
cc_name="m_axis_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
|
||||
# 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
|
||||
# cfg_interrupt_msix_mask
|
||||
# cfg_interrupt_msix_vf_enable
|
||||
# cfg_interrupt_msix_vf_mask
|
||||
# cfg_interrupt_msix_address
|
||||
# cfg_interrupt_msix_data
|
||||
# cfg_interrupt_msix_int
|
||||
# cfg_interrupt_msix_vec_pending
|
||||
# cfg_interrupt_msix_vec_pending_status
|
||||
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.driver = mqnic.Driver(self.rc)
|
||||
|
||||
self.dev.functions[0].msi_multiple_message_capable = 5
|
||||
|
||||
self.dev.functions[0].configure_bar(0, 2**self.BAR0_APERTURE, ext=True, prefetch=True)
|
||||
|
||||
# Ethernet
|
||||
cocotb.fork(Clock(dut.qsfp_0_rx_clk_0, 6.4, units="ns").start())
|
||||
self.qsfp_0_0_source = XgmiiSource(dut.qsfp_0_rxd_0, dut.qsfp_0_rxc_0, dut.qsfp_0_rx_clk_0, dut.qsfp_0_rx_rst_0)
|
||||
cocotb.fork(Clock(dut.qsfp_0_tx_clk_0, 6.4, units="ns").start())
|
||||
self.qsfp_0_0_sink = XgmiiSink(dut.qsfp_0_txd_0, dut.qsfp_0_txc_0, dut.qsfp_0_tx_clk_0, dut.qsfp_0_tx_rst_0)
|
||||
|
||||
cocotb.fork(Clock(dut.qsfp_0_rx_clk_1, 6.4, units="ns").start())
|
||||
self.qsfp_0_1_source = XgmiiSource(dut.qsfp_0_rxd_1, dut.qsfp_0_rxc_1, dut.qsfp_0_rx_clk_1, dut.qsfp_0_rx_rst_1)
|
||||
cocotb.fork(Clock(dut.qsfp_0_tx_clk_1, 6.4, units="ns").start())
|
||||
self.qsfp_0_1_sink = XgmiiSink(dut.qsfp_0_txd_1, dut.qsfp_0_txc_1, dut.qsfp_0_tx_clk_1, dut.qsfp_0_tx_rst_1)
|
||||
|
||||
cocotb.fork(Clock(dut.qsfp_0_rx_clk_2, 6.4, units="ns").start())
|
||||
self.qsfp_0_2_source = XgmiiSource(dut.qsfp_0_rxd_2, dut.qsfp_0_rxc_2, dut.qsfp_0_rx_clk_2, dut.qsfp_0_rx_rst_2)
|
||||
cocotb.fork(Clock(dut.qsfp_0_tx_clk_2, 6.4, units="ns").start())
|
||||
self.qsfp_0_2_sink = XgmiiSink(dut.qsfp_0_txd_2, dut.qsfp_0_txc_2, dut.qsfp_0_tx_clk_2, dut.qsfp_0_tx_rst_2)
|
||||
|
||||
cocotb.fork(Clock(dut.qsfp_0_rx_clk_3, 6.4, units="ns").start())
|
||||
self.qsfp_0_3_source = XgmiiSource(dut.qsfp_0_rxd_3, dut.qsfp_0_rxc_3, dut.qsfp_0_rx_clk_3, dut.qsfp_0_rx_rst_3)
|
||||
cocotb.fork(Clock(dut.qsfp_0_tx_clk_3, 6.4, units="ns").start())
|
||||
self.qsfp_0_3_sink = XgmiiSink(dut.qsfp_0_txd_3, dut.qsfp_0_txc_3, dut.qsfp_0_tx_clk_3, dut.qsfp_0_tx_rst_3)
|
||||
|
||||
cocotb.fork(Clock(dut.qsfp_1_rx_clk_0, 6.4, units="ns").start())
|
||||
self.qsfp_1_0_source = XgmiiSource(dut.qsfp_1_rxd_0, dut.qsfp_1_rxc_0, dut.qsfp_1_rx_clk_0, dut.qsfp_1_rx_rst_0)
|
||||
cocotb.fork(Clock(dut.qsfp_1_tx_clk_0, 6.4, units="ns").start())
|
||||
self.qsfp_1_0_sink = XgmiiSink(dut.qsfp_1_txd_0, dut.qsfp_1_txc_0, dut.qsfp_1_tx_clk_0, dut.qsfp_1_tx_rst_0)
|
||||
|
||||
cocotb.fork(Clock(dut.qsfp_1_rx_clk_1, 6.4, units="ns").start())
|
||||
self.qsfp_1_1_source = XgmiiSource(dut.qsfp_1_rxd_1, dut.qsfp_1_rxc_1, dut.qsfp_1_rx_clk_1, dut.qsfp_1_rx_rst_1)
|
||||
cocotb.fork(Clock(dut.qsfp_1_tx_clk_1, 6.4, units="ns").start())
|
||||
self.qsfp_1_1_sink = XgmiiSink(dut.qsfp_1_txd_1, dut.qsfp_1_txc_1, dut.qsfp_1_tx_clk_1, dut.qsfp_1_tx_rst_1)
|
||||
|
||||
cocotb.fork(Clock(dut.qsfp_1_rx_clk_2, 6.4, units="ns").start())
|
||||
self.qsfp_1_2_source = XgmiiSource(dut.qsfp_1_rxd_2, dut.qsfp_1_rxc_2, dut.qsfp_1_rx_clk_2, dut.qsfp_1_rx_rst_2)
|
||||
cocotb.fork(Clock(dut.qsfp_1_tx_clk_2, 6.4, units="ns").start())
|
||||
self.qsfp_1_2_sink = XgmiiSink(dut.qsfp_1_txd_2, dut.qsfp_1_txc_2, dut.qsfp_1_tx_clk_2, dut.qsfp_1_tx_rst_2)
|
||||
|
||||
cocotb.fork(Clock(dut.qsfp_1_rx_clk_3, 6.4, units="ns").start())
|
||||
self.qsfp_1_3_source = XgmiiSource(dut.qsfp_1_rxd_3, dut.qsfp_1_rxc_3, dut.qsfp_1_rx_clk_3, dut.qsfp_1_rx_rst_3)
|
||||
cocotb.fork(Clock(dut.qsfp_1_tx_clk_3, 6.4, units="ns").start())
|
||||
self.qsfp_1_3_sink = XgmiiSink(dut.qsfp_1_txd_3, dut.qsfp_1_txc_3, dut.qsfp_1_tx_clk_3, dut.qsfp_1_tx_rst_3)
|
||||
|
||||
dut.user_sw.setimmediatevalue(0)
|
||||
|
||||
dut.qsfp_0_rx_error_count_0.setimmediatevalue(0)
|
||||
dut.qsfp_0_rx_error_count_1.setimmediatevalue(0)
|
||||
dut.qsfp_0_rx_error_count_2.setimmediatevalue(0)
|
||||
dut.qsfp_0_rx_error_count_3.setimmediatevalue(0)
|
||||
|
||||
dut.qsfp_1_rx_error_count_0.setimmediatevalue(0)
|
||||
dut.qsfp_1_rx_error_count_1.setimmediatevalue(0)
|
||||
dut.qsfp_1_rx_error_count_2.setimmediatevalue(0)
|
||||
dut.qsfp_1_rx_error_count_3.setimmediatevalue(0)
|
||||
|
||||
dut.qsfp_0_modprs_l.setimmediatevalue(0)
|
||||
dut.qsfp_1_modprs_l.setimmediatevalue(0)
|
||||
|
||||
dut.qsfp_int_l.setimmediatevalue(1)
|
||||
dut.qsfp_i2c_scl_i.setimmediatevalue(1)
|
||||
dut.qsfp_i2c_sda_i.setimmediatevalue(1)
|
||||
|
||||
dut.eeprom_i2c_scl_i.setimmediatevalue(1)
|
||||
dut.eeprom_i2c_sda_i.setimmediatevalue(1)
|
||||
|
||||
dut.qspi_0_dq_i.setimmediatevalue(0)
|
||||
dut.qspi_1_dq_i.setimmediatevalue(0)
|
||||
|
||||
self.loopback_enable = False
|
||||
cocotb.fork(self._run_loopback())
|
||||
|
||||
async def init(self):
|
||||
|
||||
self.dut.qsfp_0_rx_rst_0.setimmediatevalue(0)
|
||||
self.dut.qsfp_0_tx_rst_0.setimmediatevalue(0)
|
||||
self.dut.qsfp_0_rx_rst_1.setimmediatevalue(0)
|
||||
self.dut.qsfp_0_tx_rst_1.setimmediatevalue(0)
|
||||
self.dut.qsfp_0_rx_rst_2.setimmediatevalue(0)
|
||||
self.dut.qsfp_0_tx_rst_2.setimmediatevalue(0)
|
||||
self.dut.qsfp_0_rx_rst_3.setimmediatevalue(0)
|
||||
self.dut.qsfp_0_tx_rst_3.setimmediatevalue(0)
|
||||
self.dut.qsfp_1_rx_rst_0.setimmediatevalue(0)
|
||||
self.dut.qsfp_1_tx_rst_0.setimmediatevalue(0)
|
||||
self.dut.qsfp_1_rx_rst_1.setimmediatevalue(0)
|
||||
self.dut.qsfp_1_tx_rst_1.setimmediatevalue(0)
|
||||
self.dut.qsfp_1_rx_rst_2.setimmediatevalue(0)
|
||||
self.dut.qsfp_1_tx_rst_2.setimmediatevalue(0)
|
||||
self.dut.qsfp_1_rx_rst_3.setimmediatevalue(0)
|
||||
self.dut.qsfp_1_tx_rst_3.setimmediatevalue(0)
|
||||
|
||||
await RisingEdge(self.dut.clk_250mhz)
|
||||
await RisingEdge(self.dut.clk_250mhz)
|
||||
|
||||
self.dut.qsfp_0_rx_rst_0.setimmediatevalue(1)
|
||||
self.dut.qsfp_0_tx_rst_0.setimmediatevalue(1)
|
||||
self.dut.qsfp_0_rx_rst_1.setimmediatevalue(1)
|
||||
self.dut.qsfp_0_tx_rst_1.setimmediatevalue(1)
|
||||
self.dut.qsfp_0_rx_rst_2.setimmediatevalue(1)
|
||||
self.dut.qsfp_0_tx_rst_2.setimmediatevalue(1)
|
||||
self.dut.qsfp_0_rx_rst_3.setimmediatevalue(1)
|
||||
self.dut.qsfp_0_tx_rst_3.setimmediatevalue(1)
|
||||
self.dut.qsfp_1_rx_rst_0.setimmediatevalue(1)
|
||||
self.dut.qsfp_1_tx_rst_0.setimmediatevalue(1)
|
||||
self.dut.qsfp_1_rx_rst_1.setimmediatevalue(1)
|
||||
self.dut.qsfp_1_tx_rst_1.setimmediatevalue(1)
|
||||
self.dut.qsfp_1_rx_rst_2.setimmediatevalue(1)
|
||||
self.dut.qsfp_1_tx_rst_2.setimmediatevalue(1)
|
||||
self.dut.qsfp_1_rx_rst_3.setimmediatevalue(1)
|
||||
self.dut.qsfp_1_tx_rst_3.setimmediatevalue(1)
|
||||
|
||||
await FallingEdge(self.dut.rst_250mhz)
|
||||
await Timer(100, 'ns')
|
||||
|
||||
await RisingEdge(self.dut.clk_250mhz)
|
||||
await RisingEdge(self.dut.clk_250mhz)
|
||||
|
||||
self.dut.qsfp_0_rx_rst_0.setimmediatevalue(0)
|
||||
self.dut.qsfp_0_tx_rst_0.setimmediatevalue(0)
|
||||
self.dut.qsfp_0_rx_rst_1.setimmediatevalue(0)
|
||||
self.dut.qsfp_0_tx_rst_1.setimmediatevalue(0)
|
||||
self.dut.qsfp_0_rx_rst_2.setimmediatevalue(0)
|
||||
self.dut.qsfp_0_tx_rst_2.setimmediatevalue(0)
|
||||
self.dut.qsfp_0_rx_rst_3.setimmediatevalue(0)
|
||||
self.dut.qsfp_0_tx_rst_3.setimmediatevalue(0)
|
||||
self.dut.qsfp_1_rx_rst_0.setimmediatevalue(0)
|
||||
self.dut.qsfp_1_tx_rst_0.setimmediatevalue(0)
|
||||
self.dut.qsfp_1_rx_rst_1.setimmediatevalue(0)
|
||||
self.dut.qsfp_1_tx_rst_1.setimmediatevalue(0)
|
||||
self.dut.qsfp_1_rx_rst_2.setimmediatevalue(0)
|
||||
self.dut.qsfp_1_tx_rst_2.setimmediatevalue(0)
|
||||
self.dut.qsfp_1_rx_rst_3.setimmediatevalue(0)
|
||||
self.dut.qsfp_1_tx_rst_3.setimmediatevalue(0)
|
||||
|
||||
await self.rc.enumerate(enable_bus_mastering=True, configure_msi=True)
|
||||
|
||||
async def _run_loopback(self):
|
||||
while True:
|
||||
await RisingEdge(self.dut.clk_250mhz)
|
||||
|
||||
if self.loopback_enable:
|
||||
if not self.qsfp_0_0_sink.empty():
|
||||
self.qsfp_0_0_source.send(self.qsfp_0_0_sink.recv())
|
||||
if not self.qsfp_0_1_sink.empty():
|
||||
self.qsfp_0_1_source.send(self.qsfp_0_1_sink.recv())
|
||||
if not self.qsfp_0_2_sink.empty():
|
||||
self.qsfp_0_2_source.send(self.qsfp_0_2_sink.recv())
|
||||
if not self.qsfp_0_3_sink.empty():
|
||||
self.qsfp_0_3_source.send(self.qsfp_0_3_sink.recv())
|
||||
if not self.qsfp_1_0_sink.empty():
|
||||
self.qsfp_1_0_source.send(self.qsfp_1_0_sink.recv())
|
||||
if not self.qsfp_1_1_sink.empty():
|
||||
self.qsfp_1_1_source.send(self.qsfp_1_1_sink.recv())
|
||||
if not self.qsfp_1_2_sink.empty():
|
||||
self.qsfp_1_2_source.send(self.qsfp_1_2_sink.recv())
|
||||
if not self.qsfp_1_3_sink.empty():
|
||||
self.qsfp_1_3_source.send(self.qsfp_1_3_sink.recv())
|
||||
|
||||
|
||||
@cocotb.test()
|
||||
async def run_test_nic(dut):
|
||||
|
||||
tb = TB(dut)
|
||||
|
||||
await tb.init()
|
||||
|
||||
tb.log.info("Init driver")
|
||||
await tb.driver.init_dev(tb.dev.functions[0].pcie_id)
|
||||
await tb.driver.interfaces[0].open()
|
||||
# await driver.interfaces[1].open()
|
||||
|
||||
# enable queues
|
||||
tb.log.info("Enable queues")
|
||||
await tb.rc.mem_write_dword(tb.driver.interfaces[0].ports[0].hw_addr+mqnic.MQNIC_PORT_REG_SCHED_ENABLE, 0x00000001)
|
||||
for k in range(tb.driver.interfaces[0].tx_queue_count):
|
||||
await tb.rc.mem_write_dword(tb.driver.interfaces[0].ports[0].schedulers[0].hw_addr+4*k, 0x00000003)
|
||||
|
||||
# wait for all writes to complete
|
||||
await tb.rc.mem_read(tb.driver.hw_addr, 4)
|
||||
tb.log.info("Init complete")
|
||||
|
||||
tb.log.info("Send and receive single packet")
|
||||
|
||||
data = bytearray([x % 256 for x in range(1024)])
|
||||
|
||||
await tb.driver.interfaces[0].start_xmit(data, 0)
|
||||
|
||||
await tb.qsfp_0_0_sink.wait()
|
||||
|
||||
pkt = tb.qsfp_0_0_sink.recv()
|
||||
tb.log.info("Packet: %s", pkt)
|
||||
|
||||
tb.qsfp_0_0_source.send(pkt)
|
||||
|
||||
await tb.driver.interfaces[0].wait()
|
||||
|
||||
pkt = tb.driver.interfaces[0].recv()
|
||||
|
||||
tb.log.info("Packet: %s", pkt)
|
||||
assert pkt.rx_checksum == ~scapy.utils.checksum(bytes(pkt.data[14:])) & 0xffff
|
||||
|
||||
# await tb.driver.interfaces[1].start_xmit(data, 0)
|
||||
|
||||
# await tb.qsfp_1_0_sink.wait()
|
||||
|
||||
# pkt = tb.qsfp_1_0_sink.recv()
|
||||
# tb.log.info("Packet: %s", pkt)
|
||||
|
||||
# tb.qsfp_1_0_source.send(pkt)
|
||||
|
||||
# await tb.driver.interfaces[1].wait()
|
||||
|
||||
# pkt = tb.driver.interfaces[1].recv()
|
||||
|
||||
# tb.log.info("Packet: %s", pkt)
|
||||
# assert pkt.rx_checksum == ~scapy.utils.checksum(bytes(pkt.data[14:])) & 0xffff
|
||||
|
||||
tb.log.info("RX and TX checksum tests")
|
||||
|
||||
payload = bytes([x % 256 for x in range(256)])
|
||||
eth = Ether(src='5A:51:52:53:54:55', dst='DA:D1:D2:D3:D4:D5')
|
||||
ip = IP(src='192.168.1.100', dst='192.168.1.101')
|
||||
udp = UDP(sport=1, dport=2)
|
||||
test_pkt = eth / ip / udp / payload
|
||||
|
||||
test_pkt2 = test_pkt.copy()
|
||||
test_pkt2[UDP].chksum = scapy.utils.checksum(bytes(test_pkt2[UDP]))
|
||||
|
||||
await tb.driver.interfaces[0].start_xmit(test_pkt2.build(), 0, 34, 6)
|
||||
|
||||
await tb.qsfp_0_0_sink.wait()
|
||||
|
||||
pkt = tb.qsfp_0_0_sink.recv()
|
||||
tb.log.info("Packet: %s", pkt)
|
||||
|
||||
tb.qsfp_0_0_source.send(pkt)
|
||||
|
||||
await tb.driver.interfaces[0].wait()
|
||||
|
||||
pkt = tb.driver.interfaces[0].recv()
|
||||
|
||||
tb.log.info("Packet: %s", pkt)
|
||||
assert pkt.rx_checksum == ~scapy.utils.checksum(bytes(pkt.data[14:])) & 0xffff
|
||||
assert Ether(pkt.data).build() == test_pkt.build()
|
||||
|
||||
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 tb.driver.interfaces[0].start_xmit(p, 0)
|
||||
|
||||
for k in range(count):
|
||||
await tb.driver.interfaces[0].wait()
|
||||
pkt = tb.driver.interfaces[0].recv()
|
||||
|
||||
tb.log.info("Packet: %s", pkt)
|
||||
assert pkt.data == pkts[k]
|
||||
assert pkt.rx_checksum == ~scapy.utils.checksum(bytes(pkt.data[14:])) & 0xffff
|
||||
|
||||
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 tb.driver.interfaces[0].start_xmit(p, 0)
|
||||
|
||||
for k in range(count):
|
||||
await tb.driver.interfaces[0].wait()
|
||||
pkt = tb.driver.interfaces[0].recv()
|
||||
|
||||
tb.log.info("Packet: %s", pkt)
|
||||
assert pkt.data == pkts[k]
|
||||
assert pkt.rx_checksum == ~scapy.utils.checksum(bytes(pkt.data[14:])) & 0xffff
|
||||
|
||||
tb.loopback_enable = False
|
||||
|
||||
await RisingEdge(dut.clk_250mhz)
|
||||
await RisingEdge(dut.clk_250mhz)
|
||||
|
||||
|
||||
# cocotb-test
|
||||
|
||||
tests_dir = os.path.dirname(__file__)
|
||||
rtl_dir = os.path.abspath(os.path.join(tests_dir, '..', '..', 'rtl'))
|
||||
lib_dir = os.path.abspath(os.path.join(rtl_dir, '..', 'lib'))
|
||||
axi_rtl_dir = os.path.abspath(os.path.join(lib_dir, 'axi', 'rtl'))
|
||||
axis_rtl_dir = os.path.abspath(os.path.join(lib_dir, 'axis', 'rtl'))
|
||||
eth_rtl_dir = os.path.abspath(os.path.join(lib_dir, 'eth', 'rtl'))
|
||||
pcie_rtl_dir = os.path.abspath(os.path.join(lib_dir, 'pcie', 'rtl'))
|
||||
|
||||
|
||||
def test_fpga_core(request):
|
||||
dut = "fpga_core"
|
||||
module = os.path.splitext(os.path.basename(__file__))[0]
|
||||
toplevel = dut
|
||||
|
||||
verilog_sources = [
|
||||
os.path.join(rtl_dir, f"{dut}.v"),
|
||||
os.path.join(rtl_dir, "common", "mqnic_interface.v"),
|
||||
os.path.join(rtl_dir, "common", "mqnic_port.v"),
|
||||
os.path.join(rtl_dir, "common", "cpl_write.v"),
|
||||
os.path.join(rtl_dir, "common", "cpl_op_mux.v"),
|
||||
os.path.join(rtl_dir, "common", "desc_fetch.v"),
|
||||
os.path.join(rtl_dir, "common", "desc_op_mux.v"),
|
||||
os.path.join(rtl_dir, "common", "queue_manager.v"),
|
||||
os.path.join(rtl_dir, "common", "cpl_queue_manager.v"),
|
||||
os.path.join(rtl_dir, "common", "tx_engine.v"),
|
||||
os.path.join(rtl_dir, "common", "rx_engine.v"),
|
||||
os.path.join(rtl_dir, "common", "tx_checksum.v"),
|
||||
os.path.join(rtl_dir, "common", "rx_hash.v"),
|
||||
os.path.join(rtl_dir, "common", "rx_checksum.v"),
|
||||
os.path.join(rtl_dir, "common", "tx_scheduler_rr.v"),
|
||||
os.path.join(rtl_dir, "common", "event_mux.v"),
|
||||
os.path.join(rtl_dir, "common", "tdma_scheduler.v"),
|
||||
os.path.join(rtl_dir, "common", "tdma_ber.v"),
|
||||
os.path.join(rtl_dir, "common", "tdma_ber_ch.v"),
|
||||
os.path.join(eth_rtl_dir, "eth_mac_10g_fifo.v"),
|
||||
os.path.join(eth_rtl_dir, "eth_mac_10g.v"),
|
||||
os.path.join(eth_rtl_dir, "axis_xgmii_rx_64.v"),
|
||||
os.path.join(eth_rtl_dir, "axis_xgmii_tx_64.v"),
|
||||
os.path.join(eth_rtl_dir, "lfsr.v"),
|
||||
os.path.join(eth_rtl_dir, "ptp_clock.v"),
|
||||
os.path.join(eth_rtl_dir, "ptp_clock_cdc.v"),
|
||||
os.path.join(eth_rtl_dir, "ptp_perout.v"),
|
||||
os.path.join(eth_rtl_dir, "ptp_ts_extract.v"),
|
||||
os.path.join(axi_rtl_dir, "axil_interconnect.v"),
|
||||
os.path.join(axi_rtl_dir, "arbiter.v"),
|
||||
os.path.join(axi_rtl_dir, "priority_encoder.v"),
|
||||
os.path.join(axis_rtl_dir, "axis_adapter.v"),
|
||||
os.path.join(axis_rtl_dir, "axis_arb_mux.v"),
|
||||
os.path.join(axis_rtl_dir, "axis_async_fifo.v"),
|
||||
os.path.join(axis_rtl_dir, "axis_async_fifo_adapter.v"),
|
||||
os.path.join(axis_rtl_dir, "axis_fifo.v"),
|
||||
os.path.join(axis_rtl_dir, "axis_register.v"),
|
||||
os.path.join(pcie_rtl_dir, "pcie_us_axil_master.v"),
|
||||
os.path.join(pcie_rtl_dir, "dma_if_pcie_us.v"),
|
||||
os.path.join(pcie_rtl_dir, "dma_if_pcie_us_rd.v"),
|
||||
os.path.join(pcie_rtl_dir, "dma_if_pcie_us_wr.v"),
|
||||
os.path.join(pcie_rtl_dir, "dma_if_mux.v"),
|
||||
os.path.join(pcie_rtl_dir, "dma_if_mux_rd.v"),
|
||||
os.path.join(pcie_rtl_dir, "dma_if_mux_wr.v"),
|
||||
os.path.join(pcie_rtl_dir, "dma_psdpram.v"),
|
||||
os.path.join(pcie_rtl_dir, "dma_client_axis_sink.v"),
|
||||
os.path.join(pcie_rtl_dir, "dma_client_axis_source.v"),
|
||||
os.path.join(pcie_rtl_dir, "pcie_us_cfg.v"),
|
||||
os.path.join(pcie_rtl_dir, "pcie_us_msi.v"),
|
||||
os.path.join(pcie_rtl_dir, "pcie_tag_manager.v"),
|
||||
os.path.join(pcie_rtl_dir, "pulse_merge.v"),
|
||||
]
|
||||
|
||||
parameters = {}
|
||||
|
||||
parameters['AXIS_PCIE_DATA_WIDTH'] = 512
|
||||
parameters['AXIS_PCIE_KEEP_WIDTH'] = int(parameters['AXIS_PCIE_DATA_WIDTH']/32)
|
||||
parameters['AXIS_PCIE_RQ_USER_WIDTH'] = 62 if parameters['AXIS_PCIE_DATA_WIDTH'] < 512 else 137
|
||||
parameters['AXIS_PCIE_RC_USER_WIDTH'] = 75 if parameters['AXIS_PCIE_DATA_WIDTH'] < 512 else 161
|
||||
parameters['AXIS_PCIE_CQ_USER_WIDTH'] = 88 if parameters['AXIS_PCIE_DATA_WIDTH'] < 512 else 183
|
||||
parameters['AXIS_PCIE_CC_USER_WIDTH'] = 33 if parameters['AXIS_PCIE_DATA_WIDTH'] < 512 else 81
|
||||
parameters['RQ_SEQ_NUM_WIDTH'] = 6
|
||||
parameters['BAR0_APERTURE'] = 24
|
||||
|
||||
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(
|
||||
python_search=[tests_dir],
|
||||
verilog_sources=verilog_sources,
|
||||
toplevel=toplevel,
|
||||
module=module,
|
||||
parameters=parameters,
|
||||
sim_build=sim_build,
|
||||
extra_env=extra_env,
|
||||
)
|
@ -1 +0,0 @@
|
||||
../lib/eth/tb/ip_ep.py
|
@ -1 +0,0 @@
|
||||
../../../../common/tb/mqnic.py
|
@ -1 +0,0 @@
|
||||
../lib/pcie/tb/pcie.py
|
@ -1 +0,0 @@
|
||||
../lib/pcie/tb/pcie_us.py
|
@ -1 +0,0 @@
|
||||
../lib/pcie/tb/pcie_usp.py
|
File diff suppressed because it is too large
Load Diff
@ -1,579 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright 2019, The Regents of the University of California.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
|
||||
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of The Regents of the University of California.
|
||||
|
||||
*/
|
||||
|
||||
// Language: Verilog 2001
|
||||
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
/*
|
||||
* Testbench for fpga_core
|
||||
*/
|
||||
module test_fpga_core;
|
||||
|
||||
// Parameters
|
||||
parameter AXIS_PCIE_DATA_WIDTH = 512;
|
||||
parameter AXIS_PCIE_KEEP_WIDTH = (AXIS_PCIE_DATA_WIDTH/32);
|
||||
parameter AXIS_PCIE_RC_USER_WIDTH = 161;
|
||||
parameter AXIS_PCIE_RQ_USER_WIDTH = 137;
|
||||
parameter AXIS_PCIE_CQ_USER_WIDTH = 183;
|
||||
parameter AXIS_PCIE_CC_USER_WIDTH = 81;
|
||||
parameter RQ_SEQ_NUM_WIDTH = 6;
|
||||
parameter BAR0_APERTURE = 24;
|
||||
|
||||
// Inputs
|
||||
reg clk = 0;
|
||||
reg rst = 0;
|
||||
reg [7:0] current_test = 0;
|
||||
|
||||
reg clk_250mhz = 0;
|
||||
reg rst_250mhz = 0;
|
||||
reg [1:0] user_sw = 0;
|
||||
reg m_axis_rq_tready = 0;
|
||||
reg [AXIS_PCIE_DATA_WIDTH-1:0] s_axis_rc_tdata = 0;
|
||||
reg [AXIS_PCIE_KEEP_WIDTH-1:0] s_axis_rc_tkeep = 0;
|
||||
reg s_axis_rc_tlast = 0;
|
||||
reg [AXIS_PCIE_RC_USER_WIDTH-1:0] s_axis_rc_tuser = 0;
|
||||
reg s_axis_rc_tvalid = 0;
|
||||
reg [AXIS_PCIE_DATA_WIDTH-1:0] s_axis_cq_tdata = 0;
|
||||
reg [AXIS_PCIE_KEEP_WIDTH-1:0] s_axis_cq_tkeep = 0;
|
||||
reg s_axis_cq_tlast = 0;
|
||||
reg [AXIS_PCIE_CQ_USER_WIDTH-1:0] s_axis_cq_tuser = 0;
|
||||
reg s_axis_cq_tvalid = 0;
|
||||
reg m_axis_cc_tready = 0;
|
||||
reg [RQ_SEQ_NUM_WIDTH-1:0] s_axis_rq_seq_num_0 = 0;
|
||||
reg s_axis_rq_seq_num_valid_0 = 0;
|
||||
reg [RQ_SEQ_NUM_WIDTH-1:0] s_axis_rq_seq_num_1 = 0;
|
||||
reg s_axis_rq_seq_num_valid_1 = 0;
|
||||
reg [3:0] pcie_tfc_nph_av = 0;
|
||||
reg [3:0] pcie_tfc_npd_av = 0;
|
||||
reg [2:0] cfg_max_payload = 0;
|
||||
reg [2:0] cfg_max_read_req = 0;
|
||||
reg [31:0] cfg_mgmt_read_data = 0;
|
||||
reg cfg_mgmt_read_write_done = 0;
|
||||
reg [7:0] cfg_fc_ph = 0;
|
||||
reg [11:0] cfg_fc_pd = 0;
|
||||
reg [7:0] cfg_fc_nph = 0;
|
||||
reg [11:0] cfg_fc_npd = 0;
|
||||
reg [7:0] cfg_fc_cplh = 0;
|
||||
reg [11:0] cfg_fc_cpld = 0;
|
||||
reg [3:0] cfg_interrupt_msi_enable = 0;
|
||||
reg [11:0] cfg_interrupt_msi_mmenable = 0;
|
||||
reg cfg_interrupt_msi_mask_update = 0;
|
||||
reg [31:0] cfg_interrupt_msi_data = 0;
|
||||
reg cfg_interrupt_msi_sent = 0;
|
||||
reg cfg_interrupt_msi_fail = 0;
|
||||
reg qsfp_0_tx_clk_0 = 0;
|
||||
reg qsfp_0_tx_rst_0 = 0;
|
||||
reg qsfp_0_rx_clk_0 = 0;
|
||||
reg qsfp_0_rx_rst_0 = 0;
|
||||
reg [63:0] qsfp_0_rxd_0 = 0;
|
||||
reg [7:0] qsfp_0_rxc_0 = 0;
|
||||
reg qsfp_0_tx_clk_1 = 0;
|
||||
reg qsfp_0_tx_rst_1 = 0;
|
||||
reg qsfp_0_rx_clk_1 = 0;
|
||||
reg qsfp_0_rx_rst_1 = 0;
|
||||
reg [63:0] qsfp_0_rxd_1 = 0;
|
||||
reg [7:0] qsfp_0_rxc_1 = 0;
|
||||
reg qsfp_0_tx_clk_2 = 0;
|
||||
reg qsfp_0_tx_rst_2 = 0;
|
||||
reg qsfp_0_rx_clk_2 = 0;
|
||||
reg qsfp_0_rx_rst_2 = 0;
|
||||
reg [63:0] qsfp_0_rxd_2 = 0;
|
||||
reg [7:0] qsfp_0_rxc_2 = 0;
|
||||
reg qsfp_0_tx_clk_3 = 0;
|
||||
reg qsfp_0_tx_rst_3 = 0;
|
||||
reg qsfp_0_rx_clk_3 = 0;
|
||||
reg qsfp_0_rx_rst_3 = 0;
|
||||
reg [63:0] qsfp_0_rxd_3 = 0;
|
||||
reg [7:0] qsfp_0_rxc_3 = 0;
|
||||
reg qsfp_0_modprs_l = 0;
|
||||
reg qsfp_1_tx_clk_0 = 0;
|
||||
reg qsfp_1_tx_rst_0 = 0;
|
||||
reg qsfp_1_rx_clk_0 = 0;
|
||||
reg qsfp_1_rx_rst_0 = 0;
|
||||
reg [63:0] qsfp_1_rxd_0 = 0;
|
||||
reg [7:0] qsfp_1_rxc_0 = 0;
|
||||
reg qsfp_1_tx_clk_1 = 0;
|
||||
reg qsfp_1_tx_rst_1 = 0;
|
||||
reg qsfp_1_rx_clk_1 = 0;
|
||||
reg qsfp_1_rx_rst_1 = 0;
|
||||
reg [63:0] qsfp_1_rxd_1 = 0;
|
||||
reg [7:0] qsfp_1_rxc_1 = 0;
|
||||
reg qsfp_1_tx_clk_2 = 0;
|
||||
reg qsfp_1_tx_rst_2 = 0;
|
||||
reg qsfp_1_rx_clk_2 = 0;
|
||||
reg qsfp_1_rx_rst_2 = 0;
|
||||
reg [63:0] qsfp_1_rxd_2 = 0;
|
||||
reg [7:0] qsfp_1_rxc_2 = 0;
|
||||
reg qsfp_1_tx_clk_3 = 0;
|
||||
reg qsfp_1_tx_rst_3 = 0;
|
||||
reg qsfp_1_rx_clk_3 = 0;
|
||||
reg qsfp_1_rx_rst_3 = 0;
|
||||
reg [63:0] qsfp_1_rxd_3 = 0;
|
||||
reg [7:0] qsfp_1_rxc_3 = 0;
|
||||
reg qsfp_1_modprs_l = 0;
|
||||
reg qsfp_int_l = 0;
|
||||
reg qsfp_i2c_scl_i = 1;
|
||||
reg qsfp_i2c_sda_i = 1;
|
||||
reg eeprom_i2c_scl_i = 1;
|
||||
reg eeprom_i2c_sda_i = 1;
|
||||
reg [3:0] qspi_0_dq_i = 0;
|
||||
reg [3:0] qspi_1_dq_i = 0;
|
||||
|
||||
// Outputs
|
||||
wire [1:0] user_led_g;
|
||||
wire user_led_r;
|
||||
wire [1:0] front_led;
|
||||
wire [AXIS_PCIE_DATA_WIDTH-1:0] m_axis_rq_tdata;
|
||||
wire [AXIS_PCIE_KEEP_WIDTH-1:0] m_axis_rq_tkeep;
|
||||
wire m_axis_rq_tlast;
|
||||
wire [AXIS_PCIE_RQ_USER_WIDTH-1:0] m_axis_rq_tuser;
|
||||
wire m_axis_rq_tvalid;
|
||||
wire s_axis_rc_tready;
|
||||
wire s_axis_cq_tready;
|
||||
wire [AXIS_PCIE_DATA_WIDTH-1:0] m_axis_cc_tdata;
|
||||
wire [AXIS_PCIE_KEEP_WIDTH-1:0] m_axis_cc_tkeep;
|
||||
wire m_axis_cc_tlast;
|
||||
wire [AXIS_PCIE_CC_USER_WIDTH-1:0] m_axis_cc_tuser;
|
||||
wire m_axis_cc_tvalid;
|
||||
wire [9:0] cfg_mgmt_addr;
|
||||
wire [7:0] cfg_mgmt_function_number;
|
||||
wire cfg_mgmt_write;
|
||||
wire [31:0] cfg_mgmt_write_data;
|
||||
wire [3:0] cfg_mgmt_byte_enable;
|
||||
wire cfg_mgmt_read;
|
||||
wire [2:0] cfg_fc_sel;
|
||||
wire [3:0] cfg_interrupt_msi_select;
|
||||
wire [31:0] cfg_interrupt_msi_int;
|
||||
wire [31:0] cfg_interrupt_msi_pending_status;
|
||||
wire cfg_interrupt_msi_pending_status_data_enable;
|
||||
wire [3:0] cfg_interrupt_msi_pending_status_function_num;
|
||||
wire [2:0] cfg_interrupt_msi_attr;
|
||||
wire cfg_interrupt_msi_tph_present;
|
||||
wire [1:0] cfg_interrupt_msi_tph_type;
|
||||
wire [8:0] cfg_interrupt_msi_tph_st_tag;
|
||||
wire [3:0] cfg_interrupt_msi_function_number;
|
||||
wire status_error_cor;
|
||||
wire status_error_uncor;
|
||||
wire [63:0] qsfp_0_txd_0;
|
||||
wire [7:0] qsfp_0_txc_0;
|
||||
wire [63:0] qsfp_0_txd_1;
|
||||
wire [7:0] qsfp_0_txc_1;
|
||||
wire [63:0] qsfp_0_txd_2;
|
||||
wire [7:0] qsfp_0_txc_2;
|
||||
wire [63:0] qsfp_0_txd_3;
|
||||
wire [7:0] qsfp_0_txc_3;
|
||||
wire qsfp_0_sel_l;
|
||||
wire [63:0] qsfp_1_txd_0;
|
||||
wire [7:0] qsfp_1_txc_0;
|
||||
wire [63:0] qsfp_1_txd_1;
|
||||
wire [7:0] qsfp_1_txc_1;
|
||||
wire [63:0] qsfp_1_txd_2;
|
||||
wire [7:0] qsfp_1_txc_2;
|
||||
wire [63:0] qsfp_1_txd_3;
|
||||
wire [7:0] qsfp_1_txc_3;
|
||||
wire qsfp_1_sel_l;
|
||||
wire qsfp_reset_l;
|
||||
wire qsfp_i2c_scl_o;
|
||||
wire qsfp_i2c_scl_t;
|
||||
wire qsfp_i2c_sda_o;
|
||||
wire qsfp_i2c_sda_t;
|
||||
wire eeprom_i2c_scl_o;
|
||||
wire eeprom_i2c_scl_t;
|
||||
wire eeprom_i2c_sda_o;
|
||||
wire eeprom_i2c_sda_t;
|
||||
wire eeprom_wp;
|
||||
wire fpga_boot;
|
||||
wire qspi_clk;
|
||||
wire [3:0] qspi_0_dq_o;
|
||||
wire [3:0] qspi_0_dq_oe;
|
||||
wire qspi_0_cs;
|
||||
wire [3:0] qspi_1_dq_o;
|
||||
wire [3:0] qspi_1_dq_oe;
|
||||
wire qspi_1_cs;
|
||||
|
||||
initial begin
|
||||
// myhdl integration
|
||||
$from_myhdl(
|
||||
clk_250mhz,
|
||||
rst_250mhz,
|
||||
current_test,
|
||||
user_sw,
|
||||
m_axis_rq_tready,
|
||||
s_axis_rc_tdata,
|
||||
s_axis_rc_tkeep,
|
||||
s_axis_rc_tlast,
|
||||
s_axis_rc_tuser,
|
||||
s_axis_rc_tvalid,
|
||||
s_axis_cq_tdata,
|
||||
s_axis_cq_tkeep,
|
||||
s_axis_cq_tlast,
|
||||
s_axis_cq_tuser,
|
||||
s_axis_cq_tvalid,
|
||||
m_axis_cc_tready,
|
||||
s_axis_rq_seq_num_0,
|
||||
s_axis_rq_seq_num_valid_0,
|
||||
s_axis_rq_seq_num_1,
|
||||
s_axis_rq_seq_num_valid_1,
|
||||
pcie_tfc_nph_av,
|
||||
pcie_tfc_npd_av,
|
||||
cfg_max_payload,
|
||||
cfg_max_read_req,
|
||||
cfg_mgmt_read_data,
|
||||
cfg_mgmt_read_write_done,
|
||||
cfg_fc_ph,
|
||||
cfg_fc_pd,
|
||||
cfg_fc_nph,
|
||||
cfg_fc_npd,
|
||||
cfg_fc_cplh,
|
||||
cfg_fc_cpld,
|
||||
cfg_interrupt_msi_enable,
|
||||
cfg_interrupt_msi_mmenable,
|
||||
cfg_interrupt_msi_mask_update,
|
||||
cfg_interrupt_msi_data,
|
||||
cfg_interrupt_msi_sent,
|
||||
cfg_interrupt_msi_fail,
|
||||
qsfp_0_tx_clk_0,
|
||||
qsfp_0_tx_rst_0,
|
||||
qsfp_0_rx_clk_0,
|
||||
qsfp_0_rx_rst_0,
|
||||
qsfp_0_rxd_0,
|
||||
qsfp_0_rxc_0,
|
||||
qsfp_0_tx_clk_1,
|
||||
qsfp_0_tx_rst_1,
|
||||
qsfp_0_rx_clk_1,
|
||||
qsfp_0_rx_rst_1,
|
||||
qsfp_0_rxd_1,
|
||||
qsfp_0_rxc_1,
|
||||
qsfp_0_tx_clk_2,
|
||||
qsfp_0_tx_rst_2,
|
||||
qsfp_0_rx_clk_2,
|
||||
qsfp_0_rx_rst_2,
|
||||
qsfp_0_rxd_2,
|
||||
qsfp_0_rxc_2,
|
||||
qsfp_0_tx_clk_3,
|
||||
qsfp_0_tx_rst_3,
|
||||
qsfp_0_rx_clk_3,
|
||||
qsfp_0_rx_rst_3,
|
||||
qsfp_0_rxd_3,
|
||||
qsfp_0_rxc_3,
|
||||
qsfp_0_modprs_l,
|
||||
qsfp_1_tx_clk_0,
|
||||
qsfp_1_tx_rst_0,
|
||||
qsfp_1_rx_clk_0,
|
||||
qsfp_1_rx_rst_0,
|
||||
qsfp_1_rxd_0,
|
||||
qsfp_1_rxc_0,
|
||||
qsfp_1_tx_clk_1,
|
||||
qsfp_1_tx_rst_1,
|
||||
qsfp_1_rx_clk_1,
|
||||
qsfp_1_rx_rst_1,
|
||||
qsfp_1_rxd_1,
|
||||
qsfp_1_rxc_1,
|
||||
qsfp_1_tx_clk_2,
|
||||
qsfp_1_tx_rst_2,
|
||||
qsfp_1_rx_clk_2,
|
||||
qsfp_1_rx_rst_2,
|
||||
qsfp_1_rxd_2,
|
||||
qsfp_1_rxc_2,
|
||||
qsfp_1_tx_clk_3,
|
||||
qsfp_1_tx_rst_3,
|
||||
qsfp_1_rx_clk_3,
|
||||
qsfp_1_rx_rst_3,
|
||||
qsfp_1_rxd_3,
|
||||
qsfp_1_rxc_3,
|
||||
qsfp_1_modprs_l,
|
||||
qsfp_int_l,
|
||||
qsfp_i2c_scl_i,
|
||||
qsfp_i2c_sda_i,
|
||||
eeprom_i2c_scl_i,
|
||||
eeprom_i2c_sda_i,
|
||||
qspi_0_dq_i,
|
||||
qspi_1_dq_i
|
||||
);
|
||||
$to_myhdl(
|
||||
user_led_g,
|
||||
user_led_r,
|
||||
front_led,
|
||||
m_axis_rq_tdata,
|
||||
m_axis_rq_tkeep,
|
||||
m_axis_rq_tlast,
|
||||
m_axis_rq_tuser,
|
||||
m_axis_rq_tvalid,
|
||||
s_axis_rc_tready,
|
||||
s_axis_cq_tready,
|
||||
m_axis_cc_tdata,
|
||||
m_axis_cc_tkeep,
|
||||
m_axis_cc_tlast,
|
||||
m_axis_cc_tuser,
|
||||
m_axis_cc_tvalid,
|
||||
cfg_mgmt_addr,
|
||||
cfg_mgmt_function_number,
|
||||
cfg_mgmt_write,
|
||||
cfg_mgmt_write_data,
|
||||
cfg_mgmt_byte_enable,
|
||||
cfg_mgmt_read,
|
||||
cfg_fc_sel,
|
||||
cfg_interrupt_msi_select,
|
||||
cfg_interrupt_msi_int,
|
||||
cfg_interrupt_msi_pending_status,
|
||||
cfg_interrupt_msi_pending_status_data_enable,
|
||||
cfg_interrupt_msi_pending_status_function_num,
|
||||
cfg_interrupt_msi_attr,
|
||||
cfg_interrupt_msi_tph_present,
|
||||
cfg_interrupt_msi_tph_type,
|
||||
cfg_interrupt_msi_tph_st_tag,
|
||||
cfg_interrupt_msi_function_number,
|
||||
status_error_cor,
|
||||
status_error_uncor,
|
||||
qsfp_0_txd_0,
|
||||
qsfp_0_txc_0,
|
||||
qsfp_0_txd_1,
|
||||
qsfp_0_txc_1,
|
||||
qsfp_0_txd_2,
|
||||
qsfp_0_txc_2,
|
||||
qsfp_0_txd_3,
|
||||
qsfp_0_txc_3,
|
||||
qsfp_0_sel_l,
|
||||
qsfp_1_txd_0,
|
||||
qsfp_1_txc_0,
|
||||
qsfp_1_txd_1,
|
||||
qsfp_1_txc_1,
|
||||
qsfp_1_txd_2,
|
||||
qsfp_1_txc_2,
|
||||
qsfp_1_txd_3,
|
||||
qsfp_1_txc_3,
|
||||
qsfp_1_sel_l,
|
||||
qsfp_reset_l,
|
||||
qsfp_i2c_scl_o,
|
||||
qsfp_i2c_scl_t,
|
||||
qsfp_i2c_sda_o,
|
||||
qsfp_i2c_sda_t,
|
||||
eeprom_i2c_scl_o,
|
||||
eeprom_i2c_scl_t,
|
||||
eeprom_i2c_sda_o,
|
||||
eeprom_i2c_sda_t,
|
||||
eeprom_wp,
|
||||
fpga_boot,
|
||||
qspi_clk,
|
||||
qspi_0_dq_o,
|
||||
qspi_0_dq_oe,
|
||||
qspi_0_cs,
|
||||
qspi_1_dq_o,
|
||||
qspi_1_dq_oe,
|
||||
qspi_1_cs
|
||||
);
|
||||
|
||||
// dump file
|
||||
$dumpfile("test_fpga_core.lxt");
|
||||
$dumpvars(0, test_fpga_core);
|
||||
end
|
||||
|
||||
fpga_core #(
|
||||
.AXIS_PCIE_DATA_WIDTH(AXIS_PCIE_DATA_WIDTH),
|
||||
.AXIS_PCIE_KEEP_WIDTH(AXIS_PCIE_KEEP_WIDTH),
|
||||
.AXIS_PCIE_RC_USER_WIDTH(AXIS_PCIE_RC_USER_WIDTH),
|
||||
.AXIS_PCIE_RQ_USER_WIDTH(AXIS_PCIE_RQ_USER_WIDTH),
|
||||
.AXIS_PCIE_CQ_USER_WIDTH(AXIS_PCIE_CQ_USER_WIDTH),
|
||||
.AXIS_PCIE_CC_USER_WIDTH(AXIS_PCIE_CC_USER_WIDTH),
|
||||
.RQ_SEQ_NUM_WIDTH(RQ_SEQ_NUM_WIDTH),
|
||||
.BAR0_APERTURE(BAR0_APERTURE)
|
||||
)
|
||||
UUT (
|
||||
.clk_250mhz(clk_250mhz),
|
||||
.rst_250mhz(rst_250mhz),
|
||||
.user_led_g(user_led_g),
|
||||
.user_led_r(user_led_r),
|
||||
.front_led(front_led),
|
||||
.user_sw(user_sw),
|
||||
.m_axis_rq_tdata(m_axis_rq_tdata),
|
||||
.m_axis_rq_tkeep(m_axis_rq_tkeep),
|
||||
.m_axis_rq_tlast(m_axis_rq_tlast),
|
||||
.m_axis_rq_tready(m_axis_rq_tready),
|
||||
.m_axis_rq_tuser(m_axis_rq_tuser),
|
||||
.m_axis_rq_tvalid(m_axis_rq_tvalid),
|
||||
.s_axis_rc_tdata(s_axis_rc_tdata),
|
||||
.s_axis_rc_tkeep(s_axis_rc_tkeep),
|
||||
.s_axis_rc_tlast(s_axis_rc_tlast),
|
||||
.s_axis_rc_tready(s_axis_rc_tready),
|
||||
.s_axis_rc_tuser(s_axis_rc_tuser),
|
||||
.s_axis_rc_tvalid(s_axis_rc_tvalid),
|
||||
.s_axis_cq_tdata(s_axis_cq_tdata),
|
||||
.s_axis_cq_tkeep(s_axis_cq_tkeep),
|
||||
.s_axis_cq_tlast(s_axis_cq_tlast),
|
||||
.s_axis_cq_tready(s_axis_cq_tready),
|
||||
.s_axis_cq_tuser(s_axis_cq_tuser),
|
||||
.s_axis_cq_tvalid(s_axis_cq_tvalid),
|
||||
.m_axis_cc_tdata(m_axis_cc_tdata),
|
||||
.m_axis_cc_tkeep(m_axis_cc_tkeep),
|
||||
.m_axis_cc_tlast(m_axis_cc_tlast),
|
||||
.m_axis_cc_tready(m_axis_cc_tready),
|
||||
.m_axis_cc_tuser(m_axis_cc_tuser),
|
||||
.m_axis_cc_tvalid(m_axis_cc_tvalid),
|
||||
.s_axis_rq_seq_num_0(s_axis_rq_seq_num_0),
|
||||
.s_axis_rq_seq_num_valid_0(s_axis_rq_seq_num_valid_0),
|
||||
.s_axis_rq_seq_num_1(s_axis_rq_seq_num_1),
|
||||
.s_axis_rq_seq_num_valid_1(s_axis_rq_seq_num_valid_1),
|
||||
.pcie_tfc_nph_av(pcie_tfc_nph_av),
|
||||
.pcie_tfc_npd_av(pcie_tfc_npd_av),
|
||||
.cfg_max_payload(cfg_max_payload),
|
||||
.cfg_max_read_req(cfg_max_read_req),
|
||||
.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),
|
||||
.status_error_cor(status_error_cor),
|
||||
.status_error_uncor(status_error_uncor),
|
||||
.qsfp_0_tx_clk_0(qsfp_0_tx_clk_0),
|
||||
.qsfp_0_tx_rst_0(qsfp_0_tx_rst_0),
|
||||
.qsfp_0_txd_0(qsfp_0_txd_0),
|
||||
.qsfp_0_txc_0(qsfp_0_txc_0),
|
||||
.qsfp_0_rx_clk_0(qsfp_0_rx_clk_0),
|
||||
.qsfp_0_rx_rst_0(qsfp_0_rx_rst_0),
|
||||
.qsfp_0_rxd_0(qsfp_0_rxd_0),
|
||||
.qsfp_0_rxc_0(qsfp_0_rxc_0),
|
||||
.qsfp_0_tx_clk_1(qsfp_0_tx_clk_1),
|
||||
.qsfp_0_tx_rst_1(qsfp_0_tx_rst_1),
|
||||
.qsfp_0_txd_1(qsfp_0_txd_1),
|
||||
.qsfp_0_txc_1(qsfp_0_txc_1),
|
||||
.qsfp_0_rx_clk_1(qsfp_0_rx_clk_1),
|
||||
.qsfp_0_rx_rst_1(qsfp_0_rx_rst_1),
|
||||
.qsfp_0_rxd_1(qsfp_0_rxd_1),
|
||||
.qsfp_0_rxc_1(qsfp_0_rxc_1),
|
||||
.qsfp_0_tx_clk_2(qsfp_0_tx_clk_2),
|
||||
.qsfp_0_tx_rst_2(qsfp_0_tx_rst_2),
|
||||
.qsfp_0_txd_2(qsfp_0_txd_2),
|
||||
.qsfp_0_txc_2(qsfp_0_txc_2),
|
||||
.qsfp_0_rx_clk_2(qsfp_0_rx_clk_2),
|
||||
.qsfp_0_rx_rst_2(qsfp_0_rx_rst_2),
|
||||
.qsfp_0_rxd_2(qsfp_0_rxd_2),
|
||||
.qsfp_0_rxc_2(qsfp_0_rxc_2),
|
||||
.qsfp_0_tx_clk_3(qsfp_0_tx_clk_3),
|
||||
.qsfp_0_tx_rst_3(qsfp_0_tx_rst_3),
|
||||
.qsfp_0_txd_3(qsfp_0_txd_3),
|
||||
.qsfp_0_txc_3(qsfp_0_txc_3),
|
||||
.qsfp_0_rx_clk_3(qsfp_0_rx_clk_3),
|
||||
.qsfp_0_rx_rst_3(qsfp_0_rx_rst_3),
|
||||
.qsfp_0_rxd_3(qsfp_0_rxd_3),
|
||||
.qsfp_0_rxc_3(qsfp_0_rxc_3),
|
||||
.qsfp_0_modprs_l(qsfp_0_modprs_l),
|
||||
.qsfp_0_sel_l(qsfp_0_sel_l),
|
||||
.qsfp_1_tx_clk_0(qsfp_1_tx_clk_0),
|
||||
.qsfp_1_tx_rst_0(qsfp_1_tx_rst_0),
|
||||
.qsfp_1_txd_0(qsfp_1_txd_0),
|
||||
.qsfp_1_txc_0(qsfp_1_txc_0),
|
||||
.qsfp_1_rx_clk_0(qsfp_1_rx_clk_0),
|
||||
.qsfp_1_rx_rst_0(qsfp_1_rx_rst_0),
|
||||
.qsfp_1_rxd_0(qsfp_1_rxd_0),
|
||||
.qsfp_1_rxc_0(qsfp_1_rxc_0),
|
||||
.qsfp_1_tx_clk_1(qsfp_1_tx_clk_1),
|
||||
.qsfp_1_tx_rst_1(qsfp_1_tx_rst_1),
|
||||
.qsfp_1_txd_1(qsfp_1_txd_1),
|
||||
.qsfp_1_txc_1(qsfp_1_txc_1),
|
||||
.qsfp_1_rx_clk_1(qsfp_1_rx_clk_1),
|
||||
.qsfp_1_rx_rst_1(qsfp_1_rx_rst_1),
|
||||
.qsfp_1_rxd_1(qsfp_1_rxd_1),
|
||||
.qsfp_1_rxc_1(qsfp_1_rxc_1),
|
||||
.qsfp_1_tx_clk_2(qsfp_1_tx_clk_2),
|
||||
.qsfp_1_tx_rst_2(qsfp_1_tx_rst_2),
|
||||
.qsfp_1_txd_2(qsfp_1_txd_2),
|
||||
.qsfp_1_txc_2(qsfp_1_txc_2),
|
||||
.qsfp_1_rx_clk_2(qsfp_1_rx_clk_2),
|
||||
.qsfp_1_rx_rst_2(qsfp_1_rx_rst_2),
|
||||
.qsfp_1_rxd_2(qsfp_1_rxd_2),
|
||||
.qsfp_1_rxc_2(qsfp_1_rxc_2),
|
||||
.qsfp_1_tx_clk_3(qsfp_1_tx_clk_3),
|
||||
.qsfp_1_tx_rst_3(qsfp_1_tx_rst_3),
|
||||
.qsfp_1_txd_3(qsfp_1_txd_3),
|
||||
.qsfp_1_txc_3(qsfp_1_txc_3),
|
||||
.qsfp_1_rx_clk_3(qsfp_1_rx_clk_3),
|
||||
.qsfp_1_rx_rst_3(qsfp_1_rx_rst_3),
|
||||
.qsfp_1_rxd_3(qsfp_1_rxd_3),
|
||||
.qsfp_1_rxc_3(qsfp_1_rxc_3),
|
||||
.qsfp_1_modprs_l(qsfp_1_modprs_l),
|
||||
.qsfp_1_sel_l(qsfp_1_sel_l),
|
||||
.qsfp_reset_l(qsfp_reset_l),
|
||||
.qsfp_int_l(qsfp_int_l),
|
||||
.qsfp_i2c_scl_i(qsfp_i2c_scl_i),
|
||||
.qsfp_i2c_scl_o(qsfp_i2c_scl_o),
|
||||
.qsfp_i2c_scl_t(qsfp_i2c_scl_t),
|
||||
.qsfp_i2c_sda_i(qsfp_i2c_sda_i),
|
||||
.qsfp_i2c_sda_o(qsfp_i2c_sda_o),
|
||||
.qsfp_i2c_sda_t(qsfp_i2c_sda_t),
|
||||
.eeprom_i2c_scl_i(eeprom_i2c_scl_i),
|
||||
.eeprom_i2c_scl_o(eeprom_i2c_scl_o),
|
||||
.eeprom_i2c_scl_t(eeprom_i2c_scl_t),
|
||||
.eeprom_i2c_sda_i(eeprom_i2c_sda_i),
|
||||
.eeprom_i2c_sda_o(eeprom_i2c_sda_o),
|
||||
.eeprom_i2c_sda_t(eeprom_i2c_sda_t),
|
||||
.eeprom_wp(eeprom_wp),
|
||||
.fpga_boot(fpga_boot),
|
||||
.qspi_clk(qspi_clk),
|
||||
.qspi_0_dq_i(qspi_0_dq_i),
|
||||
.qspi_0_dq_o(qspi_0_dq_o),
|
||||
.qspi_0_dq_oe(qspi_0_dq_oe),
|
||||
.qspi_0_cs(qspi_0_cs),
|
||||
.qspi_1_dq_i(qspi_1_dq_i),
|
||||
.qspi_1_dq_o(qspi_1_dq_o),
|
||||
.qspi_1_dq_oe(qspi_1_dq_oe),
|
||||
.qspi_1_cs(qspi_1_cs)
|
||||
);
|
||||
|
||||
endmodule
|
@ -1 +0,0 @@
|
||||
../lib/eth/tb/udp_ep.py
|
@ -1 +0,0 @@
|
||||
../lib/eth/tb/xgmii_ep.py
|
@ -1 +0,0 @@
|
||||
../lib/eth/tb/axis_ep.py
|
@ -1 +0,0 @@
|
||||
../lib/eth/tb/eth_ep.py
|
152
fpga/mqnic/ADM_PCIE_9V3/fpga_25g/tb/fpga_core/Makefile
Normal file
152
fpga/mqnic/ADM_PCIE_9V3/fpga_25g/tb/fpga_core/Makefile
Normal file
@ -0,0 +1,152 @@
|
||||
# Copyright 2020, The Regents of the University of California.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
#
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
|
||||
# IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
|
||||
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
# OF SUCH DAMAGE.
|
||||
#
|
||||
# The views and conclusions contained in the software and documentation are those
|
||||
# of the authors and should not be interpreted as representing official policies,
|
||||
# either expressed or implied, of The Regents of the University of California.
|
||||
|
||||
TOPLEVEL_LANG = verilog
|
||||
|
||||
SIM ?= icarus
|
||||
WAVES ?= 0
|
||||
|
||||
COCOTB_HDL_TIMEUNIT = 1ns
|
||||
COCOTB_HDL_TIMEPRECISION = 1ps
|
||||
|
||||
DUT = fpga_core
|
||||
TOPLEVEL = $(DUT)
|
||||
MODULE = test_$(DUT)
|
||||
VERILOG_SOURCES += ../../rtl/$(DUT).v
|
||||
VERILOG_SOURCES += ../../rtl/common/mqnic_interface.v
|
||||
VERILOG_SOURCES += ../../rtl/common/mqnic_port.v
|
||||
VERILOG_SOURCES += ../../rtl/common/cpl_write.v
|
||||
VERILOG_SOURCES += ../../rtl/common/cpl_op_mux.v
|
||||
VERILOG_SOURCES += ../../rtl/common/desc_fetch.v
|
||||
VERILOG_SOURCES += ../../rtl/common/desc_op_mux.v
|
||||
VERILOG_SOURCES += ../../rtl/common/queue_manager.v
|
||||
VERILOG_SOURCES += ../../rtl/common/cpl_queue_manager.v
|
||||
VERILOG_SOURCES += ../../rtl/common/tx_engine.v
|
||||
VERILOG_SOURCES += ../../rtl/common/rx_engine.v
|
||||
VERILOG_SOURCES += ../../rtl/common/tx_checksum.v
|
||||
VERILOG_SOURCES += ../../rtl/common/rx_hash.v
|
||||
VERILOG_SOURCES += ../../rtl/common/rx_checksum.v
|
||||
VERILOG_SOURCES += ../../rtl/common/tx_scheduler_rr.v
|
||||
VERILOG_SOURCES += ../../rtl/common/event_mux.v
|
||||
VERILOG_SOURCES += ../../rtl/common/tdma_scheduler.v
|
||||
VERILOG_SOURCES += ../../rtl/common/tdma_ber.v
|
||||
VERILOG_SOURCES += ../../rtl/common/tdma_ber_ch.v
|
||||
VERILOG_SOURCES += ../../lib/eth/rtl/eth_mac_10g_fifo.v
|
||||
VERILOG_SOURCES += ../../lib/eth/rtl/eth_mac_10g.v
|
||||
VERILOG_SOURCES += ../../lib/eth/rtl/axis_xgmii_rx_64.v
|
||||
VERILOG_SOURCES += ../../lib/eth/rtl/axis_xgmii_tx_64.v
|
||||
VERILOG_SOURCES += ../../lib/eth/rtl/lfsr.v
|
||||
VERILOG_SOURCES += ../../lib/eth/rtl/ptp_clock.v
|
||||
VERILOG_SOURCES += ../../lib/eth/rtl/ptp_clock_cdc.v
|
||||
VERILOG_SOURCES += ../../lib/eth/rtl/ptp_perout.v
|
||||
VERILOG_SOURCES += ../../lib/eth/rtl/ptp_ts_extract.v
|
||||
VERILOG_SOURCES += ../../lib/axi/rtl/axil_interconnect.v
|
||||
VERILOG_SOURCES += ../../lib/axi/rtl/arbiter.v
|
||||
VERILOG_SOURCES += ../../lib/axi/rtl/priority_encoder.v
|
||||
VERILOG_SOURCES += ../../lib/axis/rtl/axis_adapter.v
|
||||
VERILOG_SOURCES += ../../lib/axis/rtl/axis_arb_mux.v
|
||||
VERILOG_SOURCES += ../../lib/axis/rtl/axis_async_fifo.v
|
||||
VERILOG_SOURCES += ../../lib/axis/rtl/axis_async_fifo_adapter.v
|
||||
VERILOG_SOURCES += ../../lib/axis/rtl/axis_fifo.v
|
||||
VERILOG_SOURCES += ../../lib/axis/rtl/axis_register.v
|
||||
VERILOG_SOURCES += ../../lib/pcie/rtl/pcie_us_axil_master.v
|
||||
VERILOG_SOURCES += ../../lib/pcie/rtl/dma_if_pcie_us.v
|
||||
VERILOG_SOURCES += ../../lib/pcie/rtl/dma_if_pcie_us_rd.v
|
||||
VERILOG_SOURCES += ../../lib/pcie/rtl/dma_if_pcie_us_wr.v
|
||||
VERILOG_SOURCES += ../../lib/pcie/rtl/dma_if_mux.v
|
||||
VERILOG_SOURCES += ../../lib/pcie/rtl/dma_if_mux_rd.v
|
||||
VERILOG_SOURCES += ../../lib/pcie/rtl/dma_if_mux_wr.v
|
||||
VERILOG_SOURCES += ../../lib/pcie/rtl/dma_psdpram.v
|
||||
VERILOG_SOURCES += ../../lib/pcie/rtl/dma_client_axis_sink.v
|
||||
VERILOG_SOURCES += ../../lib/pcie/rtl/dma_client_axis_source.v
|
||||
VERILOG_SOURCES += ../../lib/pcie/rtl/pcie_us_cfg.v
|
||||
VERILOG_SOURCES += ../../lib/pcie/rtl/pcie_us_msi.v
|
||||
VERILOG_SOURCES += ../../lib/pcie/rtl/pcie_tag_manager.v
|
||||
VERILOG_SOURCES += ../../lib/pcie/rtl/pulse_merge.v
|
||||
|
||||
# module parameters
|
||||
export PARAM_AXIS_PCIE_DATA_WIDTH ?= 512
|
||||
export PARAM_AXIS_PCIE_KEEP_WIDTH ?= $(shell expr $(PARAM_AXIS_PCIE_DATA_WIDTH) / 32 )
|
||||
export PARAM_AXIS_PCIE_RQ_USER_WIDTH ?= $(if $(filter-out 512,$(PARAM_AXIS_PCIE_DATA_WIDTH)),62,137)
|
||||
export PARAM_AXIS_PCIE_RC_USER_WIDTH ?= $(if $(filter-out 512,$(PARAM_AXIS_PCIE_DATA_WIDTH)),75,161)
|
||||
export PARAM_AXIS_PCIE_CQ_USER_WIDTH ?= $(if $(filter-out 512,$(PARAM_AXIS_PCIE_DATA_WIDTH)),88,183)
|
||||
export PARAM_AXIS_PCIE_CC_USER_WIDTH ?= $(if $(filter-out 512,$(PARAM_AXIS_PCIE_DATA_WIDTH)),33,81)
|
||||
export PARAM_RQ_SEQ_NUM_WIDTH ?= 6
|
||||
export PARAM_BAR0_APERTURE ?= 24
|
||||
|
||||
SIM_BUILD ?= sim_build_$(MODULE)
|
||||
|
||||
ifeq ($(SIM), icarus)
|
||||
PLUSARGS += -fst
|
||||
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).AXIS_PCIE_DATA_WIDTH=$(PARAM_AXIS_PCIE_DATA_WIDTH)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).AXIS_PCIE_KEEP_WIDTH=$(PARAM_AXIS_PCIE_KEEP_WIDTH)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).AXIS_PCIE_RQ_USER_WIDTH=$(PARAM_AXIS_PCIE_RQ_USER_WIDTH)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).AXIS_PCIE_RC_USER_WIDTH=$(PARAM_AXIS_PCIE_RC_USER_WIDTH)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).AXIS_PCIE_CQ_USER_WIDTH=$(PARAM_AXIS_PCIE_CQ_USER_WIDTH)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).AXIS_PCIE_CC_USER_WIDTH=$(PARAM_AXIS_PCIE_CC_USER_WIDTH)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).RQ_SEQ_NUM_WIDTH=$(PARAM_RQ_SEQ_NUM_WIDTH)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).BAR0_APERTURE=$(PARAM_BAR0_APERTURE)
|
||||
|
||||
ifeq ($(WAVES), 1)
|
||||
VERILOG_SOURCES += iverilog_dump.v
|
||||
COMPILE_ARGS += -s iverilog_dump
|
||||
endif
|
||||
else ifeq ($(SIM), verilator)
|
||||
COMPILE_ARGS += -Wno-SELRANGE -Wno-WIDTH
|
||||
|
||||
COMPILE_ARGS += -GAXIS_PCIE_DATA_WIDTH=$(PARAM_AXIS_PCIE_DATA_WIDTH)
|
||||
COMPILE_ARGS += -GAXIS_PCIE_KEEP_WIDTH=$(PARAM_AXIS_PCIE_KEEP_WIDTH)
|
||||
COMPILE_ARGS += -GAXIS_PCIE_RQ_USER_WIDTH=$(PARAM_AXIS_PCIE_RQ_USER_WIDTH)
|
||||
COMPILE_ARGS += -GAXIS_PCIE_RC_USER_WIDTH=$(PARAM_AXIS_PCIE_RC_USER_WIDTH)
|
||||
COMPILE_ARGS += -GAXIS_PCIE_CQ_USER_WIDTH=$(PARAM_AXIS_PCIE_CQ_USER_WIDTH)
|
||||
COMPILE_ARGS += -GAXIS_PCIE_CC_USER_WIDTH=$(PARAM_AXIS_PCIE_CC_USER_WIDTH)
|
||||
COMPILE_ARGS += -GRQ_SEQ_NUM_WIDTH=$(PARAM_RQ_SEQ_NUM_WIDTH)
|
||||
COMPILE_ARGS += -GBAR0_APERTURE=$(PARAM_BAR0_APERTURE)
|
||||
|
||||
ifeq ($(WAVES), 1)
|
||||
COMPILE_ARGS += --trace-fst
|
||||
endif
|
||||
endif
|
||||
|
||||
iverilog_dump.v:
|
||||
echo 'module iverilog_dump();' > $@
|
||||
echo 'initial begin' >> $@
|
||||
echo ' $$dumpfile("$(TOPLEVEL).fst");' >> $@
|
||||
echo ' $$dumpvars(0, $(TOPLEVEL));' >> $@
|
||||
echo 'end' >> $@
|
||||
echo 'endmodule' >> $@
|
||||
|
||||
clean::
|
||||
@rm -rf sim_build_*
|
||||
@rm -rf iverilog_dump.v
|
||||
@rm -rf dump.fst $(TOPLEVEL).fst
|
||||
|
||||
include $(shell cocotb-config --makefiles)/Makefile.sim
|
||||
|
1
fpga/mqnic/ADM_PCIE_9V3/fpga_25g/tb/fpga_core/mqnic.py
Symbolic link
1
fpga/mqnic/ADM_PCIE_9V3/fpga_25g/tb/fpga_core/mqnic.py
Symbolic link
@ -0,0 +1 @@
|
||||
../../../../../common/tb/mqnic.py
|
657
fpga/mqnic/ADM_PCIE_9V3/fpga_25g/tb/fpga_core/test_fpga_core.py
Normal file
657
fpga/mqnic/ADM_PCIE_9V3/fpga_25g/tb/fpga_core/test_fpga_core.py
Normal file
@ -0,0 +1,657 @@
|
||||
"""
|
||||
|
||||
Copyright 2020, The Regents of the University of California.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
|
||||
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of The Regents of the University of California.
|
||||
|
||||
"""
|
||||
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
|
||||
import scapy.utils
|
||||
from scapy.layers.l2 import Ether
|
||||
from scapy.layers.inet import IP, UDP
|
||||
|
||||
import cocotb_test.simulator
|
||||
|
||||
import cocotb
|
||||
from cocotb.log import SimLog
|
||||
from cocotb.clock import Clock
|
||||
from cocotb.triggers import RisingEdge, FallingEdge, Timer
|
||||
|
||||
from cocotbext.pcie.core import RootComplex
|
||||
from cocotbext.pcie.xilinx.us import UltraScalePlusPcieDevice
|
||||
|
||||
from cocotbext.eth import XgmiiSource, XgmiiSink
|
||||
|
||||
try:
|
||||
import mqnic
|
||||
except ImportError:
|
||||
# attempt import from current directory
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__)))
|
||||
try:
|
||||
import mqnic
|
||||
finally:
|
||||
del sys.path[0]
|
||||
|
||||
|
||||
class TB(object):
|
||||
def __init__(self, dut):
|
||||
self.dut = dut
|
||||
|
||||
self.BAR0_APERTURE = int(os.getenv("PARAM_BAR0_APERTURE"))
|
||||
|
||||
self.log = SimLog("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_cc_straddle=False,
|
||||
rq_rc_straddle=False,
|
||||
rc_4tlp_straddle=False,
|
||||
enable_pf1=False,
|
||||
enable_client_tag=True,
|
||||
enable_extended_tag=True,
|
||||
enable_parity=False,
|
||||
enable_rx_msg_interface=False,
|
||||
enable_sriov=False,
|
||||
enable_extended_configuration=False,
|
||||
|
||||
enable_pf0_msi=True,
|
||||
enable_pf1_msi=False,
|
||||
|
||||
# signals
|
||||
# Clock and Reset Interface
|
||||
user_clk=dut.clk_250mhz,
|
||||
user_reset=dut.rst_250mhz,
|
||||
# user_lnk_up
|
||||
# sys_clk
|
||||
# sys_clk_gt
|
||||
# sys_reset
|
||||
# phy_rdy_out
|
||||
|
||||
# Requester reQuest Interface
|
||||
rq_entity=dut,
|
||||
rq_name="m_axis_rq",
|
||||
pcie_rq_seq_num0=dut.s_axis_rq_seq_num_0,
|
||||
pcie_rq_seq_num_vld0=dut.s_axis_rq_seq_num_valid_0,
|
||||
pcie_rq_seq_num1=dut.s_axis_rq_seq_num_1,
|
||||
pcie_rq_seq_num_vld1=dut.s_axis_rq_seq_num_valid_1,
|
||||
# pcie_rq_tag0
|
||||
# pcie_rq_tag1
|
||||
# pcie_rq_tag_av
|
||||
# pcie_rq_tag_vld0
|
||||
# pcie_rq_tag_vld1
|
||||
|
||||
# Requester Completion Interface
|
||||
rc_entity=dut,
|
||||
rc_name="s_axis_rc",
|
||||
|
||||
# Completer reQuest Interface
|
||||
cq_entity=dut,
|
||||
cq_name="s_axis_cq",
|
||||
# pcie_cq_np_req
|
||||
# pcie_cq_np_req_count
|
||||
|
||||
# Completer Completion Interface
|
||||
cc_entity=dut,
|
||||
cc_name="m_axis_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
|
||||
# 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
|
||||
# cfg_interrupt_msix_mask
|
||||
# cfg_interrupt_msix_vf_enable
|
||||
# cfg_interrupt_msix_vf_mask
|
||||
# cfg_interrupt_msix_address
|
||||
# cfg_interrupt_msix_data
|
||||
# cfg_interrupt_msix_int
|
||||
# cfg_interrupt_msix_vec_pending
|
||||
# cfg_interrupt_msix_vec_pending_status
|
||||
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.driver = mqnic.Driver(self.rc)
|
||||
|
||||
self.dev.functions[0].msi_multiple_message_capable = 5
|
||||
|
||||
self.dev.functions[0].configure_bar(0, 2**self.BAR0_APERTURE, ext=True, prefetch=True)
|
||||
|
||||
# Ethernet
|
||||
cocotb.fork(Clock(dut.qsfp_0_rx_clk_0, 2.56, units="ns").start())
|
||||
self.qsfp_0_0_source = XgmiiSource(dut.qsfp_0_rxd_0, dut.qsfp_0_rxc_0, dut.qsfp_0_rx_clk_0, dut.qsfp_0_rx_rst_0)
|
||||
cocotb.fork(Clock(dut.qsfp_0_tx_clk_0, 2.56, units="ns").start())
|
||||
self.qsfp_0_0_sink = XgmiiSink(dut.qsfp_0_txd_0, dut.qsfp_0_txc_0, dut.qsfp_0_tx_clk_0, dut.qsfp_0_tx_rst_0)
|
||||
|
||||
cocotb.fork(Clock(dut.qsfp_0_rx_clk_1, 2.56, units="ns").start())
|
||||
self.qsfp_0_1_source = XgmiiSource(dut.qsfp_0_rxd_1, dut.qsfp_0_rxc_1, dut.qsfp_0_rx_clk_1, dut.qsfp_0_rx_rst_1)
|
||||
cocotb.fork(Clock(dut.qsfp_0_tx_clk_1, 2.56, units="ns").start())
|
||||
self.qsfp_0_1_sink = XgmiiSink(dut.qsfp_0_txd_1, dut.qsfp_0_txc_1, dut.qsfp_0_tx_clk_1, dut.qsfp_0_tx_rst_1)
|
||||
|
||||
cocotb.fork(Clock(dut.qsfp_0_rx_clk_2, 2.56, units="ns").start())
|
||||
self.qsfp_0_2_source = XgmiiSource(dut.qsfp_0_rxd_2, dut.qsfp_0_rxc_2, dut.qsfp_0_rx_clk_2, dut.qsfp_0_rx_rst_2)
|
||||
cocotb.fork(Clock(dut.qsfp_0_tx_clk_2, 2.56, units="ns").start())
|
||||
self.qsfp_0_2_sink = XgmiiSink(dut.qsfp_0_txd_2, dut.qsfp_0_txc_2, dut.qsfp_0_tx_clk_2, dut.qsfp_0_tx_rst_2)
|
||||
|
||||
cocotb.fork(Clock(dut.qsfp_0_rx_clk_3, 2.56, units="ns").start())
|
||||
self.qsfp_0_3_source = XgmiiSource(dut.qsfp_0_rxd_3, dut.qsfp_0_rxc_3, dut.qsfp_0_rx_clk_3, dut.qsfp_0_rx_rst_3)
|
||||
cocotb.fork(Clock(dut.qsfp_0_tx_clk_3, 2.56, units="ns").start())
|
||||
self.qsfp_0_3_sink = XgmiiSink(dut.qsfp_0_txd_3, dut.qsfp_0_txc_3, dut.qsfp_0_tx_clk_3, dut.qsfp_0_tx_rst_3)
|
||||
|
||||
cocotb.fork(Clock(dut.qsfp_1_rx_clk_0, 2.56, units="ns").start())
|
||||
self.qsfp_1_0_source = XgmiiSource(dut.qsfp_1_rxd_0, dut.qsfp_1_rxc_0, dut.qsfp_1_rx_clk_0, dut.qsfp_1_rx_rst_0)
|
||||
cocotb.fork(Clock(dut.qsfp_1_tx_clk_0, 2.56, units="ns").start())
|
||||
self.qsfp_1_0_sink = XgmiiSink(dut.qsfp_1_txd_0, dut.qsfp_1_txc_0, dut.qsfp_1_tx_clk_0, dut.qsfp_1_tx_rst_0)
|
||||
|
||||
cocotb.fork(Clock(dut.qsfp_1_rx_clk_1, 2.56, units="ns").start())
|
||||
self.qsfp_1_1_source = XgmiiSource(dut.qsfp_1_rxd_1, dut.qsfp_1_rxc_1, dut.qsfp_1_rx_clk_1, dut.qsfp_1_rx_rst_1)
|
||||
cocotb.fork(Clock(dut.qsfp_1_tx_clk_1, 2.56, units="ns").start())
|
||||
self.qsfp_1_1_sink = XgmiiSink(dut.qsfp_1_txd_1, dut.qsfp_1_txc_1, dut.qsfp_1_tx_clk_1, dut.qsfp_1_tx_rst_1)
|
||||
|
||||
cocotb.fork(Clock(dut.qsfp_1_rx_clk_2, 2.56, units="ns").start())
|
||||
self.qsfp_1_2_source = XgmiiSource(dut.qsfp_1_rxd_2, dut.qsfp_1_rxc_2, dut.qsfp_1_rx_clk_2, dut.qsfp_1_rx_rst_2)
|
||||
cocotb.fork(Clock(dut.qsfp_1_tx_clk_2, 2.56, units="ns").start())
|
||||
self.qsfp_1_2_sink = XgmiiSink(dut.qsfp_1_txd_2, dut.qsfp_1_txc_2, dut.qsfp_1_tx_clk_2, dut.qsfp_1_tx_rst_2)
|
||||
|
||||
cocotb.fork(Clock(dut.qsfp_1_rx_clk_3, 2.56, units="ns").start())
|
||||
self.qsfp_1_3_source = XgmiiSource(dut.qsfp_1_rxd_3, dut.qsfp_1_rxc_3, dut.qsfp_1_rx_clk_3, dut.qsfp_1_rx_rst_3)
|
||||
cocotb.fork(Clock(dut.qsfp_1_tx_clk_3, 2.56, units="ns").start())
|
||||
self.qsfp_1_3_sink = XgmiiSink(dut.qsfp_1_txd_3, dut.qsfp_1_txc_3, dut.qsfp_1_tx_clk_3, dut.qsfp_1_tx_rst_3)
|
||||
|
||||
dut.user_sw.setimmediatevalue(0)
|
||||
|
||||
dut.qsfp_0_rx_error_count_0.setimmediatevalue(0)
|
||||
dut.qsfp_0_rx_error_count_1.setimmediatevalue(0)
|
||||
dut.qsfp_0_rx_error_count_2.setimmediatevalue(0)
|
||||
dut.qsfp_0_rx_error_count_3.setimmediatevalue(0)
|
||||
|
||||
dut.qsfp_1_rx_error_count_0.setimmediatevalue(0)
|
||||
dut.qsfp_1_rx_error_count_1.setimmediatevalue(0)
|
||||
dut.qsfp_1_rx_error_count_2.setimmediatevalue(0)
|
||||
dut.qsfp_1_rx_error_count_3.setimmediatevalue(0)
|
||||
|
||||
dut.qsfp_0_modprs_l.setimmediatevalue(0)
|
||||
dut.qsfp_1_modprs_l.setimmediatevalue(0)
|
||||
|
||||
dut.qsfp_int_l.setimmediatevalue(1)
|
||||
dut.qsfp_i2c_scl_i.setimmediatevalue(1)
|
||||
dut.qsfp_i2c_sda_i.setimmediatevalue(1)
|
||||
|
||||
dut.eeprom_i2c_scl_i.setimmediatevalue(1)
|
||||
dut.eeprom_i2c_sda_i.setimmediatevalue(1)
|
||||
|
||||
dut.qspi_0_dq_i.setimmediatevalue(0)
|
||||
dut.qspi_1_dq_i.setimmediatevalue(0)
|
||||
|
||||
self.loopback_enable = False
|
||||
cocotb.fork(self._run_loopback())
|
||||
|
||||
async def init(self):
|
||||
|
||||
self.dut.qsfp_0_rx_rst_0.setimmediatevalue(0)
|
||||
self.dut.qsfp_0_tx_rst_0.setimmediatevalue(0)
|
||||
self.dut.qsfp_0_rx_rst_1.setimmediatevalue(0)
|
||||
self.dut.qsfp_0_tx_rst_1.setimmediatevalue(0)
|
||||
self.dut.qsfp_0_rx_rst_2.setimmediatevalue(0)
|
||||
self.dut.qsfp_0_tx_rst_2.setimmediatevalue(0)
|
||||
self.dut.qsfp_0_rx_rst_3.setimmediatevalue(0)
|
||||
self.dut.qsfp_0_tx_rst_3.setimmediatevalue(0)
|
||||
self.dut.qsfp_1_rx_rst_0.setimmediatevalue(0)
|
||||
self.dut.qsfp_1_tx_rst_0.setimmediatevalue(0)
|
||||
self.dut.qsfp_1_rx_rst_1.setimmediatevalue(0)
|
||||
self.dut.qsfp_1_tx_rst_1.setimmediatevalue(0)
|
||||
self.dut.qsfp_1_rx_rst_2.setimmediatevalue(0)
|
||||
self.dut.qsfp_1_tx_rst_2.setimmediatevalue(0)
|
||||
self.dut.qsfp_1_rx_rst_3.setimmediatevalue(0)
|
||||
self.dut.qsfp_1_tx_rst_3.setimmediatevalue(0)
|
||||
|
||||
await RisingEdge(self.dut.clk_250mhz)
|
||||
await RisingEdge(self.dut.clk_250mhz)
|
||||
|
||||
self.dut.qsfp_0_rx_rst_0.setimmediatevalue(1)
|
||||
self.dut.qsfp_0_tx_rst_0.setimmediatevalue(1)
|
||||
self.dut.qsfp_0_rx_rst_1.setimmediatevalue(1)
|
||||
self.dut.qsfp_0_tx_rst_1.setimmediatevalue(1)
|
||||
self.dut.qsfp_0_rx_rst_2.setimmediatevalue(1)
|
||||
self.dut.qsfp_0_tx_rst_2.setimmediatevalue(1)
|
||||
self.dut.qsfp_0_rx_rst_3.setimmediatevalue(1)
|
||||
self.dut.qsfp_0_tx_rst_3.setimmediatevalue(1)
|
||||
self.dut.qsfp_1_rx_rst_0.setimmediatevalue(1)
|
||||
self.dut.qsfp_1_tx_rst_0.setimmediatevalue(1)
|
||||
self.dut.qsfp_1_rx_rst_1.setimmediatevalue(1)
|
||||
self.dut.qsfp_1_tx_rst_1.setimmediatevalue(1)
|
||||
self.dut.qsfp_1_rx_rst_2.setimmediatevalue(1)
|
||||
self.dut.qsfp_1_tx_rst_2.setimmediatevalue(1)
|
||||
self.dut.qsfp_1_rx_rst_3.setimmediatevalue(1)
|
||||
self.dut.qsfp_1_tx_rst_3.setimmediatevalue(1)
|
||||
|
||||
await FallingEdge(self.dut.rst_250mhz)
|
||||
await Timer(100, 'ns')
|
||||
|
||||
await RisingEdge(self.dut.clk_250mhz)
|
||||
await RisingEdge(self.dut.clk_250mhz)
|
||||
|
||||
self.dut.qsfp_0_rx_rst_0.setimmediatevalue(0)
|
||||
self.dut.qsfp_0_tx_rst_0.setimmediatevalue(0)
|
||||
self.dut.qsfp_0_rx_rst_1.setimmediatevalue(0)
|
||||
self.dut.qsfp_0_tx_rst_1.setimmediatevalue(0)
|
||||
self.dut.qsfp_0_rx_rst_2.setimmediatevalue(0)
|
||||
self.dut.qsfp_0_tx_rst_2.setimmediatevalue(0)
|
||||
self.dut.qsfp_0_rx_rst_3.setimmediatevalue(0)
|
||||
self.dut.qsfp_0_tx_rst_3.setimmediatevalue(0)
|
||||
self.dut.qsfp_1_rx_rst_0.setimmediatevalue(0)
|
||||
self.dut.qsfp_1_tx_rst_0.setimmediatevalue(0)
|
||||
self.dut.qsfp_1_rx_rst_1.setimmediatevalue(0)
|
||||
self.dut.qsfp_1_tx_rst_1.setimmediatevalue(0)
|
||||
self.dut.qsfp_1_rx_rst_2.setimmediatevalue(0)
|
||||
self.dut.qsfp_1_tx_rst_2.setimmediatevalue(0)
|
||||
self.dut.qsfp_1_rx_rst_3.setimmediatevalue(0)
|
||||
self.dut.qsfp_1_tx_rst_3.setimmediatevalue(0)
|
||||
|
||||
await self.rc.enumerate(enable_bus_mastering=True, configure_msi=True)
|
||||
|
||||
async def _run_loopback(self):
|
||||
while True:
|
||||
await RisingEdge(self.dut.clk_250mhz)
|
||||
|
||||
if self.loopback_enable:
|
||||
if not self.qsfp_0_0_sink.empty():
|
||||
self.qsfp_0_0_source.send(self.qsfp_0_0_sink.recv())
|
||||
if not self.qsfp_0_1_sink.empty():
|
||||
self.qsfp_0_1_source.send(self.qsfp_0_1_sink.recv())
|
||||
if not self.qsfp_0_2_sink.empty():
|
||||
self.qsfp_0_2_source.send(self.qsfp_0_2_sink.recv())
|
||||
if not self.qsfp_0_3_sink.empty():
|
||||
self.qsfp_0_3_source.send(self.qsfp_0_3_sink.recv())
|
||||
if not self.qsfp_1_0_sink.empty():
|
||||
self.qsfp_1_0_source.send(self.qsfp_1_0_sink.recv())
|
||||
if not self.qsfp_1_1_sink.empty():
|
||||
self.qsfp_1_1_source.send(self.qsfp_1_1_sink.recv())
|
||||
if not self.qsfp_1_2_sink.empty():
|
||||
self.qsfp_1_2_source.send(self.qsfp_1_2_sink.recv())
|
||||
if not self.qsfp_1_3_sink.empty():
|
||||
self.qsfp_1_3_source.send(self.qsfp_1_3_sink.recv())
|
||||
|
||||
|
||||
@cocotb.test()
|
||||
async def run_test_nic(dut):
|
||||
|
||||
tb = TB(dut)
|
||||
|
||||
await tb.init()
|
||||
|
||||
tb.log.info("Init driver")
|
||||
await tb.driver.init_dev(tb.dev.functions[0].pcie_id)
|
||||
await tb.driver.interfaces[0].open()
|
||||
# await driver.interfaces[1].open()
|
||||
|
||||
# enable queues
|
||||
tb.log.info("Enable queues")
|
||||
await tb.rc.mem_write_dword(tb.driver.interfaces[0].ports[0].hw_addr+mqnic.MQNIC_PORT_REG_SCHED_ENABLE, 0x00000001)
|
||||
for k in range(tb.driver.interfaces[0].tx_queue_count):
|
||||
await tb.rc.mem_write_dword(tb.driver.interfaces[0].ports[0].schedulers[0].hw_addr+4*k, 0x00000003)
|
||||
|
||||
# wait for all writes to complete
|
||||
await tb.rc.mem_read(tb.driver.hw_addr, 4)
|
||||
tb.log.info("Init complete")
|
||||
|
||||
tb.log.info("Send and receive single packet")
|
||||
|
||||
data = bytearray([x % 256 for x in range(1024)])
|
||||
|
||||
await tb.driver.interfaces[0].start_xmit(data, 0)
|
||||
|
||||
await tb.qsfp_0_0_sink.wait()
|
||||
|
||||
pkt = tb.qsfp_0_0_sink.recv()
|
||||
tb.log.info("Packet: %s", pkt)
|
||||
|
||||
tb.qsfp_0_0_source.send(pkt)
|
||||
|
||||
await tb.driver.interfaces[0].wait()
|
||||
|
||||
pkt = tb.driver.interfaces[0].recv()
|
||||
|
||||
tb.log.info("Packet: %s", pkt)
|
||||
assert pkt.rx_checksum == ~scapy.utils.checksum(bytes(pkt.data[14:])) & 0xffff
|
||||
|
||||
# await tb.driver.interfaces[1].start_xmit(data, 0)
|
||||
|
||||
# await tb.qsfp_1_0_sink.wait()
|
||||
|
||||
# pkt = tb.qsfp_1_0_sink.recv()
|
||||
# tb.log.info("Packet: %s", pkt)
|
||||
|
||||
# tb.qsfp_1_0_source.send(pkt)
|
||||
|
||||
# await tb.driver.interfaces[1].wait()
|
||||
|
||||
# pkt = tb.driver.interfaces[1].recv()
|
||||
|
||||
# tb.log.info("Packet: %s", pkt)
|
||||
# assert pkt.rx_checksum == ~scapy.utils.checksum(bytes(pkt.data[14:])) & 0xffff
|
||||
|
||||
tb.log.info("RX and TX checksum tests")
|
||||
|
||||
payload = bytes([x % 256 for x in range(256)])
|
||||
eth = Ether(src='5A:51:52:53:54:55', dst='DA:D1:D2:D3:D4:D5')
|
||||
ip = IP(src='192.168.1.100', dst='192.168.1.101')
|
||||
udp = UDP(sport=1, dport=2)
|
||||
test_pkt = eth / ip / udp / payload
|
||||
|
||||
test_pkt2 = test_pkt.copy()
|
||||
test_pkt2[UDP].chksum = scapy.utils.checksum(bytes(test_pkt2[UDP]))
|
||||
|
||||
await tb.driver.interfaces[0].start_xmit(test_pkt2.build(), 0, 34, 6)
|
||||
|
||||
await tb.qsfp_0_0_sink.wait()
|
||||
|
||||
pkt = tb.qsfp_0_0_sink.recv()
|
||||
tb.log.info("Packet: %s", pkt)
|
||||
|
||||
tb.qsfp_0_0_source.send(pkt)
|
||||
|
||||
await tb.driver.interfaces[0].wait()
|
||||
|
||||
pkt = tb.driver.interfaces[0].recv()
|
||||
|
||||
tb.log.info("Packet: %s", pkt)
|
||||
assert pkt.rx_checksum == ~scapy.utils.checksum(bytes(pkt.data[14:])) & 0xffff
|
||||
assert Ether(pkt.data).build() == test_pkt.build()
|
||||
|
||||
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 tb.driver.interfaces[0].start_xmit(p, 0)
|
||||
|
||||
for k in range(count):
|
||||
await tb.driver.interfaces[0].wait()
|
||||
pkt = tb.driver.interfaces[0].recv()
|
||||
|
||||
tb.log.info("Packet: %s", pkt)
|
||||
assert pkt.data == pkts[k]
|
||||
assert pkt.rx_checksum == ~scapy.utils.checksum(bytes(pkt.data[14:])) & 0xffff
|
||||
|
||||
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 tb.driver.interfaces[0].start_xmit(p, 0)
|
||||
|
||||
for k in range(count):
|
||||
await tb.driver.interfaces[0].wait()
|
||||
pkt = tb.driver.interfaces[0].recv()
|
||||
|
||||
tb.log.info("Packet: %s", pkt)
|
||||
assert pkt.data == pkts[k]
|
||||
assert pkt.rx_checksum == ~scapy.utils.checksum(bytes(pkt.data[14:])) & 0xffff
|
||||
|
||||
tb.loopback_enable = False
|
||||
|
||||
await RisingEdge(dut.clk_250mhz)
|
||||
await RisingEdge(dut.clk_250mhz)
|
||||
|
||||
|
||||
# cocotb-test
|
||||
|
||||
tests_dir = os.path.dirname(__file__)
|
||||
rtl_dir = os.path.abspath(os.path.join(tests_dir, '..', '..', 'rtl'))
|
||||
lib_dir = os.path.abspath(os.path.join(rtl_dir, '..', 'lib'))
|
||||
axi_rtl_dir = os.path.abspath(os.path.join(lib_dir, 'axi', 'rtl'))
|
||||
axis_rtl_dir = os.path.abspath(os.path.join(lib_dir, 'axis', 'rtl'))
|
||||
eth_rtl_dir = os.path.abspath(os.path.join(lib_dir, 'eth', 'rtl'))
|
||||
pcie_rtl_dir = os.path.abspath(os.path.join(lib_dir, 'pcie', 'rtl'))
|
||||
|
||||
|
||||
def test_fpga_core(request):
|
||||
dut = "fpga_core"
|
||||
module = os.path.splitext(os.path.basename(__file__))[0]
|
||||
toplevel = dut
|
||||
|
||||
verilog_sources = [
|
||||
os.path.join(rtl_dir, f"{dut}.v"),
|
||||
os.path.join(rtl_dir, "common", "mqnic_interface.v"),
|
||||
os.path.join(rtl_dir, "common", "mqnic_port.v"),
|
||||
os.path.join(rtl_dir, "common", "cpl_write.v"),
|
||||
os.path.join(rtl_dir, "common", "cpl_op_mux.v"),
|
||||
os.path.join(rtl_dir, "common", "desc_fetch.v"),
|
||||
os.path.join(rtl_dir, "common", "desc_op_mux.v"),
|
||||
os.path.join(rtl_dir, "common", "queue_manager.v"),
|
||||
os.path.join(rtl_dir, "common", "cpl_queue_manager.v"),
|
||||
os.path.join(rtl_dir, "common", "tx_engine.v"),
|
||||
os.path.join(rtl_dir, "common", "rx_engine.v"),
|
||||
os.path.join(rtl_dir, "common", "tx_checksum.v"),
|
||||
os.path.join(rtl_dir, "common", "rx_hash.v"),
|
||||
os.path.join(rtl_dir, "common", "rx_checksum.v"),
|
||||
os.path.join(rtl_dir, "common", "tx_scheduler_rr.v"),
|
||||
os.path.join(rtl_dir, "common", "event_mux.v"),
|
||||
os.path.join(rtl_dir, "common", "tdma_scheduler.v"),
|
||||
os.path.join(rtl_dir, "common", "tdma_ber.v"),
|
||||
os.path.join(rtl_dir, "common", "tdma_ber_ch.v"),
|
||||
os.path.join(eth_rtl_dir, "eth_mac_10g_fifo.v"),
|
||||
os.path.join(eth_rtl_dir, "eth_mac_10g.v"),
|
||||
os.path.join(eth_rtl_dir, "axis_xgmii_rx_64.v"),
|
||||
os.path.join(eth_rtl_dir, "axis_xgmii_tx_64.v"),
|
||||
os.path.join(eth_rtl_dir, "lfsr.v"),
|
||||
os.path.join(eth_rtl_dir, "ptp_clock.v"),
|
||||
os.path.join(eth_rtl_dir, "ptp_clock_cdc.v"),
|
||||
os.path.join(eth_rtl_dir, "ptp_perout.v"),
|
||||
os.path.join(eth_rtl_dir, "ptp_ts_extract.v"),
|
||||
os.path.join(axi_rtl_dir, "axil_interconnect.v"),
|
||||
os.path.join(axi_rtl_dir, "arbiter.v"),
|
||||
os.path.join(axi_rtl_dir, "priority_encoder.v"),
|
||||
os.path.join(axis_rtl_dir, "axis_adapter.v"),
|
||||
os.path.join(axis_rtl_dir, "axis_arb_mux.v"),
|
||||
os.path.join(axis_rtl_dir, "axis_async_fifo.v"),
|
||||
os.path.join(axis_rtl_dir, "axis_async_fifo_adapter.v"),
|
||||
os.path.join(axis_rtl_dir, "axis_fifo.v"),
|
||||
os.path.join(axis_rtl_dir, "axis_register.v"),
|
||||
os.path.join(pcie_rtl_dir, "pcie_us_axil_master.v"),
|
||||
os.path.join(pcie_rtl_dir, "dma_if_pcie_us.v"),
|
||||
os.path.join(pcie_rtl_dir, "dma_if_pcie_us_rd.v"),
|
||||
os.path.join(pcie_rtl_dir, "dma_if_pcie_us_wr.v"),
|
||||
os.path.join(pcie_rtl_dir, "dma_if_mux.v"),
|
||||
os.path.join(pcie_rtl_dir, "dma_if_mux_rd.v"),
|
||||
os.path.join(pcie_rtl_dir, "dma_if_mux_wr.v"),
|
||||
os.path.join(pcie_rtl_dir, "dma_psdpram.v"),
|
||||
os.path.join(pcie_rtl_dir, "dma_client_axis_sink.v"),
|
||||
os.path.join(pcie_rtl_dir, "dma_client_axis_source.v"),
|
||||
os.path.join(pcie_rtl_dir, "pcie_us_cfg.v"),
|
||||
os.path.join(pcie_rtl_dir, "pcie_us_msi.v"),
|
||||
os.path.join(pcie_rtl_dir, "pcie_tag_manager.v"),
|
||||
os.path.join(pcie_rtl_dir, "pulse_merge.v"),
|
||||
]
|
||||
|
||||
parameters = {}
|
||||
|
||||
parameters['AXIS_PCIE_DATA_WIDTH'] = 512
|
||||
parameters['AXIS_PCIE_KEEP_WIDTH'] = int(parameters['AXIS_PCIE_DATA_WIDTH']/32)
|
||||
parameters['AXIS_PCIE_RQ_USER_WIDTH'] = 62 if parameters['AXIS_PCIE_DATA_WIDTH'] < 512 else 137
|
||||
parameters['AXIS_PCIE_RC_USER_WIDTH'] = 75 if parameters['AXIS_PCIE_DATA_WIDTH'] < 512 else 161
|
||||
parameters['AXIS_PCIE_CQ_USER_WIDTH'] = 88 if parameters['AXIS_PCIE_DATA_WIDTH'] < 512 else 183
|
||||
parameters['AXIS_PCIE_CC_USER_WIDTH'] = 33 if parameters['AXIS_PCIE_DATA_WIDTH'] < 512 else 81
|
||||
parameters['RQ_SEQ_NUM_WIDTH'] = 6
|
||||
parameters['BAR0_APERTURE'] = 24
|
||||
|
||||
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(
|
||||
python_search=[tests_dir],
|
||||
verilog_sources=verilog_sources,
|
||||
toplevel=toplevel,
|
||||
module=module,
|
||||
parameters=parameters,
|
||||
sim_build=sim_build,
|
||||
extra_env=extra_env,
|
||||
)
|
@ -1 +0,0 @@
|
||||
../lib/eth/tb/ip_ep.py
|
@ -1 +0,0 @@
|
||||
../../../../common/tb/mqnic.py
|
@ -1 +0,0 @@
|
||||
../lib/pcie/tb/pcie.py
|
@ -1 +0,0 @@
|
||||
../lib/pcie/tb/pcie_us.py
|
@ -1 +0,0 @@
|
||||
../lib/pcie/tb/pcie_usp.py
|
File diff suppressed because it is too large
Load Diff
@ -1,579 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright 2019, The Regents of the University of California.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
|
||||
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of The Regents of the University of California.
|
||||
|
||||
*/
|
||||
|
||||
// Language: Verilog 2001
|
||||
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
/*
|
||||
* Testbench for fpga_core
|
||||
*/
|
||||
module test_fpga_core;
|
||||
|
||||
// Parameters
|
||||
parameter AXIS_PCIE_DATA_WIDTH = 512;
|
||||
parameter AXIS_PCIE_KEEP_WIDTH = (AXIS_PCIE_DATA_WIDTH/32);
|
||||
parameter AXIS_PCIE_RC_USER_WIDTH = 161;
|
||||
parameter AXIS_PCIE_RQ_USER_WIDTH = 137;
|
||||
parameter AXIS_PCIE_CQ_USER_WIDTH = 183;
|
||||
parameter AXIS_PCIE_CC_USER_WIDTH = 81;
|
||||
parameter RQ_SEQ_NUM_WIDTH = 6;
|
||||
parameter BAR0_APERTURE = 24;
|
||||
|
||||
// Inputs
|
||||
reg clk = 0;
|
||||
reg rst = 0;
|
||||
reg [7:0] current_test = 0;
|
||||
|
||||
reg clk_250mhz = 0;
|
||||
reg rst_250mhz = 0;
|
||||
reg [1:0] user_sw = 0;
|
||||
reg m_axis_rq_tready = 0;
|
||||
reg [AXIS_PCIE_DATA_WIDTH-1:0] s_axis_rc_tdata = 0;
|
||||
reg [AXIS_PCIE_KEEP_WIDTH-1:0] s_axis_rc_tkeep = 0;
|
||||
reg s_axis_rc_tlast = 0;
|
||||
reg [AXIS_PCIE_RC_USER_WIDTH-1:0] s_axis_rc_tuser = 0;
|
||||
reg s_axis_rc_tvalid = 0;
|
||||
reg [AXIS_PCIE_DATA_WIDTH-1:0] s_axis_cq_tdata = 0;
|
||||
reg [AXIS_PCIE_KEEP_WIDTH-1:0] s_axis_cq_tkeep = 0;
|
||||
reg s_axis_cq_tlast = 0;
|
||||
reg [AXIS_PCIE_CQ_USER_WIDTH-1:0] s_axis_cq_tuser = 0;
|
||||
reg s_axis_cq_tvalid = 0;
|
||||
reg m_axis_cc_tready = 0;
|
||||
reg [RQ_SEQ_NUM_WIDTH-1:0] s_axis_rq_seq_num_0 = 0;
|
||||
reg s_axis_rq_seq_num_valid_0 = 0;
|
||||
reg [RQ_SEQ_NUM_WIDTH-1:0] s_axis_rq_seq_num_1 = 0;
|
||||
reg s_axis_rq_seq_num_valid_1 = 0;
|
||||
reg [3:0] pcie_tfc_nph_av = 0;
|
||||
reg [3:0] pcie_tfc_npd_av = 0;
|
||||
reg [2:0] cfg_max_payload = 0;
|
||||
reg [2:0] cfg_max_read_req = 0;
|
||||
reg [31:0] cfg_mgmt_read_data = 0;
|
||||
reg cfg_mgmt_read_write_done = 0;
|
||||
reg [7:0] cfg_fc_ph = 0;
|
||||
reg [11:0] cfg_fc_pd = 0;
|
||||
reg [7:0] cfg_fc_nph = 0;
|
||||
reg [11:0] cfg_fc_npd = 0;
|
||||
reg [7:0] cfg_fc_cplh = 0;
|
||||
reg [11:0] cfg_fc_cpld = 0;
|
||||
reg [3:0] cfg_interrupt_msi_enable = 0;
|
||||
reg [11:0] cfg_interrupt_msi_mmenable = 0;
|
||||
reg cfg_interrupt_msi_mask_update = 0;
|
||||
reg [31:0] cfg_interrupt_msi_data = 0;
|
||||
reg cfg_interrupt_msi_sent = 0;
|
||||
reg cfg_interrupt_msi_fail = 0;
|
||||
reg qsfp_0_tx_clk_0 = 0;
|
||||
reg qsfp_0_tx_rst_0 = 0;
|
||||
reg qsfp_0_rx_clk_0 = 0;
|
||||
reg qsfp_0_rx_rst_0 = 0;
|
||||
reg [63:0] qsfp_0_rxd_0 = 0;
|
||||
reg [7:0] qsfp_0_rxc_0 = 0;
|
||||
reg qsfp_0_tx_clk_1 = 0;
|
||||
reg qsfp_0_tx_rst_1 = 0;
|
||||
reg qsfp_0_rx_clk_1 = 0;
|
||||
reg qsfp_0_rx_rst_1 = 0;
|
||||
reg [63:0] qsfp_0_rxd_1 = 0;
|
||||
reg [7:0] qsfp_0_rxc_1 = 0;
|
||||
reg qsfp_0_tx_clk_2 = 0;
|
||||
reg qsfp_0_tx_rst_2 = 0;
|
||||
reg qsfp_0_rx_clk_2 = 0;
|
||||
reg qsfp_0_rx_rst_2 = 0;
|
||||
reg [63:0] qsfp_0_rxd_2 = 0;
|
||||
reg [7:0] qsfp_0_rxc_2 = 0;
|
||||
reg qsfp_0_tx_clk_3 = 0;
|
||||
reg qsfp_0_tx_rst_3 = 0;
|
||||
reg qsfp_0_rx_clk_3 = 0;
|
||||
reg qsfp_0_rx_rst_3 = 0;
|
||||
reg [63:0] qsfp_0_rxd_3 = 0;
|
||||
reg [7:0] qsfp_0_rxc_3 = 0;
|
||||
reg qsfp_0_modprs_l = 0;
|
||||
reg qsfp_1_tx_clk_0 = 0;
|
||||
reg qsfp_1_tx_rst_0 = 0;
|
||||
reg qsfp_1_rx_clk_0 = 0;
|
||||
reg qsfp_1_rx_rst_0 = 0;
|
||||
reg [63:0] qsfp_1_rxd_0 = 0;
|
||||
reg [7:0] qsfp_1_rxc_0 = 0;
|
||||
reg qsfp_1_tx_clk_1 = 0;
|
||||
reg qsfp_1_tx_rst_1 = 0;
|
||||
reg qsfp_1_rx_clk_1 = 0;
|
||||
reg qsfp_1_rx_rst_1 = 0;
|
||||
reg [63:0] qsfp_1_rxd_1 = 0;
|
||||
reg [7:0] qsfp_1_rxc_1 = 0;
|
||||
reg qsfp_1_tx_clk_2 = 0;
|
||||
reg qsfp_1_tx_rst_2 = 0;
|
||||
reg qsfp_1_rx_clk_2 = 0;
|
||||
reg qsfp_1_rx_rst_2 = 0;
|
||||
reg [63:0] qsfp_1_rxd_2 = 0;
|
||||
reg [7:0] qsfp_1_rxc_2 = 0;
|
||||
reg qsfp_1_tx_clk_3 = 0;
|
||||
reg qsfp_1_tx_rst_3 = 0;
|
||||
reg qsfp_1_rx_clk_3 = 0;
|
||||
reg qsfp_1_rx_rst_3 = 0;
|
||||
reg [63:0] qsfp_1_rxd_3 = 0;
|
||||
reg [7:0] qsfp_1_rxc_3 = 0;
|
||||
reg qsfp_1_modprs_l = 0;
|
||||
reg qsfp_int_l = 0;
|
||||
reg qsfp_i2c_scl_i = 1;
|
||||
reg qsfp_i2c_sda_i = 1;
|
||||
reg eeprom_i2c_scl_i = 1;
|
||||
reg eeprom_i2c_sda_i = 1;
|
||||
reg [3:0] qspi_0_dq_i = 0;
|
||||
reg [3:0] qspi_1_dq_i = 0;
|
||||
|
||||
// Outputs
|
||||
wire [1:0] user_led_g;
|
||||
wire user_led_r;
|
||||
wire [1:0] front_led;
|
||||
wire [AXIS_PCIE_DATA_WIDTH-1:0] m_axis_rq_tdata;
|
||||
wire [AXIS_PCIE_KEEP_WIDTH-1:0] m_axis_rq_tkeep;
|
||||
wire m_axis_rq_tlast;
|
||||
wire [AXIS_PCIE_RQ_USER_WIDTH-1:0] m_axis_rq_tuser;
|
||||
wire m_axis_rq_tvalid;
|
||||
wire s_axis_rc_tready;
|
||||
wire s_axis_cq_tready;
|
||||
wire [AXIS_PCIE_DATA_WIDTH-1:0] m_axis_cc_tdata;
|
||||
wire [AXIS_PCIE_KEEP_WIDTH-1:0] m_axis_cc_tkeep;
|
||||
wire m_axis_cc_tlast;
|
||||
wire [AXIS_PCIE_CC_USER_WIDTH-1:0] m_axis_cc_tuser;
|
||||
wire m_axis_cc_tvalid;
|
||||
wire [9:0] cfg_mgmt_addr;
|
||||
wire [7:0] cfg_mgmt_function_number;
|
||||
wire cfg_mgmt_write;
|
||||
wire [31:0] cfg_mgmt_write_data;
|
||||
wire [3:0] cfg_mgmt_byte_enable;
|
||||
wire cfg_mgmt_read;
|
||||
wire [2:0] cfg_fc_sel;
|
||||
wire [3:0] cfg_interrupt_msi_select;
|
||||
wire [31:0] cfg_interrupt_msi_int;
|
||||
wire [31:0] cfg_interrupt_msi_pending_status;
|
||||
wire cfg_interrupt_msi_pending_status_data_enable;
|
||||
wire [3:0] cfg_interrupt_msi_pending_status_function_num;
|
||||
wire [2:0] cfg_interrupt_msi_attr;
|
||||
wire cfg_interrupt_msi_tph_present;
|
||||
wire [1:0] cfg_interrupt_msi_tph_type;
|
||||
wire [8:0] cfg_interrupt_msi_tph_st_tag;
|
||||
wire [3:0] cfg_interrupt_msi_function_number;
|
||||
wire status_error_cor;
|
||||
wire status_error_uncor;
|
||||
wire [63:0] qsfp_0_txd_0;
|
||||
wire [7:0] qsfp_0_txc_0;
|
||||
wire [63:0] qsfp_0_txd_1;
|
||||
wire [7:0] qsfp_0_txc_1;
|
||||
wire [63:0] qsfp_0_txd_2;
|
||||
wire [7:0] qsfp_0_txc_2;
|
||||
wire [63:0] qsfp_0_txd_3;
|
||||
wire [7:0] qsfp_0_txc_3;
|
||||
wire qsfp_0_sel_l;
|
||||
wire [63:0] qsfp_1_txd_0;
|
||||
wire [7:0] qsfp_1_txc_0;
|
||||
wire [63:0] qsfp_1_txd_1;
|
||||
wire [7:0] qsfp_1_txc_1;
|
||||
wire [63:0] qsfp_1_txd_2;
|
||||
wire [7:0] qsfp_1_txc_2;
|
||||
wire [63:0] qsfp_1_txd_3;
|
||||
wire [7:0] qsfp_1_txc_3;
|
||||
wire qsfp_1_sel_l;
|
||||
wire qsfp_reset_l;
|
||||
wire qsfp_i2c_scl_o;
|
||||
wire qsfp_i2c_scl_t;
|
||||
wire qsfp_i2c_sda_o;
|
||||
wire qsfp_i2c_sda_t;
|
||||
wire eeprom_i2c_scl_o;
|
||||
wire eeprom_i2c_scl_t;
|
||||
wire eeprom_i2c_sda_o;
|
||||
wire eeprom_i2c_sda_t;
|
||||
wire eeprom_wp;
|
||||
wire fpga_boot;
|
||||
wire qspi_clk;
|
||||
wire [3:0] qspi_0_dq_o;
|
||||
wire [3:0] qspi_0_dq_oe;
|
||||
wire qspi_0_cs;
|
||||
wire [3:0] qspi_1_dq_o;
|
||||
wire [3:0] qspi_1_dq_oe;
|
||||
wire qspi_1_cs;
|
||||
|
||||
initial begin
|
||||
// myhdl integration
|
||||
$from_myhdl(
|
||||
clk_250mhz,
|
||||
rst_250mhz,
|
||||
current_test,
|
||||
user_sw,
|
||||
m_axis_rq_tready,
|
||||
s_axis_rc_tdata,
|
||||
s_axis_rc_tkeep,
|
||||
s_axis_rc_tlast,
|
||||
s_axis_rc_tuser,
|
||||
s_axis_rc_tvalid,
|
||||
s_axis_cq_tdata,
|
||||
s_axis_cq_tkeep,
|
||||
s_axis_cq_tlast,
|
||||
s_axis_cq_tuser,
|
||||
s_axis_cq_tvalid,
|
||||
m_axis_cc_tready,
|
||||
s_axis_rq_seq_num_0,
|
||||
s_axis_rq_seq_num_valid_0,
|
||||
s_axis_rq_seq_num_1,
|
||||
s_axis_rq_seq_num_valid_1,
|
||||
pcie_tfc_nph_av,
|
||||
pcie_tfc_npd_av,
|
||||
cfg_max_payload,
|
||||
cfg_max_read_req,
|
||||
cfg_mgmt_read_data,
|
||||
cfg_mgmt_read_write_done,
|
||||
cfg_fc_ph,
|
||||
cfg_fc_pd,
|
||||
cfg_fc_nph,
|
||||
cfg_fc_npd,
|
||||
cfg_fc_cplh,
|
||||
cfg_fc_cpld,
|
||||
cfg_interrupt_msi_enable,
|
||||
cfg_interrupt_msi_mmenable,
|
||||
cfg_interrupt_msi_mask_update,
|
||||
cfg_interrupt_msi_data,
|
||||
cfg_interrupt_msi_sent,
|
||||
cfg_interrupt_msi_fail,
|
||||
qsfp_0_tx_clk_0,
|
||||
qsfp_0_tx_rst_0,
|
||||
qsfp_0_rx_clk_0,
|
||||
qsfp_0_rx_rst_0,
|
||||
qsfp_0_rxd_0,
|
||||
qsfp_0_rxc_0,
|
||||
qsfp_0_tx_clk_1,
|
||||
qsfp_0_tx_rst_1,
|
||||
qsfp_0_rx_clk_1,
|
||||
qsfp_0_rx_rst_1,
|
||||
qsfp_0_rxd_1,
|
||||
qsfp_0_rxc_1,
|
||||
qsfp_0_tx_clk_2,
|
||||
qsfp_0_tx_rst_2,
|
||||
qsfp_0_rx_clk_2,
|
||||
qsfp_0_rx_rst_2,
|
||||
qsfp_0_rxd_2,
|
||||
qsfp_0_rxc_2,
|
||||
qsfp_0_tx_clk_3,
|
||||
qsfp_0_tx_rst_3,
|
||||
qsfp_0_rx_clk_3,
|
||||
qsfp_0_rx_rst_3,
|
||||
qsfp_0_rxd_3,
|
||||
qsfp_0_rxc_3,
|
||||
qsfp_0_modprs_l,
|
||||
qsfp_1_tx_clk_0,
|
||||
qsfp_1_tx_rst_0,
|
||||
qsfp_1_rx_clk_0,
|
||||
qsfp_1_rx_rst_0,
|
||||
qsfp_1_rxd_0,
|
||||
qsfp_1_rxc_0,
|
||||
qsfp_1_tx_clk_1,
|
||||
qsfp_1_tx_rst_1,
|
||||
qsfp_1_rx_clk_1,
|
||||
qsfp_1_rx_rst_1,
|
||||
qsfp_1_rxd_1,
|
||||
qsfp_1_rxc_1,
|
||||
qsfp_1_tx_clk_2,
|
||||
qsfp_1_tx_rst_2,
|
||||
qsfp_1_rx_clk_2,
|
||||
qsfp_1_rx_rst_2,
|
||||
qsfp_1_rxd_2,
|
||||
qsfp_1_rxc_2,
|
||||
qsfp_1_tx_clk_3,
|
||||
qsfp_1_tx_rst_3,
|
||||
qsfp_1_rx_clk_3,
|
||||
qsfp_1_rx_rst_3,
|
||||
qsfp_1_rxd_3,
|
||||
qsfp_1_rxc_3,
|
||||
qsfp_1_modprs_l,
|
||||
qsfp_int_l,
|
||||
qsfp_i2c_scl_i,
|
||||
qsfp_i2c_sda_i,
|
||||
eeprom_i2c_scl_i,
|
||||
eeprom_i2c_sda_i,
|
||||
qspi_0_dq_i,
|
||||
qspi_1_dq_i
|
||||
);
|
||||
$to_myhdl(
|
||||
user_led_g,
|
||||
user_led_r,
|
||||
front_led,
|
||||
m_axis_rq_tdata,
|
||||
m_axis_rq_tkeep,
|
||||
m_axis_rq_tlast,
|
||||
m_axis_rq_tuser,
|
||||
m_axis_rq_tvalid,
|
||||
s_axis_rc_tready,
|
||||
s_axis_cq_tready,
|
||||
m_axis_cc_tdata,
|
||||
m_axis_cc_tkeep,
|
||||
m_axis_cc_tlast,
|
||||
m_axis_cc_tuser,
|
||||
m_axis_cc_tvalid,
|
||||
cfg_mgmt_addr,
|
||||
cfg_mgmt_function_number,
|
||||
cfg_mgmt_write,
|
||||
cfg_mgmt_write_data,
|
||||
cfg_mgmt_byte_enable,
|
||||
cfg_mgmt_read,
|
||||
cfg_fc_sel,
|
||||
cfg_interrupt_msi_select,
|
||||
cfg_interrupt_msi_int,
|
||||
cfg_interrupt_msi_pending_status,
|
||||
cfg_interrupt_msi_pending_status_data_enable,
|
||||
cfg_interrupt_msi_pending_status_function_num,
|
||||
cfg_interrupt_msi_attr,
|
||||
cfg_interrupt_msi_tph_present,
|
||||
cfg_interrupt_msi_tph_type,
|
||||
cfg_interrupt_msi_tph_st_tag,
|
||||
cfg_interrupt_msi_function_number,
|
||||
status_error_cor,
|
||||
status_error_uncor,
|
||||
qsfp_0_txd_0,
|
||||
qsfp_0_txc_0,
|
||||
qsfp_0_txd_1,
|
||||
qsfp_0_txc_1,
|
||||
qsfp_0_txd_2,
|
||||
qsfp_0_txc_2,
|
||||
qsfp_0_txd_3,
|
||||
qsfp_0_txc_3,
|
||||
qsfp_0_sel_l,
|
||||
qsfp_1_txd_0,
|
||||
qsfp_1_txc_0,
|
||||
qsfp_1_txd_1,
|
||||
qsfp_1_txc_1,
|
||||
qsfp_1_txd_2,
|
||||
qsfp_1_txc_2,
|
||||
qsfp_1_txd_3,
|
||||
qsfp_1_txc_3,
|
||||
qsfp_1_sel_l,
|
||||
qsfp_reset_l,
|
||||
qsfp_i2c_scl_o,
|
||||
qsfp_i2c_scl_t,
|
||||
qsfp_i2c_sda_o,
|
||||
qsfp_i2c_sda_t,
|
||||
eeprom_i2c_scl_o,
|
||||
eeprom_i2c_scl_t,
|
||||
eeprom_i2c_sda_o,
|
||||
eeprom_i2c_sda_t,
|
||||
eeprom_wp,
|
||||
fpga_boot,
|
||||
qspi_clk,
|
||||
qspi_0_dq_o,
|
||||
qspi_0_dq_oe,
|
||||
qspi_0_cs,
|
||||
qspi_1_dq_o,
|
||||
qspi_1_dq_oe,
|
||||
qspi_1_cs
|
||||
);
|
||||
|
||||
// dump file
|
||||
$dumpfile("test_fpga_core.lxt");
|
||||
$dumpvars(0, test_fpga_core);
|
||||
end
|
||||
|
||||
fpga_core #(
|
||||
.AXIS_PCIE_DATA_WIDTH(AXIS_PCIE_DATA_WIDTH),
|
||||
.AXIS_PCIE_KEEP_WIDTH(AXIS_PCIE_KEEP_WIDTH),
|
||||
.AXIS_PCIE_RC_USER_WIDTH(AXIS_PCIE_RC_USER_WIDTH),
|
||||
.AXIS_PCIE_RQ_USER_WIDTH(AXIS_PCIE_RQ_USER_WIDTH),
|
||||
.AXIS_PCIE_CQ_USER_WIDTH(AXIS_PCIE_CQ_USER_WIDTH),
|
||||
.AXIS_PCIE_CC_USER_WIDTH(AXIS_PCIE_CC_USER_WIDTH),
|
||||
.RQ_SEQ_NUM_WIDTH(RQ_SEQ_NUM_WIDTH),
|
||||
.BAR0_APERTURE(BAR0_APERTURE)
|
||||
)
|
||||
UUT (
|
||||
.clk_250mhz(clk_250mhz),
|
||||
.rst_250mhz(rst_250mhz),
|
||||
.user_led_g(user_led_g),
|
||||
.user_led_r(user_led_r),
|
||||
.front_led(front_led),
|
||||
.user_sw(user_sw),
|
||||
.m_axis_rq_tdata(m_axis_rq_tdata),
|
||||
.m_axis_rq_tkeep(m_axis_rq_tkeep),
|
||||
.m_axis_rq_tlast(m_axis_rq_tlast),
|
||||
.m_axis_rq_tready(m_axis_rq_tready),
|
||||
.m_axis_rq_tuser(m_axis_rq_tuser),
|
||||
.m_axis_rq_tvalid(m_axis_rq_tvalid),
|
||||
.s_axis_rc_tdata(s_axis_rc_tdata),
|
||||
.s_axis_rc_tkeep(s_axis_rc_tkeep),
|
||||
.s_axis_rc_tlast(s_axis_rc_tlast),
|
||||
.s_axis_rc_tready(s_axis_rc_tready),
|
||||
.s_axis_rc_tuser(s_axis_rc_tuser),
|
||||
.s_axis_rc_tvalid(s_axis_rc_tvalid),
|
||||
.s_axis_cq_tdata(s_axis_cq_tdata),
|
||||
.s_axis_cq_tkeep(s_axis_cq_tkeep),
|
||||
.s_axis_cq_tlast(s_axis_cq_tlast),
|
||||
.s_axis_cq_tready(s_axis_cq_tready),
|
||||
.s_axis_cq_tuser(s_axis_cq_tuser),
|
||||
.s_axis_cq_tvalid(s_axis_cq_tvalid),
|
||||
.m_axis_cc_tdata(m_axis_cc_tdata),
|
||||
.m_axis_cc_tkeep(m_axis_cc_tkeep),
|
||||
.m_axis_cc_tlast(m_axis_cc_tlast),
|
||||
.m_axis_cc_tready(m_axis_cc_tready),
|
||||
.m_axis_cc_tuser(m_axis_cc_tuser),
|
||||
.m_axis_cc_tvalid(m_axis_cc_tvalid),
|
||||
.s_axis_rq_seq_num_0(s_axis_rq_seq_num_0),
|
||||
.s_axis_rq_seq_num_valid_0(s_axis_rq_seq_num_valid_0),
|
||||
.s_axis_rq_seq_num_1(s_axis_rq_seq_num_1),
|
||||
.s_axis_rq_seq_num_valid_1(s_axis_rq_seq_num_valid_1),
|
||||
.pcie_tfc_nph_av(pcie_tfc_nph_av),
|
||||
.pcie_tfc_npd_av(pcie_tfc_npd_av),
|
||||
.cfg_max_payload(cfg_max_payload),
|
||||
.cfg_max_read_req(cfg_max_read_req),
|
||||
.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),
|
||||
.status_error_cor(status_error_cor),
|
||||
.status_error_uncor(status_error_uncor),
|
||||
.qsfp_0_tx_clk_0(qsfp_0_tx_clk_0),
|
||||
.qsfp_0_tx_rst_0(qsfp_0_tx_rst_0),
|
||||
.qsfp_0_txd_0(qsfp_0_txd_0),
|
||||
.qsfp_0_txc_0(qsfp_0_txc_0),
|
||||
.qsfp_0_rx_clk_0(qsfp_0_rx_clk_0),
|
||||
.qsfp_0_rx_rst_0(qsfp_0_rx_rst_0),
|
||||
.qsfp_0_rxd_0(qsfp_0_rxd_0),
|
||||
.qsfp_0_rxc_0(qsfp_0_rxc_0),
|
||||
.qsfp_0_tx_clk_1(qsfp_0_tx_clk_1),
|
||||
.qsfp_0_tx_rst_1(qsfp_0_tx_rst_1),
|
||||
.qsfp_0_txd_1(qsfp_0_txd_1),
|
||||
.qsfp_0_txc_1(qsfp_0_txc_1),
|
||||
.qsfp_0_rx_clk_1(qsfp_0_rx_clk_1),
|
||||
.qsfp_0_rx_rst_1(qsfp_0_rx_rst_1),
|
||||
.qsfp_0_rxd_1(qsfp_0_rxd_1),
|
||||
.qsfp_0_rxc_1(qsfp_0_rxc_1),
|
||||
.qsfp_0_tx_clk_2(qsfp_0_tx_clk_2),
|
||||
.qsfp_0_tx_rst_2(qsfp_0_tx_rst_2),
|
||||
.qsfp_0_txd_2(qsfp_0_txd_2),
|
||||
.qsfp_0_txc_2(qsfp_0_txc_2),
|
||||
.qsfp_0_rx_clk_2(qsfp_0_rx_clk_2),
|
||||
.qsfp_0_rx_rst_2(qsfp_0_rx_rst_2),
|
||||
.qsfp_0_rxd_2(qsfp_0_rxd_2),
|
||||
.qsfp_0_rxc_2(qsfp_0_rxc_2),
|
||||
.qsfp_0_tx_clk_3(qsfp_0_tx_clk_3),
|
||||
.qsfp_0_tx_rst_3(qsfp_0_tx_rst_3),
|
||||
.qsfp_0_txd_3(qsfp_0_txd_3),
|
||||
.qsfp_0_txc_3(qsfp_0_txc_3),
|
||||
.qsfp_0_rx_clk_3(qsfp_0_rx_clk_3),
|
||||
.qsfp_0_rx_rst_3(qsfp_0_rx_rst_3),
|
||||
.qsfp_0_rxd_3(qsfp_0_rxd_3),
|
||||
.qsfp_0_rxc_3(qsfp_0_rxc_3),
|
||||
.qsfp_0_modprs_l(qsfp_0_modprs_l),
|
||||
.qsfp_0_sel_l(qsfp_0_sel_l),
|
||||
.qsfp_1_tx_clk_0(qsfp_1_tx_clk_0),
|
||||
.qsfp_1_tx_rst_0(qsfp_1_tx_rst_0),
|
||||
.qsfp_1_txd_0(qsfp_1_txd_0),
|
||||
.qsfp_1_txc_0(qsfp_1_txc_0),
|
||||
.qsfp_1_rx_clk_0(qsfp_1_rx_clk_0),
|
||||
.qsfp_1_rx_rst_0(qsfp_1_rx_rst_0),
|
||||
.qsfp_1_rxd_0(qsfp_1_rxd_0),
|
||||
.qsfp_1_rxc_0(qsfp_1_rxc_0),
|
||||
.qsfp_1_tx_clk_1(qsfp_1_tx_clk_1),
|
||||
.qsfp_1_tx_rst_1(qsfp_1_tx_rst_1),
|
||||
.qsfp_1_txd_1(qsfp_1_txd_1),
|
||||
.qsfp_1_txc_1(qsfp_1_txc_1),
|
||||
.qsfp_1_rx_clk_1(qsfp_1_rx_clk_1),
|
||||
.qsfp_1_rx_rst_1(qsfp_1_rx_rst_1),
|
||||
.qsfp_1_rxd_1(qsfp_1_rxd_1),
|
||||
.qsfp_1_rxc_1(qsfp_1_rxc_1),
|
||||
.qsfp_1_tx_clk_2(qsfp_1_tx_clk_2),
|
||||
.qsfp_1_tx_rst_2(qsfp_1_tx_rst_2),
|
||||
.qsfp_1_txd_2(qsfp_1_txd_2),
|
||||
.qsfp_1_txc_2(qsfp_1_txc_2),
|
||||
.qsfp_1_rx_clk_2(qsfp_1_rx_clk_2),
|
||||
.qsfp_1_rx_rst_2(qsfp_1_rx_rst_2),
|
||||
.qsfp_1_rxd_2(qsfp_1_rxd_2),
|
||||
.qsfp_1_rxc_2(qsfp_1_rxc_2),
|
||||
.qsfp_1_tx_clk_3(qsfp_1_tx_clk_3),
|
||||
.qsfp_1_tx_rst_3(qsfp_1_tx_rst_3),
|
||||
.qsfp_1_txd_3(qsfp_1_txd_3),
|
||||
.qsfp_1_txc_3(qsfp_1_txc_3),
|
||||
.qsfp_1_rx_clk_3(qsfp_1_rx_clk_3),
|
||||
.qsfp_1_rx_rst_3(qsfp_1_rx_rst_3),
|
||||
.qsfp_1_rxd_3(qsfp_1_rxd_3),
|
||||
.qsfp_1_rxc_3(qsfp_1_rxc_3),
|
||||
.qsfp_1_modprs_l(qsfp_1_modprs_l),
|
||||
.qsfp_1_sel_l(qsfp_1_sel_l),
|
||||
.qsfp_reset_l(qsfp_reset_l),
|
||||
.qsfp_int_l(qsfp_int_l),
|
||||
.qsfp_i2c_scl_i(qsfp_i2c_scl_i),
|
||||
.qsfp_i2c_scl_o(qsfp_i2c_scl_o),
|
||||
.qsfp_i2c_scl_t(qsfp_i2c_scl_t),
|
||||
.qsfp_i2c_sda_i(qsfp_i2c_sda_i),
|
||||
.qsfp_i2c_sda_o(qsfp_i2c_sda_o),
|
||||
.qsfp_i2c_sda_t(qsfp_i2c_sda_t),
|
||||
.eeprom_i2c_scl_i(eeprom_i2c_scl_i),
|
||||
.eeprom_i2c_scl_o(eeprom_i2c_scl_o),
|
||||
.eeprom_i2c_scl_t(eeprom_i2c_scl_t),
|
||||
.eeprom_i2c_sda_i(eeprom_i2c_sda_i),
|
||||
.eeprom_i2c_sda_o(eeprom_i2c_sda_o),
|
||||
.eeprom_i2c_sda_t(eeprom_i2c_sda_t),
|
||||
.eeprom_wp(eeprom_wp),
|
||||
.fpga_boot(fpga_boot),
|
||||
.qspi_clk(qspi_clk),
|
||||
.qspi_0_dq_i(qspi_0_dq_i),
|
||||
.qspi_0_dq_o(qspi_0_dq_o),
|
||||
.qspi_0_dq_oe(qspi_0_dq_oe),
|
||||
.qspi_0_cs(qspi_0_cs),
|
||||
.qspi_1_dq_i(qspi_1_dq_i),
|
||||
.qspi_1_dq_o(qspi_1_dq_o),
|
||||
.qspi_1_dq_oe(qspi_1_dq_oe),
|
||||
.qspi_1_cs(qspi_1_cs)
|
||||
);
|
||||
|
||||
endmodule
|
@ -1 +0,0 @@
|
||||
../lib/eth/tb/udp_ep.py
|
@ -1 +0,0 @@
|
||||
../lib/eth/tb/xgmii_ep.py
|
@ -1 +0,0 @@
|
||||
../lib/eth/tb/axis_ep.py
|
@ -1 +0,0 @@
|
||||
../lib/eth/tb/eth_ep.py
|
153
fpga/mqnic/AU200/fpga_100g/tb/fpga_core/Makefile
Normal file
153
fpga/mqnic/AU200/fpga_100g/tb/fpga_core/Makefile
Normal file
@ -0,0 +1,153 @@
|
||||
# Copyright 2020, The Regents of the University of California.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
#
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
|
||||
# IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
|
||||
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
# OF SUCH DAMAGE.
|
||||
#
|
||||
# The views and conclusions contained in the software and documentation are those
|
||||
# of the authors and should not be interpreted as representing official policies,
|
||||
# either expressed or implied, of The Regents of the University of California.
|
||||
|
||||
TOPLEVEL_LANG = verilog
|
||||
|
||||
SIM ?= icarus
|
||||
WAVES ?= 0
|
||||
|
||||
COCOTB_HDL_TIMEUNIT = 1ns
|
||||
COCOTB_HDL_TIMEPRECISION = 1ps
|
||||
|
||||
DUT = fpga_core
|
||||
TOPLEVEL = $(DUT)
|
||||
MODULE = test_$(DUT)
|
||||
VERILOG_SOURCES += ../../rtl/$(DUT).v
|
||||
VERILOG_SOURCES += ../../rtl/common/mqnic_interface.v
|
||||
VERILOG_SOURCES += ../../rtl/common/mqnic_port.v
|
||||
VERILOG_SOURCES += ../../rtl/common/cpl_write.v
|
||||
VERILOG_SOURCES += ../../rtl/common/cpl_op_mux.v
|
||||
VERILOG_SOURCES += ../../rtl/common/desc_fetch.v
|
||||
VERILOG_SOURCES += ../../rtl/common/desc_op_mux.v
|
||||
VERILOG_SOURCES += ../../rtl/common/queue_manager.v
|
||||
VERILOG_SOURCES += ../../rtl/common/cpl_queue_manager.v
|
||||
VERILOG_SOURCES += ../../rtl/common/tx_engine.v
|
||||
VERILOG_SOURCES += ../../rtl/common/rx_engine.v
|
||||
VERILOG_SOURCES += ../../rtl/common/tx_checksum.v
|
||||
VERILOG_SOURCES += ../../rtl/common/rx_hash.v
|
||||
VERILOG_SOURCES += ../../rtl/common/rx_checksum.v
|
||||
VERILOG_SOURCES += ../../rtl/common/tx_scheduler_rr.v
|
||||
VERILOG_SOURCES += ../../rtl/common/event_mux.v
|
||||
VERILOG_SOURCES += ../../rtl/common/tdma_scheduler.v
|
||||
VERILOG_SOURCES += ../../rtl/common/tdma_ber.v
|
||||
VERILOG_SOURCES += ../../rtl/common/tdma_ber_ch.v
|
||||
VERILOG_SOURCES += ../../lib/eth/rtl/ptp_clock.v
|
||||
VERILOG_SOURCES += ../../lib/eth/rtl/ptp_clock_cdc.v
|
||||
VERILOG_SOURCES += ../../lib/eth/rtl/ptp_perout.v
|
||||
VERILOG_SOURCES += ../../lib/eth/rtl/ptp_ts_extract.v
|
||||
VERILOG_SOURCES += ../../lib/axi/rtl/axil_interconnect.v
|
||||
VERILOG_SOURCES += ../../lib/axi/rtl/arbiter.v
|
||||
VERILOG_SOURCES += ../../lib/axi/rtl/priority_encoder.v
|
||||
VERILOG_SOURCES += ../../lib/axis/rtl/axis_adapter.v
|
||||
VERILOG_SOURCES += ../../lib/axis/rtl/axis_arb_mux.v
|
||||
VERILOG_SOURCES += ../../lib/axis/rtl/axis_async_fifo.v
|
||||
VERILOG_SOURCES += ../../lib/axis/rtl/axis_async_fifo_adapter.v
|
||||
VERILOG_SOURCES += ../../lib/axis/rtl/axis_fifo.v
|
||||
VERILOG_SOURCES += ../../lib/axis/rtl/axis_register.v
|
||||
VERILOG_SOURCES += ../../lib/pcie/rtl/pcie_us_axil_master.v
|
||||
VERILOG_SOURCES += ../../lib/pcie/rtl/dma_if_pcie_us.v
|
||||
VERILOG_SOURCES += ../../lib/pcie/rtl/dma_if_pcie_us_rd.v
|
||||
VERILOG_SOURCES += ../../lib/pcie/rtl/dma_if_pcie_us_wr.v
|
||||
VERILOG_SOURCES += ../../lib/pcie/rtl/dma_if_mux.v
|
||||
VERILOG_SOURCES += ../../lib/pcie/rtl/dma_if_mux_rd.v
|
||||
VERILOG_SOURCES += ../../lib/pcie/rtl/dma_if_mux_wr.v
|
||||
VERILOG_SOURCES += ../../lib/pcie/rtl/dma_psdpram.v
|
||||
VERILOG_SOURCES += ../../lib/pcie/rtl/dma_client_axis_sink.v
|
||||
VERILOG_SOURCES += ../../lib/pcie/rtl/dma_client_axis_source.v
|
||||
VERILOG_SOURCES += ../../lib/pcie/rtl/pcie_us_cfg.v
|
||||
VERILOG_SOURCES += ../../lib/pcie/rtl/pcie_us_msi.v
|
||||
VERILOG_SOURCES += ../../lib/pcie/rtl/pcie_tag_manager.v
|
||||
VERILOG_SOURCES += ../../lib/pcie/rtl/pulse_merge.v
|
||||
|
||||
# module parameters
|
||||
export PARAM_AXIS_PCIE_DATA_WIDTH ?= 512
|
||||
export PARAM_AXIS_PCIE_KEEP_WIDTH ?= $(shell expr $(PARAM_AXIS_PCIE_DATA_WIDTH) / 32 )
|
||||
export PARAM_AXIS_PCIE_RQ_USER_WIDTH ?= $(if $(filter-out 512,$(PARAM_AXIS_PCIE_DATA_WIDTH)),62,137)
|
||||
export PARAM_AXIS_PCIE_RC_USER_WIDTH ?= $(if $(filter-out 512,$(PARAM_AXIS_PCIE_DATA_WIDTH)),75,161)
|
||||
export PARAM_AXIS_PCIE_CQ_USER_WIDTH ?= $(if $(filter-out 512,$(PARAM_AXIS_PCIE_DATA_WIDTH)),88,183)
|
||||
export PARAM_AXIS_PCIE_CC_USER_WIDTH ?= $(if $(filter-out 512,$(PARAM_AXIS_PCIE_DATA_WIDTH)),33,81)
|
||||
export PARAM_RQ_SEQ_NUM_WIDTH ?= 6
|
||||
export PARAM_BAR0_APERTURE ?= 24
|
||||
export PARAM_AXIS_ETH_DATA_WIDTH = 512
|
||||
export PARAM_AXIS_ETH_KEEP_WIDTH = $(shell expr $(PARAM_AXIS_ETH_DATA_WIDTH) / 8 )
|
||||
|
||||
SIM_BUILD ?= sim_build_$(MODULE)
|
||||
|
||||
ifeq ($(SIM), icarus)
|
||||
PLUSARGS += -fst
|
||||
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).AXIS_PCIE_DATA_WIDTH=$(PARAM_AXIS_PCIE_DATA_WIDTH)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).AXIS_PCIE_KEEP_WIDTH=$(PARAM_AXIS_PCIE_KEEP_WIDTH)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).AXIS_PCIE_RQ_USER_WIDTH=$(PARAM_AXIS_PCIE_RQ_USER_WIDTH)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).AXIS_PCIE_RC_USER_WIDTH=$(PARAM_AXIS_PCIE_RC_USER_WIDTH)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).AXIS_PCIE_CQ_USER_WIDTH=$(PARAM_AXIS_PCIE_CQ_USER_WIDTH)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).AXIS_PCIE_CC_USER_WIDTH=$(PARAM_AXIS_PCIE_CC_USER_WIDTH)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).RQ_SEQ_NUM_WIDTH=$(PARAM_RQ_SEQ_NUM_WIDTH)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).BAR0_APERTURE=$(PARAM_BAR0_APERTURE)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).AXIS_ETH_DATA_WIDTH=$(PARAM_AXIS_ETH_DATA_WIDTH)
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).AXIS_ETH_KEEP_WIDTH=$(PARAM_AXIS_ETH_KEEP_WIDTH)
|
||||
|
||||
ifeq ($(WAVES), 1)
|
||||
VERILOG_SOURCES += iverilog_dump.v
|
||||
COMPILE_ARGS += -s iverilog_dump
|
||||
endif
|
||||
else ifeq ($(SIM), verilator)
|
||||
COMPILE_ARGS += -Wno-SELRANGE -Wno-WIDTH
|
||||
|
||||
COMPILE_ARGS += -GAXIS_PCIE_DATA_WIDTH=$(PARAM_AXIS_PCIE_DATA_WIDTH)
|
||||
COMPILE_ARGS += -GAXIS_PCIE_KEEP_WIDTH=$(PARAM_AXIS_PCIE_KEEP_WIDTH)
|
||||
COMPILE_ARGS += -GAXIS_PCIE_RQ_USER_WIDTH=$(PARAM_AXIS_PCIE_RQ_USER_WIDTH)
|
||||
COMPILE_ARGS += -GAXIS_PCIE_RC_USER_WIDTH=$(PARAM_AXIS_PCIE_RC_USER_WIDTH)
|
||||
COMPILE_ARGS += -GAXIS_PCIE_CQ_USER_WIDTH=$(PARAM_AXIS_PCIE_CQ_USER_WIDTH)
|
||||
COMPILE_ARGS += -GAXIS_PCIE_CC_USER_WIDTH=$(PARAM_AXIS_PCIE_CC_USER_WIDTH)
|
||||
COMPILE_ARGS += -GRQ_SEQ_NUM_WIDTH=$(PARAM_RQ_SEQ_NUM_WIDTH)
|
||||
COMPILE_ARGS += -GBAR0_APERTURE=$(PARAM_BAR0_APERTURE)
|
||||
COMPILE_ARGS += -GAXIS_ETH_DATA_WIDTH=$(PARAM_AXIS_ETH_DATA_WIDTH)
|
||||
COMPILE_ARGS += -GAXIS_ETH_KEEP_WIDTH=$(PARAM_AXIS_ETH_KEEP_WIDTH)
|
||||
|
||||
ifeq ($(WAVES), 1)
|
||||
COMPILE_ARGS += --trace-fst
|
||||
endif
|
||||
endif
|
||||
|
||||
iverilog_dump.v:
|
||||
echo 'module iverilog_dump();' > $@
|
||||
echo 'initial begin' >> $@
|
||||
echo ' $$dumpfile("$(TOPLEVEL).fst");' >> $@
|
||||
echo ' $$dumpvars(0, $(TOPLEVEL));' >> $@
|
||||
echo 'end' >> $@
|
||||
echo 'endmodule' >> $@
|
||||
|
||||
clean::
|
||||
@rm -rf sim_build_*
|
||||
@rm -rf iverilog_dump.v
|
||||
@rm -rf dump.fst $(TOPLEVEL).fst
|
||||
|
||||
include $(shell cocotb-config --makefiles)/Makefile.sim
|
||||
|
1
fpga/mqnic/AU200/fpga_100g/tb/fpga_core/mqnic.py
Symbolic link
1
fpga/mqnic/AU200/fpga_100g/tb/fpga_core/mqnic.py
Symbolic link
@ -0,0 +1 @@
|
||||
../../../../../common/tb/mqnic.py
|
585
fpga/mqnic/AU200/fpga_100g/tb/fpga_core/test_fpga_core.py
Normal file
585
fpga/mqnic/AU200/fpga_100g/tb/fpga_core/test_fpga_core.py
Normal file
@ -0,0 +1,585 @@
|
||||
"""
|
||||
|
||||
Copyright 2020, The Regents of the University of California.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
|
||||
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of The Regents of the University of California.
|
||||
|
||||
"""
|
||||
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
|
||||
import scapy.utils
|
||||
from scapy.layers.l2 import Ether
|
||||
from scapy.layers.inet import IP, UDP
|
||||
|
||||
import cocotb_test.simulator
|
||||
|
||||
import cocotb
|
||||
from cocotb.log import SimLog
|
||||
from cocotb.clock import Clock
|
||||
from cocotb.triggers import RisingEdge, FallingEdge, Timer
|
||||
|
||||
from cocotbext.pcie.core import RootComplex
|
||||
from cocotbext.pcie.xilinx.us import UltraScalePlusPcieDevice
|
||||
|
||||
from cocotbext.axi import AxiStreamSource, AxiStreamSink
|
||||
|
||||
try:
|
||||
import mqnic
|
||||
except ImportError:
|
||||
# attempt import from current directory
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__)))
|
||||
try:
|
||||
import mqnic
|
||||
finally:
|
||||
del sys.path[0]
|
||||
|
||||
|
||||
class TB(object):
|
||||
def __init__(self, dut):
|
||||
self.dut = dut
|
||||
|
||||
self.BAR0_APERTURE = int(os.getenv("PARAM_BAR0_APERTURE"))
|
||||
|
||||
self.log = SimLog("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_cc_straddle=False,
|
||||
rq_rc_straddle=False,
|
||||
rc_4tlp_straddle=False,
|
||||
enable_pf1=False,
|
||||
enable_client_tag=True,
|
||||
enable_extended_tag=True,
|
||||
enable_parity=False,
|
||||
enable_rx_msg_interface=False,
|
||||
enable_sriov=False,
|
||||
enable_extended_configuration=False,
|
||||
|
||||
enable_pf0_msi=True,
|
||||
enable_pf1_msi=False,
|
||||
|
||||
# signals
|
||||
# Clock and Reset Interface
|
||||
user_clk=dut.clk_250mhz,
|
||||
user_reset=dut.rst_250mhz,
|
||||
# user_lnk_up
|
||||
# sys_clk
|
||||
# sys_clk_gt
|
||||
# sys_reset
|
||||
# phy_rdy_out
|
||||
|
||||
# Requester reQuest Interface
|
||||
rq_entity=dut,
|
||||
rq_name="m_axis_rq",
|
||||
pcie_rq_seq_num0=dut.s_axis_rq_seq_num_0,
|
||||
pcie_rq_seq_num_vld0=dut.s_axis_rq_seq_num_valid_0,
|
||||
pcie_rq_seq_num1=dut.s_axis_rq_seq_num_1,
|
||||
pcie_rq_seq_num_vld1=dut.s_axis_rq_seq_num_valid_1,
|
||||
# pcie_rq_tag0
|
||||
# pcie_rq_tag1
|
||||
# pcie_rq_tag_av
|
||||
# pcie_rq_tag_vld0
|
||||
# pcie_rq_tag_vld1
|
||||
|
||||
# Requester Completion Interface
|
||||
rc_entity=dut,
|
||||
rc_name="s_axis_rc",
|
||||
|
||||
# Completer reQuest Interface
|
||||
cq_entity=dut,
|
||||
cq_name="s_axis_cq",
|
||||
# pcie_cq_np_req
|
||||
# pcie_cq_np_req_count
|
||||
|
||||
# Completer Completion Interface
|
||||
cc_entity=dut,
|
||||
cc_name="m_axis_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
|
||||
# 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
|
||||
# cfg_interrupt_msix_mask
|
||||
# cfg_interrupt_msix_vf_enable
|
||||
# cfg_interrupt_msix_vf_mask
|
||||
# cfg_interrupt_msix_address
|
||||
# cfg_interrupt_msix_data
|
||||
# cfg_interrupt_msix_int
|
||||
# cfg_interrupt_msix_vec_pending
|
||||
# cfg_interrupt_msix_vec_pending_status
|
||||
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.driver = mqnic.Driver(self.rc)
|
||||
|
||||
self.dev.functions[0].msi_multiple_message_capable = 5
|
||||
|
||||
self.dev.functions[0].configure_bar(0, 2**self.BAR0_APERTURE, ext=True, prefetch=True)
|
||||
|
||||
# Ethernet
|
||||
cocotb.fork(Clock(dut.qsfp0_rx_clk, 3.102, units="ns").start())
|
||||
self.qsfp0_source = AxiStreamSource(dut, "qsfp0_rx_axis", dut.qsfp0_rx_clk, dut.qsfp0_rx_rst)
|
||||
cocotb.fork(Clock(dut.qsfp0_tx_clk, 3.102, units="ns").start())
|
||||
self.qsfp0_sink = AxiStreamSink(dut, "qsfp0_tx_axis", dut.qsfp0_tx_clk, dut.qsfp0_tx_rst)
|
||||
|
||||
cocotb.fork(Clock(dut.qsfp1_rx_clk, 3.102, units="ns").start())
|
||||
self.qsfp1_source = AxiStreamSource(dut, "qsfp1_rx_axis", dut.qsfp1_rx_clk, dut.qsfp1_rx_rst)
|
||||
cocotb.fork(Clock(dut.qsfp1_tx_clk, 3.102, units="ns").start())
|
||||
self.qsfp1_sink = AxiStreamSink(dut, "qsfp1_tx_axis", dut.qsfp1_tx_clk, dut.qsfp1_tx_rst)
|
||||
|
||||
dut.sw.setimmediatevalue(0)
|
||||
|
||||
dut.i2c_scl_i.setimmediatevalue(1)
|
||||
dut.i2c_sda_i.setimmediatevalue(1)
|
||||
|
||||
dut.qsfp0_modprsl.setimmediatevalue(0)
|
||||
dut.qsfp0_intl.setimmediatevalue(1)
|
||||
|
||||
dut.qsfp1_modprsl.setimmediatevalue(0)
|
||||
dut.qsfp1_intl.setimmediatevalue(1)
|
||||
|
||||
dut.qspi_dq_i.setimmediatevalue(0)
|
||||
|
||||
self.loopback_enable = False
|
||||
cocotb.fork(self._run_loopback())
|
||||
|
||||
async def init(self):
|
||||
|
||||
self.dut.qsfp0_rx_rst.setimmediatevalue(0)
|
||||
self.dut.qsfp0_tx_rst.setimmediatevalue(0)
|
||||
self.dut.qsfp1_rx_rst.setimmediatevalue(0)
|
||||
self.dut.qsfp1_tx_rst.setimmediatevalue(0)
|
||||
|
||||
await RisingEdge(self.dut.clk_250mhz)
|
||||
await RisingEdge(self.dut.clk_250mhz)
|
||||
|
||||
self.dut.qsfp0_rx_rst.setimmediatevalue(1)
|
||||
self.dut.qsfp0_tx_rst.setimmediatevalue(1)
|
||||
self.dut.qsfp1_rx_rst.setimmediatevalue(1)
|
||||
self.dut.qsfp1_tx_rst.setimmediatevalue(1)
|
||||
|
||||
await FallingEdge(self.dut.rst_250mhz)
|
||||
await Timer(100, 'ns')
|
||||
|
||||
await RisingEdge(self.dut.clk_250mhz)
|
||||
await RisingEdge(self.dut.clk_250mhz)
|
||||
|
||||
self.dut.qsfp0_rx_rst.setimmediatevalue(0)
|
||||
self.dut.qsfp0_tx_rst.setimmediatevalue(0)
|
||||
self.dut.qsfp1_rx_rst.setimmediatevalue(0)
|
||||
self.dut.qsfp1_tx_rst.setimmediatevalue(0)
|
||||
|
||||
await self.rc.enumerate(enable_bus_mastering=True, configure_msi=True)
|
||||
|
||||
async def _run_loopback(self):
|
||||
while True:
|
||||
await RisingEdge(self.dut.clk_250mhz)
|
||||
|
||||
if self.loopback_enable:
|
||||
if not self.qsfp0_sink.empty():
|
||||
self.qsfp0_source.send(self.qsfp0_sink.recv())
|
||||
if not self.qsfp1_sink.empty():
|
||||
self.qsfp1_source.send(self.qsfp1_sink.recv())
|
||||
|
||||
|
||||
@cocotb.test()
|
||||
async def run_test_nic(dut):
|
||||
|
||||
tb = TB(dut)
|
||||
|
||||
await tb.init()
|
||||
|
||||
tb.log.info("Init driver")
|
||||
await tb.driver.init_dev(tb.dev.functions[0].pcie_id)
|
||||
await tb.driver.interfaces[0].open()
|
||||
# await driver.interfaces[1].open()
|
||||
|
||||
# enable queues
|
||||
tb.log.info("Enable queues")
|
||||
await tb.rc.mem_write_dword(tb.driver.interfaces[0].ports[0].hw_addr+mqnic.MQNIC_PORT_REG_SCHED_ENABLE, 0x00000001)
|
||||
for k in range(tb.driver.interfaces[0].tx_queue_count):
|
||||
await tb.rc.mem_write_dword(tb.driver.interfaces[0].ports[0].schedulers[0].hw_addr+4*k, 0x00000003)
|
||||
|
||||
# wait for all writes to complete
|
||||
await tb.rc.mem_read(tb.driver.hw_addr, 4)
|
||||
tb.log.info("Init complete")
|
||||
|
||||
tb.log.info("Send and receive single packet")
|
||||
|
||||
data = bytearray([x % 256 for x in range(1024)])
|
||||
|
||||
await tb.driver.interfaces[0].start_xmit(data, 0)
|
||||
|
||||
await tb.qsfp0_sink.wait()
|
||||
|
||||
pkt = tb.qsfp0_sink.recv()
|
||||
tb.log.info("Packet: %s", pkt)
|
||||
|
||||
tb.qsfp0_source.send(pkt)
|
||||
|
||||
await tb.driver.interfaces[0].wait()
|
||||
|
||||
pkt = tb.driver.interfaces[0].recv()
|
||||
|
||||
tb.log.info("Packet: %s", pkt)
|
||||
assert pkt.rx_checksum == ~scapy.utils.checksum(bytes(pkt.data[14:])) & 0xffff
|
||||
|
||||
# await tb.driver.interfaces[1].start_xmit(data, 0)
|
||||
|
||||
# await tb.qsfp1_0_sink.wait()
|
||||
|
||||
# pkt = tb.qsfp1_0_sink.recv()
|
||||
# tb.log.info("Packet: %s", pkt)
|
||||
|
||||
# tb.qsfp1_0_source.send(pkt)
|
||||
|
||||
# await tb.driver.interfaces[1].wait()
|
||||
|
||||
# pkt = tb.driver.interfaces[1].recv()
|
||||
|
||||
# tb.log.info("Packet: %s", pkt)
|
||||
# assert pkt.rx_checksum == ~scapy.utils.checksum(bytes(pkt.data[14:])) & 0xffff
|
||||
|
||||
tb.log.info("RX and TX checksum tests")
|
||||
|
||||
payload = bytes([x % 256 for x in range(256)])
|
||||
eth = Ether(src='5A:51:52:53:54:55', dst='DA:D1:D2:D3:D4:D5')
|
||||
ip = IP(src='192.168.1.100', dst='192.168.1.101')
|
||||
udp = UDP(sport=1, dport=2)
|
||||
test_pkt = eth / ip / udp / payload
|
||||
|
||||
test_pkt2 = test_pkt.copy()
|
||||
test_pkt2[UDP].chksum = scapy.utils.checksum(bytes(test_pkt2[UDP]))
|
||||
|
||||
await tb.driver.interfaces[0].start_xmit(test_pkt2.build(), 0, 34, 6)
|
||||
|
||||
await tb.qsfp0_sink.wait()
|
||||
|
||||
pkt = tb.qsfp0_sink.recv()
|
||||
tb.log.info("Packet: %s", pkt)
|
||||
|
||||
tb.qsfp0_source.send(pkt)
|
||||
|
||||
await tb.driver.interfaces[0].wait()
|
||||
|
||||
pkt = tb.driver.interfaces[0].recv()
|
||||
|
||||
tb.log.info("Packet: %s", pkt)
|
||||
assert pkt.rx_checksum == ~scapy.utils.checksum(bytes(pkt.data[14:])) & 0xffff
|
||||
assert Ether(pkt.data).build() == test_pkt.build()
|
||||
|
||||
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 tb.driver.interfaces[0].start_xmit(p, 0)
|
||||
|
||||
for k in range(count):
|
||||
await tb.driver.interfaces[0].wait()
|
||||
pkt = tb.driver.interfaces[0].recv()
|
||||
|
||||
tb.log.info("Packet: %s", pkt)
|
||||
assert pkt.data == pkts[k]
|
||||
assert pkt.rx_checksum == ~scapy.utils.checksum(bytes(pkt.data[14:])) & 0xffff
|
||||
|
||||
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 tb.driver.interfaces[0].start_xmit(p, 0)
|
||||
|
||||
for k in range(count):
|
||||
await tb.driver.interfaces[0].wait()
|
||||
pkt = tb.driver.interfaces[0].recv()
|
||||
|
||||
tb.log.info("Packet: %s", pkt)
|
||||
assert pkt.data == pkts[k]
|
||||
assert pkt.rx_checksum == ~scapy.utils.checksum(bytes(pkt.data[14:])) & 0xffff
|
||||
|
||||
tb.loopback_enable = False
|
||||
|
||||
tb.log.info("Jumbo frames")
|
||||
|
||||
count = 64
|
||||
|
||||
pkts = [bytearray([(x+k) % 256 for x in range(9014)]) for k in range(count)]
|
||||
|
||||
tb.loopback_enable = True
|
||||
|
||||
for p in pkts:
|
||||
await tb.driver.interfaces[0].start_xmit(p, 0)
|
||||
|
||||
for k in range(count):
|
||||
await tb.driver.interfaces[0].wait()
|
||||
pkt = tb.driver.interfaces[0].recv()
|
||||
|
||||
tb.log.info("Packet: %s", pkt)
|
||||
assert pkt.data == pkts[k]
|
||||
assert pkt.rx_checksum == ~scapy.utils.checksum(bytes(pkt.data[14:])) & 0xffff
|
||||
|
||||
tb.loopback_enable = False
|
||||
|
||||
await RisingEdge(dut.clk_250mhz)
|
||||
await RisingEdge(dut.clk_250mhz)
|
||||
|
||||
|
||||
# cocotb-test
|
||||
|
||||
tests_dir = os.path.dirname(__file__)
|
||||
rtl_dir = os.path.abspath(os.path.join(tests_dir, '..', '..', 'rtl'))
|
||||
lib_dir = os.path.abspath(os.path.join(rtl_dir, '..', 'lib'))
|
||||
axi_rtl_dir = os.path.abspath(os.path.join(lib_dir, 'axi', 'rtl'))
|
||||
axis_rtl_dir = os.path.abspath(os.path.join(lib_dir, 'axis', 'rtl'))
|
||||
eth_rtl_dir = os.path.abspath(os.path.join(lib_dir, 'eth', 'rtl'))
|
||||
pcie_rtl_dir = os.path.abspath(os.path.join(lib_dir, 'pcie', 'rtl'))
|
||||
|
||||
|
||||
def test_fpga_core(request):
|
||||
dut = "fpga_core"
|
||||
module = os.path.splitext(os.path.basename(__file__))[0]
|
||||
toplevel = dut
|
||||
|
||||
verilog_sources = [
|
||||
os.path.join(rtl_dir, f"{dut}.v"),
|
||||
os.path.join(rtl_dir, "common", "mqnic_interface.v"),
|
||||
os.path.join(rtl_dir, "common", "mqnic_port.v"),
|
||||
os.path.join(rtl_dir, "common", "cpl_write.v"),
|
||||
os.path.join(rtl_dir, "common", "cpl_op_mux.v"),
|
||||
os.path.join(rtl_dir, "common", "desc_fetch.v"),
|
||||
os.path.join(rtl_dir, "common", "desc_op_mux.v"),
|
||||
os.path.join(rtl_dir, "common", "queue_manager.v"),
|
||||
os.path.join(rtl_dir, "common", "cpl_queue_manager.v"),
|
||||
os.path.join(rtl_dir, "common", "tx_engine.v"),
|
||||
os.path.join(rtl_dir, "common", "rx_engine.v"),
|
||||
os.path.join(rtl_dir, "common", "tx_checksum.v"),
|
||||
os.path.join(rtl_dir, "common", "rx_hash.v"),
|
||||
os.path.join(rtl_dir, "common", "rx_checksum.v"),
|
||||
os.path.join(rtl_dir, "common", "tx_scheduler_rr.v"),
|
||||
os.path.join(rtl_dir, "common", "event_mux.v"),
|
||||
os.path.join(rtl_dir, "common", "tdma_scheduler.v"),
|
||||
os.path.join(rtl_dir, "common", "tdma_ber.v"),
|
||||
os.path.join(rtl_dir, "common", "tdma_ber_ch.v"),
|
||||
os.path.join(eth_rtl_dir, "ptp_clock.v"),
|
||||
os.path.join(eth_rtl_dir, "ptp_clock_cdc.v"),
|
||||
os.path.join(eth_rtl_dir, "ptp_perout.v"),
|
||||
os.path.join(eth_rtl_dir, "ptp_ts_extract.v"),
|
||||
os.path.join(axi_rtl_dir, "axil_interconnect.v"),
|
||||
os.path.join(axi_rtl_dir, "arbiter.v"),
|
||||
os.path.join(axi_rtl_dir, "priority_encoder.v"),
|
||||
os.path.join(axis_rtl_dir, "axis_adapter.v"),
|
||||
os.path.join(axis_rtl_dir, "axis_arb_mux.v"),
|
||||
os.path.join(axis_rtl_dir, "axis_async_fifo.v"),
|
||||
os.path.join(axis_rtl_dir, "axis_async_fifo_adapter.v"),
|
||||
os.path.join(axis_rtl_dir, "axis_fifo.v"),
|
||||
os.path.join(axis_rtl_dir, "axis_register.v"),
|
||||
os.path.join(pcie_rtl_dir, "pcie_us_axil_master.v"),
|
||||
os.path.join(pcie_rtl_dir, "dma_if_pcie_us.v"),
|
||||
os.path.join(pcie_rtl_dir, "dma_if_pcie_us_rd.v"),
|
||||
os.path.join(pcie_rtl_dir, "dma_if_pcie_us_wr.v"),
|
||||
os.path.join(pcie_rtl_dir, "dma_if_mux.v"),
|
||||
os.path.join(pcie_rtl_dir, "dma_if_mux_rd.v"),
|
||||
os.path.join(pcie_rtl_dir, "dma_if_mux_wr.v"),
|
||||
os.path.join(pcie_rtl_dir, "dma_psdpram.v"),
|
||||
os.path.join(pcie_rtl_dir, "dma_client_axis_sink.v"),
|
||||
os.path.join(pcie_rtl_dir, "dma_client_axis_source.v"),
|
||||
os.path.join(pcie_rtl_dir, "pcie_us_cfg.v"),
|
||||
os.path.join(pcie_rtl_dir, "pcie_us_msi.v"),
|
||||
os.path.join(pcie_rtl_dir, "pcie_tag_manager.v"),
|
||||
os.path.join(pcie_rtl_dir, "pulse_merge.v"),
|
||||
]
|
||||
|
||||
parameters = {}
|
||||
|
||||
parameters['AXIS_PCIE_DATA_WIDTH'] = 512
|
||||
parameters['AXIS_PCIE_KEEP_WIDTH'] = parameters['AXIS_PCIE_DATA_WIDTH'] // 32
|
||||
parameters['AXIS_PCIE_RQ_USER_WIDTH'] = 62 if parameters['AXIS_PCIE_DATA_WIDTH'] < 512 else 137
|
||||
parameters['AXIS_PCIE_RC_USER_WIDTH'] = 75 if parameters['AXIS_PCIE_DATA_WIDTH'] < 512 else 161
|
||||
parameters['AXIS_PCIE_CQ_USER_WIDTH'] = 88 if parameters['AXIS_PCIE_DATA_WIDTH'] < 512 else 183
|
||||
parameters['AXIS_PCIE_CC_USER_WIDTH'] = 33 if parameters['AXIS_PCIE_DATA_WIDTH'] < 512 else 81
|
||||
parameters['RQ_SEQ_NUM_WIDTH'] = 6
|
||||
parameters['BAR0_APERTURE'] = 24
|
||||
parameters['AXIS_ETH_DATA_WIDTH'] = 512
|
||||
parameters['AXIS_ETH_KEEP_WIDTH'] = parameters['AXIS_ETH_DATA_WIDTH'] // 8
|
||||
|
||||
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(
|
||||
python_search=[tests_dir],
|
||||
verilog_sources=verilog_sources,
|
||||
toplevel=toplevel,
|
||||
module=module,
|
||||
parameters=parameters,
|
||||
sim_build=sim_build,
|
||||
extra_env=extra_env,
|
||||
)
|
@ -1 +0,0 @@
|
||||
../lib/eth/tb/ip_ep.py
|
@ -1 +0,0 @@
|
||||
../../../../common/tb/mqnic.py
|
@ -1 +0,0 @@
|
||||
../lib/pcie/tb/pcie.py
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user