Improve AXI stream transfer tracking

This commit is contained in:
Alex Forencich
2021-01-03 22:47:38 -08:00
parent 2e79ef233f
commit 7c18f9b73f
3 changed files with 29 additions and 8 deletions

View File

@@ -277,7 +277,9 @@ Attributes:
* `tid`: tid field, optional; int or list with one entry per `tdata`, last value used per cycle when sending. * `tid`: tid field, optional; int or list with one entry per `tdata`, last value used per cycle when sending.
* `tdest`: tdest field, optional; int or list with one entry per `tdata`, last value used per cycle when sending. * `tdest`: tdest field, optional; int or list with one entry per `tdata`, last value used per cycle when sending.
* `tuser`: tuser field, optional; int or list with one entry per `tdata`, last value used per cycle when sending. * `tuser`: tuser field, optional; int or list with one entry per `tdata`, last value used per cycle when sending.
* `rx_sim_time`: simulation time when frame arrived at sink or monitor. * `sim_time_start`: simulation time of first transfer cycle of frame.
* `sim_time_end`: simulation time of last transfer cycle of frame.
* `tx_complete`: event or callable triggered when frame is transmitted.
Methods: Methods:

View File

@@ -35,13 +35,15 @@ from .reset import Reset
class AxiStreamFrame: class AxiStreamFrame:
def __init__(self, tdata=b'', tkeep=None, tid=None, tdest=None, tuser=None): def __init__(self, tdata=b'', tkeep=None, tid=None, tdest=None, tuser=None, tx_complete=None):
self.tdata = bytearray() self.tdata = bytearray()
self.tkeep = None self.tkeep = None
self.tid = None self.tid = None
self.tdest = None self.tdest = None
self.tuser = None self.tuser = None
self.rx_sim_time = None self.sim_time_start = None
self.sim_time_end = None
self.tx_complete = None
if type(tdata) is AxiStreamFrame: if type(tdata) is AxiStreamFrame:
if type(tdata.tdata) is bytearray: if type(tdata.tdata) is bytearray:
@@ -65,19 +67,23 @@ class AxiStreamFrame:
self.tuser = tdata.tuser self.tuser = tdata.tuser
else: else:
self.tuser = list(tdata.tuser) self.tuser = list(tdata.tuser)
self.rx_sim_time = tdata.rx_sim_time self.sim_time_start = tdata.sim_time_start
self.sim_time_end = tdata.sim_time_end
self.tx_complete = tdata.tx_complete
elif type(tdata) in (bytes, bytearray): elif type(tdata) in (bytes, bytearray):
self.tdata = bytearray(tdata) self.tdata = bytearray(tdata)
self.tkeep = tkeep self.tkeep = tkeep
self.tid = tid self.tid = tid
self.tdest = tdest self.tdest = tdest
self.tuser = tuser self.tuser = tuser
self.tx_complete = tx_complete
else: else:
self.tdata = list(tdata) self.tdata = list(tdata)
self.tkeep = tkeep self.tkeep = tkeep
self.tid = tid self.tid = tid
self.tdest = tdest self.tdest = tdest
self.tuser = tuser self.tuser = tuser
self.tx_complete = tx_complete
def normalize(self): def normalize(self):
# normalize all sideband signals to the same size as tdata # normalize all sideband signals to the same size as tdata
@@ -148,6 +154,12 @@ class AxiStreamFrame:
elif all(self.tuser[0] == i for i in self.tuser): elif all(self.tuser[0] == i for i in self.tuser):
self.tuser = self.tuser[0] self.tuser = self.tuser[0]
def handle_tx_complete(self):
if isinstance(self.tx_complete, Event):
self.tx_complete.set(self)
elif callable(self.tx_complete):
self.tx_complete(self)
def __eq__(self, other): def __eq__(self, other):
if not isinstance(other, AxiStreamFrame): if not isinstance(other, AxiStreamFrame):
return False return False
@@ -204,7 +216,8 @@ class AxiStreamFrame:
f"tid={self.tid!r}, " f"tid={self.tid!r}, "
f"tdest={self.tdest!r}, " f"tdest={self.tdest!r}, "
f"tuser={self.tuser!r}, " f"tuser={self.tuser!r}, "
f"rx_sim_time={self.rx_sim_time!r})" f"sim_time_start={self.sim_time_start!r}, "
f"sim_time_end={self.sim_time_end!r})"
) )
def __len__(self): def __len__(self):
@@ -397,6 +410,7 @@ class AxiStreamSource(Reset):
frame = self.queue.popleft() frame = self.queue.popleft()
self.queue_occupancy_bytes -= len(frame) self.queue_occupancy_bytes -= len(frame)
self.queue_occupancy_frames -= 1 self.queue_occupancy_frames -= 1
frame.sim_time_start = get_sim_time()
self.log.info("TX frame: %s", frame) self.log.info("TX frame: %s", frame)
frame.normalize() frame.normalize()
self.active = True self.active = True
@@ -418,6 +432,8 @@ class AxiStreamSource(Reset):
if len(frame.tdata) == 0: if len(frame.tdata) == 0:
tlast_val = 1 tlast_val = 1
frame.sim_time_end = get_sim_time()
frame.handle_tx_complete()
frame = None frame = None
break break
@@ -640,7 +656,7 @@ class AxiStreamSink(Reset):
frame = AxiStreamFrame(bytearray(), [], [], [], []) frame = AxiStreamFrame(bytearray(), [], [], [], [])
else: else:
frame = AxiStreamFrame([], [], [], [], []) frame = AxiStreamFrame([], [], [], [], [])
frame.rx_sim_time = get_sim_time() frame.sim_time_start = get_sim_time()
for offset in range(self.byte_lanes): for offset in range(self.byte_lanes):
@@ -655,6 +671,7 @@ class AxiStreamSink(Reset):
frame.tuser.append(self.bus.tuser.value.integer) frame.tuser.append(self.bus.tuser.value.integer)
if not hasattr(self.bus, "tlast") or self.bus.tlast.value: if not hasattr(self.bus, "tlast") or self.bus.tlast.value:
frame.sim_time_end = get_sim_time()
self.log.info("RX frame: %s", frame) self.log.info("RX frame: %s", frame)
self.queue_occupancy_bytes += len(frame) self.queue_occupancy_bytes += len(frame)
@@ -835,7 +852,7 @@ class AxiStreamMonitor(Reset):
frame = AxiStreamFrame(bytearray(), [], [], [], []) frame = AxiStreamFrame(bytearray(), [], [], [], [])
else: else:
frame = AxiStreamFrame([], [], [], [], []) frame = AxiStreamFrame([], [], [], [], [])
frame.rx_sim_time = get_sim_time() frame.sim_time_start = get_sim_time()
for offset in range(self.byte_lanes): for offset in range(self.byte_lanes):
@@ -850,6 +867,7 @@ class AxiStreamMonitor(Reset):
frame.tuser.append(self.bus.tuser.value.integer) frame.tuser.append(self.bus.tuser.value.integer)
if not hasattr(self.bus, "tlast") or self.bus.tlast.value: if not hasattr(self.bus, "tlast") or self.bus.tlast.value:
frame.sim_time_end = get_sim_time()
self.log.info("RX frame: %s", frame) self.log.info("RX frame: %s", frame)
self.queue.append(frame) self.queue.append(frame)

View File

@@ -111,7 +111,8 @@ async def run_test(dut, payload_lengths=None, payload_data=None, idle_inserter=N
assert mon_rx_frame.tdest == test_frame.tdest assert mon_rx_frame.tdest == test_frame.tdest
assert not mon_rx_frame.tuser assert not mon_rx_frame.tuser
assert rx_frame.rx_sim_time == mon_rx_frame.rx_sim_time assert rx_frame.sim_time_start == mon_rx_frame.sim_time_start
assert rx_frame.sim_time_end == mon_rx_frame.sim_time_end
assert tb.sink.empty() assert tb.sink.empty()
assert tb.monitor.empty() assert tb.monitor.empty()