1
0
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:
Alex Forencich 2020-12-15 16:52:20 -08:00
parent 3003b3228d
commit b5ee772761
422 changed files with 24044 additions and 46121 deletions

39
fpga/common/tb/Makefile Normal file
View 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)

View File

@ -1 +0,0 @@
../lib/axi/tb/axi.py

View File

@ -1 +0,0 @@
../lib/axi/tb/axil.py

View File

@ -1 +0,0 @@
../lib/axis/tb/axis_ep.py

View 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

View 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,
)

View File

@ -1 +0,0 @@
../lib/eth/tb/eth_ep.py

View File

@ -1 +0,0 @@
../lib/eth/tb/ip_ep.py

View File

@ -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)

View File

@ -1 +0,0 @@
../lib/pcie/tb/pcie.py

View File

@ -1 +0,0 @@
../lib/pcie/tb/pcie_us.py

View File

@ -1 +0,0 @@
../lib/pcie/tb/pcie_usp.py

View File

@ -1 +0,0 @@
../lib/eth/tb/ptp.py

View 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

View 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,
)

View 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

View 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,
)

View 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

View 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,
)

View 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

View 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,
)

View 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

View 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,
)

View 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

View 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,
)

View File

@ -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()

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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()

View File

@ -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

View 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

View 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,
)

View File

@ -1 +0,0 @@
../lib/eth/tb/udp_ep.py

View File

@ -1 +0,0 @@
../lib/eth/tb/xgmii_ep.py

View File

@ -1 +0,0 @@
../lib/eth/tb/axis_ep.py

View File

@ -1 +0,0 @@
../lib/eth/tb/eth_ep.py

View 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

View File

@ -0,0 +1 @@
../../../../../common/tb/mqnic.py

View 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,
)

View File

@ -1 +0,0 @@
../lib/eth/tb/ip_ep.py

View File

@ -1 +0,0 @@
../../../../common/tb/mqnic.py

View File

@ -1 +0,0 @@
../lib/pcie/tb/pcie.py

View File

@ -1 +0,0 @@
../lib/pcie/tb/pcie_us.py

View File

@ -1 +0,0 @@
../lib/pcie/tb/pcie_usp.py

View File

@ -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()

View File

@ -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

View File

@ -1 +0,0 @@
../lib/eth/tb/udp_ep.py

View File

@ -1 +0,0 @@
../lib/eth/tb/axis_ep.py

View File

@ -1 +0,0 @@
../lib/eth/tb/eth_ep.py

View 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

View File

@ -0,0 +1 @@
../../../../../common/tb/mqnic.py

View 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,
)

View File

@ -1 +0,0 @@
../lib/eth/tb/ip_ep.py

View File

@ -1 +0,0 @@
../../../../common/tb/mqnic.py

View File

@ -1 +0,0 @@
../lib/pcie/tb/pcie.py

View File

@ -1 +0,0 @@
../lib/pcie/tb/pcie_us.py

View File

@ -1 +0,0 @@
../lib/pcie/tb/pcie_usp.py

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -1 +0,0 @@
../lib/eth/tb/udp_ep.py

View File

@ -1 +0,0 @@
../lib/eth/tb/xgmii_ep.py

View File

@ -1 +0,0 @@
../lib/eth/tb/axis_ep.py

View File

@ -1 +0,0 @@
../lib/eth/tb/eth_ep.py

View 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

View File

@ -0,0 +1 @@
../../../../../common/tb/mqnic.py

View 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,
)

View File

@ -1 +0,0 @@
../lib/eth/tb/ip_ep.py

View File

@ -1 +0,0 @@
../../../../common/tb/mqnic.py

View File

@ -1 +0,0 @@
../lib/pcie/tb/pcie.py

View File

@ -1 +0,0 @@
../lib/pcie/tb/pcie_us.py

View File

@ -1 +0,0 @@
../lib/pcie/tb/pcie_usp.py

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -1 +0,0 @@
../lib/eth/tb/udp_ep.py

View File

@ -1 +0,0 @@
../lib/eth/tb/xgmii_ep.py

View File

@ -1 +0,0 @@
../lib/eth/tb/axis_ep.py

View File

@ -1 +0,0 @@
../lib/eth/tb/eth_ep.py

View 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

View File

@ -0,0 +1 @@
../../../../../common/tb/mqnic.py

View 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,
)

View File

@ -1 +0,0 @@
../lib/eth/tb/ip_ep.py

View File

@ -1 +0,0 @@
../../../../common/tb/mqnic.py

View File

@ -1 +0,0 @@
../lib/pcie/tb/pcie.py

Some files were not shown because too many files have changed in this diff Show More