Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Axi test harness #1153

Merged
merged 68 commits into from
Jan 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
6b8e7f9
Initial, WIP commit of cocotb test harness
nathanielnrn Jul 22, 2022
1c5a565
Merge branch 'master' into axi-test-harness
nathanielnrn Jul 22, 2022
60e1df0
WIP Make parameterized
nathanielnrn Jul 29, 2022
fe1662e
axi-test.py improvements
nathanielnrn Aug 2, 2022
5d6b64d
WIP Possible working hard-coded cocotb test
nathanielnrn Aug 2, 2022
2cd1155
Merge branch 'master' into axi-test-harness
nathanielnrn Aug 2, 2022
aab1e25
Add AW and ARBURST[1:0] ports to make cocotb happy
nathanielnrn Aug 3, 2022
8c0558b
WIP hard coded axi-test changes
nathanielnrn Aug 3, 2022
fd2b887
Manual changes to make cocotb work
nathanielnrn Aug 4, 2022
f450e42
WIP, added dynamic decoding logic
nathanielnrn Aug 4, 2022
75fc4fe
Fix runtime errors in axi-test.py
nathanielnrn Aug 4, 2022
a97f040
Merge branch 'master' into axi-test-harness
nathanielnrn Aug 7, 2022
0a285cd
WIP of cocotb test bench
nathanielnrn Aug 11, 2022
02376a5
Merge branch 'master' into axi-test-harness
nathanielnrn Aug 11, 2022
f57ec81
Reorganized xilinx test directory
nathanielnrn Aug 13, 2022
b96c46d
Working generalized version of vadd testbench
nathanielnrn Aug 13, 2022
4229308
Change tb to ensure all memories match expected
nathanielnrn Aug 13, 2022
e41fd97
Add altered toplevel
nathanielnrn Aug 15, 2022
bcb921d
Cleanup, formatting corrections to axi-test.py
nathanielnrn Aug 15, 2022
b41117f
Merge branch 'master' into cleanup-runt-files
nathanielnrn Aug 16, 2022
b5b007d
More cleanup post merge
nathanielnrn Aug 16, 2022
1a03ba8
WIP integrating with CI
nathanielnrn Aug 16, 2022
db5c7e2
Merge branch 'cleanup-runt-files' into axi-test-harness
nathanielnrn Aug 16, 2022
21570e9
WIP, seeting up runt tests and organizing test dir
nathanielnrn Aug 16, 2022
0a029e9
Add test files
nathanielnrn Aug 19, 2022
1fc2b77
Working generalized axi-test
nathanielnrn Aug 19, 2022
17ae4e4
WIP Runt and MAKE compatability
nathanielnrn Aug 19, 2022
aa30519
Runt pipeline for cocotb tests nearly works
nathanielnrn Aug 22, 2022
a59fbe3
Merge branch 'master' into axi-test-harness
nathanielnrn Aug 22, 2022
fb204e4
Merge branch 'master' into axi-test-harness
nathanielnrn Aug 30, 2022
5004d00
Cleanup
nathanielnrn Aug 30, 2022
4f311d4
Made make silent for runt testing
nathanielnrn Aug 30, 2022
1e8b3d7
axi_test cleanup
nathanielnrn Aug 30, 2022
252bace
Merge branch 'master' into axi-test-harness
nathanielnrn Sep 11, 2022
5ba9cb8
Modified cocotb scripts to not need `.expected`s
nathanielnrn Sep 11, 2022
01ed775
Commiting cocotb vadd expect file
nathanielnrn Sep 11, 2022
6869a36
Formatting
nathanielnrn Sep 11, 2022
ff428e2
Removed extra comments
nathanielnrn Sep 11, 2022
0f7eb30
Fix multiple cocotb tests through runt
nathanielnrn Oct 2, 2022
696a53e
Merge branch 'master' into axi-test-harness
nathanielnrn Oct 2, 2022
8f8ac4c
Merge branch 'master' into axi-test-harness
nathanielnrn Oct 2, 2022
b4ff83f
Clean up generated files
nathanielnrn Oct 2, 2022
6ac94e1
Updated runt gold files for AXI generation
nathanielnrn Oct 5, 2022
696fa15
Merge branch 'master' into axi-test-harness
nathanielnrn Oct 5, 2022
c6ae735
Merge branch 'master' into axi-test-harness
nathanielnrn Oct 9, 2022
355c70f
Added cocotb dependency in Dockerfile
nathanielnrn Oct 9, 2022
9f2eb3a
Make flake happy
nathanielnrn Oct 9, 2022
d44b0a2
Revert "Added cocotb dependency in Dockerfile"
nathanielnrn Oct 9, 2022
45e0717
Merge branch 'master' into axi-test-harness
nathanielnrn Oct 12, 2022
eb01dc3
Merge branch 'master' into axi-test-harness
rachitnigam Oct 12, 2022
7fa7bcf
Merge branch 'master' into axi-test-harness
nathanielnrn Oct 13, 2022
7d97dcc
Merge branch 'axi-test-harness' of github.com:cucapra/calyx into axi-…
nathanielnrn Oct 13, 2022
ae74f95
Merge branch 'master' into axi-test-harness
nathanielnrn Oct 21, 2022
62275b3
Merge branch 'master' into axi-test-harness
nathanielnrn Oct 21, 2022
b995885
Merge branch 'master' into axi-test-harness
rachitnigam Oct 21, 2022
4fb0522
Dynamically generate verilog files from runt
nathanielnrn Oct 22, 2022
ed79f95
Merge remote-tracking branch 'origin' into axi-test-harness
nathanielnrn Oct 22, 2022
15dd3ef
Merge branch 'axi-test-harness' of github.com:cucapra/calyx into axi-…
nathanielnrn Oct 22, 2022
5b845fd
Add symlinks
nathanielnrn Oct 22, 2022
c30a256
Update runt expects
nathanielnrn Oct 22, 2022
4f18f46
Runt cocotb output fil fix
nathanielnrn Oct 22, 2022
1dc2bbd
Remove hard coded main.sv and toplevel.v files for cocotb testing
nathanielnrn Oct 22, 2022
4440a2b
Add mkdir to runt
nathanielnrn Oct 23, 2022
2f848b6
Merge master into axi-test-harness
github-actions[bot] Nov 15, 2022
af31dc1
Merge branch 'master' into axi-test-harness
rachitnigam Nov 15, 2022
ab843c1
Merge branch 'master' into axi-test-harness
rachitnigam Dec 21, 2022
26b3f92
update tests and runt command
rachitnigam Dec 21, 2022
e4e621b
disable verification and init in synthesis mode
rachitnigam Dec 21, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion fud/fud/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ def register_stages(registry):
registry.register(
futil.FutilStage(
"synth-verilog",
"-b verilog --synthesis -p external",
"-b verilog --synthesis -p external --disable-init --disable-verify",
"Compile Calyx to synthesizable Verilog",
)
)
Expand Down
28 changes: 25 additions & 3 deletions runt.toml
Original file line number Diff line number Diff line change
Expand Up @@ -279,10 +279,32 @@ fud e {} -s verilog.cycle_limit 500 \
[[tests]]
name = "AXI generation"
paths = [
"tests/xilinx/dot-product.futil",
"tests/xilinx/language-tutorial-iterate.futil",
"tests/xilinx/vectorized-add.futil"
"tests/xilinx/compile/dot-product.futil",
"tests/xilinx/compile/language-tutorial-iterate.futil",
"tests/xilinx/compile/vectorized-add.futil",
]
cmd = """
target/debug/futil {} -b xilinx
"""


[[tests]]
name = "Cocotb correctness tests"
paths = [
"tests/xilinx/cocotb/dot-product/",
"tests/xilinx/cocotb/vectorized-add/",
]
cmd = """
mkdir -p {}/hdl && \
dir_name=$(basename {}) && \
fud e -q {}/${dir_name}.futil --to synth-verilog -o {}/hdl/main.sv &&\
fud e -q {}/${dir_name}.futil --to axi-wrapper -o {}/hdl/toplevel.v

cd {}/../ && \
make --silent -B TEST_PATH={} COCOTB_LOG_LEVEL=CRITICAL |\
grep -E '^Output:' |\
sed 's/Output://g' &&\
make clean && \
rm -f results.xml

"""
27 changes: 27 additions & 0 deletions tests/xilinx/cocotb/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Makefile

# defaults
SIM ?= icarus
TOPLEVEL_LANG ?= verilog


#Needed to extract desired test from runt invocation
ifdef TEST_PATH
DIR_NAME := $(shell basename ${TEST_PATH})
endif

VERILOG_SOURCES += $(PWD)/$(DIR_NAME)/hdl/toplevel.v
VERILOG_SOURCES += $(PWD)/$(DIR_NAME)/hdl/main.sv

#Defines build directory, if left to default only a single computation is run
SIM_BUILD=sim_build/$(DIR_NAME)

# TOPLEVEL is the name of the toplevel module in your Verilog or VHDL file
TOPLEVEL = Toplevel

# MODULE is the basename of the Python test file
MODULE = run_axi_test


# include cocotb's make rules to take care of the simulator setup
include $(shell cocotb-config --makefiles)/Makefile.sim
155 changes: 155 additions & 0 deletions tests/xilinx/cocotb/axi_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
import json
import cocotb
from cocotb.clock import Clock
from cocotbext.axi import AxiBus, AxiRam
from cocotb.triggers import Timer, FallingEdge, with_timeout
from typing import Literal, Mapping, Any, Union
from pathlib import Path
import os


# NOTE (nathanielnrn) cocotb-bus 0.2.1 has a bug that does not recognize optional
# signals such as WSTRB when it is capitalized. Install directly from the cocotb-bus
# github repo to fix
class KernelTB:
def __init__(self, toplevel, data_path: Path):
self.toplevel = toplevel
self.data_path = data_path
assert os.path.isfile(
self.data_path
), "data_path must be a data path to a valid file"
# self.expect_path = expect_path
# assert os.path.isfile(
# self.expect_path
# ), "data_path must be a data path to a valid file"

async def setup_rams(self, data: Mapping[str, Any]):
# Create cocotb AxiRams
rams = {}
for i, mem in enumerate(data.keys()):
assert not isinstance(data[mem]["data"][0], list)
size = mem_size(mem, data)
width = data_width(mem, data)

# From_prefix assumes signals of form toplevel.<prefix>_<signal>
# i.e m0_axi_RDATA.
# These prefixes have to match verilog code. See kernel.xml <args>
# and ports assigned within that for guidance.
# In general, the index of `m<idx>_axi` just
# increments by 1 in fud axi generation
rams[mem] = AxiRam(
AxiBus.from_prefix(self.toplevel, f"m{i}_axi"),
self.toplevel.ap_clk,
# XXX (nathanielnrn): no easy way to invert ap_rst_n signal
# through cocotb
# self.toplevel.ap_rst_n,
size=size,
)

# NOTE: This defaults to little endian to match AxiRam defaults
data_in_bytes = encode(data[mem]["data"], width)
addr = 0x0000
for byte_data in data_in_bytes:
rams[mem].write(addr, byte_data)
addr += width

self.rams = rams

def get_rams(self):
return self.rams

async def reset(self):
await Timer(50, "ns")
self.toplevel.ap_rst_n.value = 0
await Timer(50, "ns")
self.toplevel.ap_rst_n.value = 1


async def run_kernel_test(toplevel, data_path: str):
# XXX (nathanielnrn): This only works if data passed in is less than 64 bytes
# (512 bits) because the AxiRam isn't correctly writing to our generated
# verilog. Speicfically, RDATA is a dump of all of the ram data, seemingly
# regardless of ARADDR. When too much dta is passed in they are simply dropped
tb = KernelTB(toplevel, Path(data_path))
await tb.reset()

data = None
with open(data_path) as f:
data = json.load(f)
f.close()
assert data is not None

# set up clock of 2ns period, simulator default timestep is 1ps
cocotb.start_soon(Clock(toplevel.ap_clk, 2, units="ns").start())
await tb.setup_rams(data)
await Timer(100, "ns")
await FallingEdge(toplevel.ap_clk)

toplevel.ap_start.value = 1

# Get data from ram
mems: list[str] = list(data.keys())
rams = tb.get_rams()

# Finish when ap_done is high or 100 us of simulation have passed.
timeout = 100
await with_timeout(FallingEdge(toplevel.ap_done), timeout, "us")

post = {}
for mem in mems:
addr = 0x000
size = mem_size(mem, data)
post_execution = rams[mem].read(addr, size)
width = data_width(mem, data)
post_execution = decode(post_execution, width)
post.update({mem: post_execution})
post = {"memories": post}

print("Output:" + json.dumps(post))


def mem_size(mem: str, data):
"""Returns size of memory within data in bytes"""
width = data_width(mem, data)
length = len(data[mem]["data"]) * width
return length


def data_width(mem: str, data):
"""Returns data width of mem in bytes"""
assert mem in data, "mem must be a key in data"
width = data[mem]["format"]["width"] // 8
if data[mem]["format"]["width"] % 8 != 0:
width += 1
return width


# AxiRam assumes little bytorder, hence the defaults
def decode(
b: bytes,
width: int,
byteorder: Union[Literal["little"], Literal["big"]] = "little",
signed=False,
):
"""Return the list of `ints` corresponding to value in `b` based on
encoding of `width` bytes
For example, `decode('b\x00\x00\x00\04', 4)` returns `[4]`
"""
assert len(b) % width == 0, "Mismatch between bytes length and width"
to_return = []
for i in range(len(b) // width):
start = i * width
end = start + width
to_return.append(
int.from_bytes(b[start:end], byteorder=byteorder, signed=signed)
)
return to_return


def encode(
lst: list[int],
width,
byteorder: Union[Literal["little"], Literal["big"]] = "little",
):
"""Return the `width`-wide byte representation of lst with byteorder"""
return [i.to_bytes(width, byteorder) for i in lst]
3 changes: 3 additions & 0 deletions tests/xilinx/cocotb/dot-product.expect
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{"memories": {"A": [27, 48, 88, 69, 9, 44, 3, 73], "B": [95, 68, 79, 39, 33, 88, 51, 99], "v": [27021]}}
---STDERR---
sys:1: ResourceWarning: unclosed file <_io.TextIOWrapper name=2 mode='w' encoding='UTF-8'>
1 change: 1 addition & 0 deletions tests/xilinx/cocotb/dot-product/dot-product.fuse.data
1 change: 1 addition & 0 deletions tests/xilinx/cocotb/dot-product/dot-product.futil
14 changes: 14 additions & 0 deletions tests/xilinx/cocotb/run_axi_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import cocotb
import os


@cocotb.test()
async def run(toplevel):
from axi_test import run_kernel_test

test_path = os.getcwd() + "/" + os.path.basename(os.environ["TEST_PATH"])
data_path = None
for file in os.listdir(test_path):
if file.endswith(".data"):
data_path = test_path + "/" + file
await run_kernel_test(toplevel, data_path)
3 changes: 3 additions & 0 deletions tests/xilinx/cocotb/vectorized-add.expect
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{"memories": {"A": [1, 3, 7, 15, 31, 63, 127, 255], "B": [1, 1, 1, 1, 1, 1, 1, 1], "Sum": [2, 4, 8, 16, 32, 64, 128, 256]}}
---STDERR---
sys:1: ResourceWarning: unclosed file <_io.TextIOWrapper name=2 mode='w' encoding='UTF-8'>
1 change: 1 addition & 0 deletions tests/xilinx/cocotb/vectorized-add/vectorized-add.futil
Loading