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

Optional interleaving / deinterleaving in Axis #62

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,11 @@ To receive data with an `AxiStreamSink` or `AxiStreamMonitor`, call `recv()`/`re

data = await axis_sink.recv()

To de-interleave receive data, for example the `deinterleave` parameter can be set on the `AxiStreamSink` constructor. This causes calls to `read()` and `recv()` to return data sorted by `tid` ot `tdest`, returned in order of transaction completion time.
ollie-etl marked this conversation as resolved.
Show resolved Hide resolved

axis_sink = AxiStreamSink(AxiStreamBus.from_prefix(dut, "m_axis"), dut.clk, dut.rst, deinterleave="tid")
data = await axis_sink.recv()

#### Signals

* `tdata`: data, required
Expand Down
27 changes: 24 additions & 3 deletions cocotbext/axi/axis.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
from .version import __version__
from .reset import Reset

from functools import reduce


class AxiStreamFrame:
def __init__(self, tdata=b'', tkeep=None, tid=None, tdest=None, tuser=None, tx_complete=None):
Expand Down Expand Up @@ -736,8 +738,9 @@ class AxiStreamSink(AxiStreamMonitor, AxiStreamPause):
_ready_init = 0

def __init__(self, bus, clock, reset=None, reset_active_level=True,
byte_size=None, byte_lanes=None, *args, **kwargs):
byte_size=None, byte_lanes=None, deinterleave=None, *args, **kwargs):

self.deinterleave = deinterleave
self.queue_occupancy_limit_bytes = -1
self.queue_occupancy_limit_frames = -1

Expand Down Expand Up @@ -765,7 +768,14 @@ def _dequeue(self, frame):
self.wake_event.set()

async def _run(self):
frame = None
if self.deinterleave is None:
num_frames = 1
if self.deinterleave is "tid":
num_frames = len(self.bus.tid)
if self.deinterleave is "tdest":
num_frames = len(self.bus.tdest)
ollie-etl marked this conversation as resolved.
Show resolved Hide resolved

frames = [None for _ in range(num_frames)]
self.active = False

has_tready = hasattr(self.bus, "tready")
Expand All @@ -790,6 +800,15 @@ async def _run(self):
tvalid_sample = (not has_tvalid) or self.bus.tvalid.value

if tready_sample and tvalid_sample:
if self.deinterleave is None:
qid = 0
if self.deinterleave is "tid":
qid = self.bus.tid.value
if self.deinterleave is "tdest":
qid = self.bus.tdest.value

frame = frames[qid]

if not frame:
if self.byte_size == 8:
frame = AxiStreamFrame(bytearray(), [], [], [], [])
Expand Down Expand Up @@ -820,8 +839,10 @@ async def _run(self):
self.active_event.set()

frame = None

frames[qid] = frame
else:
self.active = bool(frame)
self.active = reduce(lambda r, f: r or bool(f), frames, False)

if has_tready:
self.bus.tready.value = (not self.full() and not pause_sample)
Expand Down