Improve AXI stream transfer tracking
This commit is contained in:
@@ -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:
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
Reference in New Issue
Block a user