This commit is contained in:
2025-05-11 23:43:59 +02:00
parent 9c20fe7e7c
commit 079d1ab0d5
21 changed files with 3372 additions and 0 deletions

View File

@@ -0,0 +1,130 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
.pytest_cache/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
.python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# celery beat schedule file
celerybeat-schedule
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# Cocotb build folder
build/
# Cocotb results
results.xml

View File

@@ -0,0 +1,20 @@
export PYTHON_BIN=python3
PWD := $(shell pwd)
SIM ?= ghdl
SIM_ARGS ?= --wave=$(PWD)/build/waveform.ghw -gc_clkfreq=100000000 -gc_sclkfreq=10000000
GHDL_ARGS ?= -fsynopsys
TOPLEVEL_LANG = vhdl
SIM_BUILD = $(PWD)/build
MODULE = tester_axis_lw_spi_master
TOPLEVEL = axis_lw_spi_master
HDL_DIR = $(PWD)/../hdl
VHDL_SOURCES = \
$(HDL_DIR)/spi_master_lightweight/rtl/lw_spi_master.vhd \
$(HDL_DIR)/axis_lw_spi_master.vhd
include $(shell cocotb-config --makefiles)/Makefile.sim

View File

@@ -0,0 +1,82 @@
#!/usr/bin/env python3
import secrets
import cocotb
from cocotb.clock import Clock
from cocotb.triggers import RisingEdge, ClockCycles
from cocotbext.axi4stream.drivers import Axi4StreamMaster
from cocotbext.axi4stream.monitors import Axi4Stream
from cocotbext.spi import SpiSlaveBase, SpiSignals, SpiConfig
CLK_PERIOD = 10
class SimpleSpiSlave(SpiSlaveBase):
def __init__(self, signals, config, data):
self._config = config
self.content = 0
self.data = data
super().__init__(signals)
async def get_content(self):
await self.idle.wait()
return self.content
async def _transaction(self, frame_start, frame_end):
await frame_start
self.idle.clear()
self._miso.value = 1 if self.data[0] & 0x80 else 0
self.content = int(await self._shift(len(self.data) * 8 - 1, tx_word=int.from_bytes(self.data, 'big')))
await RisingEdge(self._sclk)
self.content = self.content << 1 | int(self._mosi.value.integer)
await frame_end
async def setup_dut(dut):
cocotb.fork(Clock(dut.aclk, CLK_PERIOD, "ns").start())
@cocotb.test()
async def test_spi(dut, length=32):
"""TODO"""
spi_signals = SpiSignals(
sclk = dut.sclk,
mosi = dut.mosi,
miso = dut.miso,
cs = dut.cs
)
spi_config = SpiConfig(
word_width = 8,
cpol = False,
cpha = False,
data_output_idle = 0,
msb_first = True
)
mosi_tx = secrets.randbits(length * 8).to_bytes(length, 'little')
miso_tx = secrets.randbits(length * 8).to_bytes(length, 'little')
spi_slave = SimpleSpiSlave(spi_signals, spi_config, miso_tx)
miso_rx = bytearray()
axis_m = Axi4StreamMaster(dut, "s_axis", dut.aclk)
axis_monitor = Axi4Stream(dut, "m_axis", dut.aclk, packets=False)
axis_monitor.add_callback(lambda data: miso_rx.extend(data))
await setup_dut(dut)
await ClockCycles(dut.aclk, 10)
await axis_m.write([b for b in mosi_tx])
mosi_rx = (await spi_slave.get_content()).to_bytes(length, 'big')
await ClockCycles(dut.aclk, 10)
assert mosi_tx == mosi_rx, "Received MOSI data does not match transmitted one"
assert miso_tx == miso_rx, "Received MISO data does not match transmitted one"

View File

@@ -0,0 +1,53 @@
[*]
[*] GTKWave Analyzer v3.3.104 (w)1999-2020 BSI
[*] Fri Mar 25 16:24:27 2022
[*]
[dumpfile] "/home/nicola/Documents/Vivado/IPs/ip_repo/axi4-stream-spi-master/sim/build/waveform.ghw"
[dumpfile_mtime] "Fri Mar 25 16:23:35 2022"
[dumpfile_size] 3066
[savefile] "/home/nicola/Documents/Vivado/IPs/ip_repo/axi4-stream-spi-master/sim/waveforms.gtkw"
[timestart] 0
[size] 1920 1001
[pos] -27 -24
*-27.176317 7190000000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
[treeopen] top.
[treeopen] top.axis_lw_spi_master.
[treeopen] top.axis_lw_spi_master.inst_lw_spi_master.
[sst_width] 281
[signals_width] 200
[sst_expanded] 1
[sst_vpaned_height] 285
@28
top.axis_lw_spi_master.clk
@200
-
@28
top.axis_lw_spi_master.s_axis_tvalid
top.axis_lw_spi_master.s_axis_tready
@22
#{top.axis_lw_spi_master.s_axis_tdata[7:0]} top.axis_lw_spi_master.s_axis_tdata[7] top.axis_lw_spi_master.s_axis_tdata[6] top.axis_lw_spi_master.s_axis_tdata[5] top.axis_lw_spi_master.s_axis_tdata[4] top.axis_lw_spi_master.s_axis_tdata[3] top.axis_lw_spi_master.s_axis_tdata[2] top.axis_lw_spi_master.s_axis_tdata[1] top.axis_lw_spi_master.s_axis_tdata[0]
@200
-
@28
top.axis_lw_spi_master.m_axis_tvalid
@22
#{top.axis_lw_spi_master.m_axis_tdata[7:0]} top.axis_lw_spi_master.m_axis_tdata[7] top.axis_lw_spi_master.m_axis_tdata[6] top.axis_lw_spi_master.m_axis_tdata[5] top.axis_lw_spi_master.m_axis_tdata[4] top.axis_lw_spi_master.m_axis_tdata[3] top.axis_lw_spi_master.m_axis_tdata[2] top.axis_lw_spi_master.m_axis_tdata[1] top.axis_lw_spi_master.m_axis_tdata[0]
@200
-
@28
top.axis_lw_spi_master.inst_lw_spi_master.en_i
@22
#{top.axis_lw_spi_master.inst_lw_spi_master.mosi_data_i[7:0]} top.axis_lw_spi_master.inst_lw_spi_master.mosi_data_i[7] top.axis_lw_spi_master.inst_lw_spi_master.mosi_data_i[6] top.axis_lw_spi_master.inst_lw_spi_master.mosi_data_i[5] top.axis_lw_spi_master.inst_lw_spi_master.mosi_data_i[4] top.axis_lw_spi_master.inst_lw_spi_master.mosi_data_i[3] top.axis_lw_spi_master.inst_lw_spi_master.mosi_data_i[2] top.axis_lw_spi_master.inst_lw_spi_master.mosi_data_i[1] top.axis_lw_spi_master.inst_lw_spi_master.mosi_data_i[0]
#{top.axis_lw_spi_master.inst_lw_spi_master.miso_data_o[7:0]} top.axis_lw_spi_master.inst_lw_spi_master.miso_data_o[7] top.axis_lw_spi_master.inst_lw_spi_master.miso_data_o[6] top.axis_lw_spi_master.inst_lw_spi_master.miso_data_o[5] top.axis_lw_spi_master.inst_lw_spi_master.miso_data_o[4] top.axis_lw_spi_master.inst_lw_spi_master.miso_data_o[3] top.axis_lw_spi_master.inst_lw_spi_master.miso_data_o[2] top.axis_lw_spi_master.inst_lw_spi_master.miso_data_o[1] top.axis_lw_spi_master.inst_lw_spi_master.miso_data_o[0]
@28
top.axis_lw_spi_master.inst_lw_spi_master.data_ready_o
@200
-
@28
top.axis_lw_spi_master.sclk
top.axis_lw_spi_master.mosi
top.axis_lw_spi_master.miso
@29
top.axis_lw_spi_master.cs
[pattern_trace] 1
[pattern_trace] 0