diff --git a/README.md b/README.md index a4333c6..fad5d0b 100644 --- a/README.md +++ b/README.md @@ -277,7 +277,9 @@ Attributes: * `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. * `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: diff --git a/cocotbext/axi/axis.py b/cocotbext/axi/axis.py index 2d87423..c10394e 100644 --- a/cocotbext/axi/axis.py +++ b/cocotbext/axi/axis.py @@ -35,13 +35,15 @@ from .reset import Reset 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.tkeep = None self.tid = None self.tdest = 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.tdata) is bytearray: @@ -65,19 +67,23 @@ class AxiStreamFrame: self.tuser = tdata.tuser else: 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): self.tdata = bytearray(tdata) self.tkeep = tkeep self.tid = tid self.tdest = tdest self.tuser = tuser + self.tx_complete = tx_complete else: self.tdata = list(tdata) self.tkeep = tkeep self.tid = tid self.tdest = tdest self.tuser = tuser + self.tx_complete = tx_complete def normalize(self): # 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): 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): if not isinstance(other, AxiStreamFrame): return False @@ -204,7 +216,8 @@ class AxiStreamFrame: f"tid={self.tid!r}, " f"tdest={self.tdest!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): @@ -397,6 +410,7 @@ class AxiStreamSource(Reset): frame = self.queue.popleft() self.queue_occupancy_bytes -= len(frame) self.queue_occupancy_frames -= 1 + frame.sim_time_start = get_sim_time() self.log.info("TX frame: %s", frame) frame.normalize() self.active = True @@ -418,6 +432,8 @@ class AxiStreamSource(Reset): if len(frame.tdata) == 0: tlast_val = 1 + frame.sim_time_end = get_sim_time() + frame.handle_tx_complete() frame = None break @@ -640,7 +656,7 @@ class AxiStreamSink(Reset): frame = AxiStreamFrame(bytearray(), [], [], [], []) else: frame = AxiStreamFrame([], [], [], [], []) - frame.rx_sim_time = get_sim_time() + frame.sim_time_start = get_sim_time() for offset in range(self.byte_lanes): @@ -655,6 +671,7 @@ class AxiStreamSink(Reset): frame.tuser.append(self.bus.tuser.value.integer) 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.queue_occupancy_bytes += len(frame) @@ -835,7 +852,7 @@ class AxiStreamMonitor(Reset): frame = AxiStreamFrame(bytearray(), [], [], [], []) else: frame = AxiStreamFrame([], [], [], [], []) - frame.rx_sim_time = get_sim_time() + frame.sim_time_start = get_sim_time() for offset in range(self.byte_lanes): @@ -850,6 +867,7 @@ class AxiStreamMonitor(Reset): frame.tuser.append(self.bus.tuser.value.integer) 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.queue.append(frame) diff --git a/tests/axis/test_axis.py b/tests/axis/test_axis.py index 09bb471..8392254 100644 --- a/tests/axis/test_axis.py +++ b/tests/axis/test_axis.py @@ -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 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.monitor.empty()