From 37b23c358b1c5209173c49fa970a1b230b879147 Mon Sep 17 00:00:00 2001 From: Alex Forencich Date: Tue, 24 Jan 2023 17:42:05 -0800 Subject: [PATCH] Put sources and sinks to sleep when idle Signed-off-by: Alex Forencich --- cocotbext/eth/gmii.py | 16 +++++++++++++++- cocotbext/eth/mii.py | 16 +++++++++++++++- cocotbext/eth/rgmii.py | 21 ++++++++++++++++++++- cocotbext/eth/xgmii.py | 27 +++++++++++++++++++++++---- 4 files changed, 73 insertions(+), 7 deletions(-) diff --git a/cocotbext/eth/gmii.py b/cocotbext/eth/gmii.py index 4a32276..03f3a60 100644 --- a/cocotbext/eth/gmii.py +++ b/cocotbext/eth/gmii.py @@ -157,6 +157,7 @@ class GmiiSource(Reset): self.current_frame = None self.idle_event = Event() self.idle_event.set() + self.active_event = Event() self.ifg = 12 self.mii_mode = False @@ -189,6 +190,7 @@ class GmiiSource(Reset): frame = GmiiFrame(frame) await self.queue.put(frame) self.idle_event.clear() + self.active_event.set() self.queue_occupancy_bytes += len(frame) self.queue_occupancy_frames += 1 @@ -198,6 +200,7 @@ class GmiiSource(Reset): frame = GmiiFrame(frame) self.queue.put_nowait(frame) self.idle_event.clear() + self.active_event.set() self.queue_occupancy_bytes += len(frame) self.queue_occupancy_frames += 1 @@ -225,6 +228,7 @@ class GmiiSource(Reset): frame.handle_tx_complete() self.dequeue_event.set() self.idle_event.set() + self.active_event.clear() self.queue_occupancy_bytes = 0 self.queue_occupancy_frames = 0 @@ -251,6 +255,7 @@ class GmiiSource(Reset): if self.queue.empty(): self.idle_event.set() + self.active_event.clear() else: self.log.info("Reset de-asserted") if self._run_cr is None: @@ -332,7 +337,11 @@ class GmiiSource(Reset): self.er.value = 0 self.dv.value = 0 self.active = False - self.idle_event.set() + + if ifg_cnt == 0 and self.queue.empty(): + self.idle_event.set() + self.active_event.clear() + await self.active_event.wait() elif self.enable is not None and not self.enable.value: await enable_event @@ -439,6 +448,8 @@ class GmiiSink(Reset): clock_edge_event = RisingEdge(self.clock) + active_event = RisingEdge(self.dv) + enable_event = None if self.enable is not None: enable_event = RisingEdge(self.enable) @@ -503,6 +514,9 @@ class GmiiSink(Reset): frame.data.append(d_val) frame.error.append(er_val) + if not dv_val: + await active_event + elif self.enable is not None and not self.enable.value: await enable_event diff --git a/cocotbext/eth/mii.py b/cocotbext/eth/mii.py index 0bb0e71..198e46b 100644 --- a/cocotbext/eth/mii.py +++ b/cocotbext/eth/mii.py @@ -59,6 +59,7 @@ class MiiSource(Reset): self.current_frame = None self.idle_event = Event() self.idle_event.set() + self.active_event = Event() self.ifg = 12 @@ -90,6 +91,7 @@ class MiiSource(Reset): frame = GmiiFrame(frame) await self.queue.put(frame) self.idle_event.clear() + self.active_event.set() self.queue_occupancy_bytes += len(frame) self.queue_occupancy_frames += 1 @@ -99,6 +101,7 @@ class MiiSource(Reset): frame = GmiiFrame(frame) self.queue.put_nowait(frame) self.idle_event.clear() + self.active_event.set() self.queue_occupancy_bytes += len(frame) self.queue_occupancy_frames += 1 @@ -126,6 +129,7 @@ class MiiSource(Reset): frame.handle_tx_complete() self.dequeue_event.set() self.idle_event.set() + self.active_event.clear() self.queue_occupancy_bytes = 0 self.queue_occupancy_frames = 0 @@ -152,6 +156,7 @@ class MiiSource(Reset): if self.queue.empty(): self.idle_event.set() + self.active_event.clear() else: self.log.info("Reset de-asserted") if self._run_cr is None: @@ -226,7 +231,11 @@ class MiiSource(Reset): self.er.value = 0 self.dv.value = 0 self.active = False - self.idle_event.set() + + if ifg_cnt == 0 and self.queue.empty(): + self.idle_event.set() + self.active_event.clear() + await self.active_event.wait() elif self.enable is not None and not self.enable.value: await enable_event @@ -330,6 +339,8 @@ class MiiSink(Reset): clock_edge_event = RisingEdge(self.clock) + active_event = RisingEdge(self.dv) + enable_event = None if self.enable is not None: enable_event = RisingEdge(self.enable) @@ -389,6 +400,9 @@ class MiiSink(Reset): frame.data.append(d_val) frame.error.append(er_val) + if not dv_val: + await active_event + elif self.enable is not None and not self.enable.value: await enable_event diff --git a/cocotbext/eth/rgmii.py b/cocotbext/eth/rgmii.py index 31a47a4..6786a0d 100644 --- a/cocotbext/eth/rgmii.py +++ b/cocotbext/eth/rgmii.py @@ -61,6 +61,7 @@ class RgmiiSource(Reset): self.current_frame = None self.idle_event = Event() self.idle_event.set() + self.active_event = Event() self.ifg = 12 self.mii_mode = False @@ -90,6 +91,7 @@ class RgmiiSource(Reset): frame = GmiiFrame(frame) await self.queue.put(frame) self.idle_event.clear() + self.active_event.set() self.queue_occupancy_bytes += len(frame) self.queue_occupancy_frames += 1 @@ -99,6 +101,7 @@ class RgmiiSource(Reset): frame = GmiiFrame(frame) self.queue.put_nowait(frame) self.idle_event.clear() + self.active_event.set() self.queue_occupancy_bytes += len(frame) self.queue_occupancy_frames += 1 @@ -126,6 +129,7 @@ class RgmiiSource(Reset): frame.handle_tx_complete() self.dequeue_event.set() self.idle_event.set() + self.active_event.clear() self.queue_occupancy_bytes = 0 self.queue_occupancy_frames = 0 @@ -150,6 +154,7 @@ class RgmiiSource(Reset): if self.queue.empty(): self.idle_event.set() + self.active_event.clear() else: self.log.info("Reset de-asserted") if self._run_cr is None: @@ -161,6 +166,7 @@ class RgmiiSource(Reset): frame_data = None frame_error = None ifg_cnt = 0 + in_ifg = False self.active = False d = 0 er = 0 @@ -187,9 +193,12 @@ class RgmiiSource(Reset): self.ctrl.value = en ^ er if self.enable is None or self.enable.value: + in_ifg = False + if ifg_cnt > 0: # in IFG ifg_cnt -= 1 + in_ifg = True elif frame is None and not self.queue.empty(): # send frame @@ -234,6 +243,7 @@ class RgmiiSource(Reset): if frame_offset >= len(frame_data): ifg_cnt = max(self.ifg, 1) + in_ifg = True frame.sim_time_end = get_sim_time() frame.handle_tx_complete() frame = None @@ -243,7 +253,11 @@ class RgmiiSource(Reset): er = 0 en = 0 self.active = False - self.idle_event.set() + + if not in_ifg and self.queue.empty(): + self.idle_event.set() + self.active_event.clear() + await self.active_event.wait() elif self.enable is not None and not self.enable.value: await enable_event @@ -352,6 +366,8 @@ class RgmiiSink(Reset): clock_rising_edge_event = RisingEdge(self.clock) clock_falling_edge_event = FallingEdge(self.clock) + active_event = RisingEdge(self.ctrl) + enable_event = None if self.enable is not None: enable_event = RisingEdge(self.enable) @@ -423,6 +439,9 @@ class RgmiiSink(Reset): frame.data.append(d_val) frame.error.append(er_val) + if not dv_val: + await active_event + elif self.enable is not None and not self.enable.value: await enable_event diff --git a/cocotbext/eth/xgmii.py b/cocotbext/eth/xgmii.py index be4920c..b1b7733 100644 --- a/cocotbext/eth/xgmii.py +++ b/cocotbext/eth/xgmii.py @@ -28,7 +28,7 @@ import zlib import cocotb from cocotb.queue import Queue, QueueFull -from cocotb.triggers import RisingEdge, Timer, First, Event +from cocotb.triggers import Edge, RisingEdge, Timer, First, Event from cocotb.utils import get_sim_time from .version import __version__ @@ -158,6 +158,7 @@ class XgmiiSource(Reset): self.current_frame = None self.idle_event = Event() self.idle_event.set() + self.active_event = Event() self.enable_dic = True self.ifg = 12 @@ -200,6 +201,7 @@ class XgmiiSource(Reset): frame = XgmiiFrame(frame) await self.queue.put(frame) self.idle_event.clear() + self.active_event.set() self.queue_occupancy_bytes += len(frame) self.queue_occupancy_frames += 1 @@ -209,6 +211,7 @@ class XgmiiSource(Reset): frame = XgmiiFrame(frame) self.queue.put_nowait(frame) self.idle_event.clear() + self.active_event.set() self.queue_occupancy_bytes += len(frame) self.queue_occupancy_frames += 1 @@ -236,6 +239,7 @@ class XgmiiSource(Reset): frame.handle_tx_complete() self.dequeue_event.set() self.idle_event.set() + self.active_event.clear() self.queue_occupancy_bytes = 0 self.queue_occupancy_frames = 0 @@ -260,6 +264,7 @@ class XgmiiSource(Reset): if self.queue.empty(): self.idle_event.set() + self.active_event.clear() else: self.log.info("Reset de-asserted") if self._run_cr is None: @@ -363,7 +368,11 @@ class XgmiiSource(Reset): self.data.value = self.idle_d self.ctrl.value = self.idle_c self.active = False - self.idle_event.set() + + if ifg_cnt == 0 and self.queue.empty(): + self.idle_event.set() + self.active_event.clear() + await self.active_event.wait() elif self.enable is not None and not self.enable.value: await enable_event @@ -467,17 +476,24 @@ class XgmiiSink(Reset): clock_edge_event = RisingEdge(self.clock) + active_event = First(Edge(self.data), Edge(self.ctrl)) + enable_event = None if self.enable is not None: enable_event = RisingEdge(self.enable) + idle_d = sum([XgmiiCtrl.IDLE << n*8 for n in range(self.byte_lanes)]) + idle_c = 2**self.byte_lanes-1 + while True: await clock_edge_event if self.enable is None or self.enable.value: + data_val = self.data.value.integer + ctrl_val = self.ctrl.value.integer for offset in range(self.byte_lanes): - d_val = (self.data.value.integer >> (offset*8)) & 0xff - c_val = (self.ctrl.value.integer >> offset) & 1 + d_val = (data_val >> (offset*8)) & 0xff + c_val = (ctrl_val >> offset) & 1 if frame is None: if c_val and d_val == XgmiiCtrl.START: @@ -511,5 +527,8 @@ class XgmiiSink(Reset): frame.data.append(d_val) frame.ctrl.append(c_val) + if data_val == idle_d and ctrl_val == idle_c: + await active_event + elif self.enable is not None and not self.enable.value: await enable_event