From 5855644670c312a38d5add3d4531bf5a3bf93928 Mon Sep 17 00:00:00 2001 From: Alex Forencich Date: Wed, 17 Mar 2021 18:13:04 -0700 Subject: [PATCH] Use cocotb async queues --- cocotbext/eth/gmii.py | 68 +++++++++++++++++++++++++----------------- cocotbext/eth/mii.py | 68 +++++++++++++++++++++++++----------------- cocotbext/eth/rgmii.py | 68 +++++++++++++++++++++++++----------------- cocotbext/eth/xgmii.py | 68 +++++++++++++++++++++++++----------------- 4 files changed, 164 insertions(+), 108 deletions(-) diff --git a/cocotbext/eth/gmii.py b/cocotbext/eth/gmii.py index 1b832ae..4fac4d5 100644 --- a/cocotbext/eth/gmii.py +++ b/cocotbext/eth/gmii.py @@ -25,9 +25,9 @@ THE SOFTWARE. import logging import struct import zlib -from collections import deque import cocotb +from cocotb.queue import Queue from cocotb.triggers import RisingEdge, Timer, First, Event from cocotb.utils import get_sim_time, get_sim_steps @@ -152,7 +152,9 @@ class GmiiSource(Reset): super().__init__(*args, **kwargs) self.active = False - self.queue = deque() + self.queue = Queue() + self.idle_event = Event() + self.idle_event.set() self.ifg = 12 self.mii_mode = False @@ -176,31 +178,37 @@ class GmiiSource(Reset): self._init_reset(reset, reset_active_level) async def send(self, frame): - self.send_nowait(frame) + frame = GmiiFrame(frame) + await self.queue.put(frame) + self.idle_event.clear() + self.queue_occupancy_bytes += len(frame) + self.queue_occupancy_frames += 1 def send_nowait(self, frame): frame = GmiiFrame(frame) + self.queue.put_nowait(frame) + self.idle_event.clear() self.queue_occupancy_bytes += len(frame) self.queue_occupancy_frames += 1 - self.queue.append(frame) def count(self): - return len(self.queue) + return self.queue.qsize() def empty(self): - return not self.queue + return self.queue.empty() def idle(self): return self.empty() and not self.active def clear(self): - self.queue.clear() + while not self.queue.empty(): + self.queue.get_nowait() + self.idle_event.set() self.queue_occupancy_bytes = 0 self.queue_occupancy_frames = 0 async def wait(self): - while not self.idle(): - await RisingEdge(self.clock) + await self.idle_event.wait() def _handle_reset(self, state): if state: @@ -232,9 +240,9 @@ class GmiiSource(Reset): # in IFG ifg_cnt -= 1 - elif frame is None and self.queue: + elif frame is None and not self.queue.empty(): # send frame - frame = self.queue.popleft() + frame = self.queue.get_nowait() self.queue_occupancy_bytes -= len(frame) self.queue_occupancy_frames -= 1 frame.sim_time_start = get_sim_time() @@ -279,6 +287,7 @@ class GmiiSource(Reset): self.er <= 0 self.dv <= 0 self.active = False + self.idle_event.set() class GmiiSink(Reset): @@ -301,8 +310,8 @@ class GmiiSink(Reset): super().__init__(*args, **kwargs) self.active = False - self.queue = deque() - self.sync = Event() + self.queue = Queue() + self.active_event = Event() self.mii_mode = False @@ -323,41 +332,46 @@ class GmiiSink(Reset): self._init_reset(reset, reset_active_level) async def recv(self, compact=True): - while self.empty(): - self.sync.clear() - await self.sync.wait() - return self.recv_nowait(compact) + frame = await self.queue.get() + if self.queue.empty(): + self.active_event.clear() + self.queue_occupancy_bytes -= len(frame) + self.queue_occupancy_frames -= 1 + return frame def recv_nowait(self, compact=True): - if self.queue: - frame = self.queue.popleft() + if not self.queue.empty(): + frame = self.queue.get_nowait() + if self.queue.empty(): + self.active_event.clear() self.queue_occupancy_bytes -= len(frame) self.queue_occupancy_frames -= 1 return frame return None def count(self): - return len(self.queue) + return self.queue.qsize() def empty(self): - return not self.queue + return self.queue.empty() def idle(self): return not self.active def clear(self): - self.queue.clear() + while not self.queue.empty(): + self.queue.get_nowait() + self.active_event.clear() self.queue_occupancy_bytes = 0 self.queue_occupancy_frames = 0 async def wait(self, timeout=0, timeout_unit=None): if not self.empty(): return - self.sync.clear() if timeout: - await First(self.sync.wait(), Timer(timeout, timeout_unit)) + await First(self.active_event.wait(), Timer(timeout, timeout_unit)) else: - await self.sync.wait() + await self.active_event.wait() def _handle_reset(self, state): if state: @@ -424,8 +438,8 @@ class GmiiSink(Reset): self.queue_occupancy_bytes += len(frame) self.queue_occupancy_frames += 1 - self.queue.append(frame) - self.sync.set() + self.queue.put_nowait(frame) + self.active_event.set() frame = None diff --git a/cocotbext/eth/mii.py b/cocotbext/eth/mii.py index 9fb521d..5f85891 100644 --- a/cocotbext/eth/mii.py +++ b/cocotbext/eth/mii.py @@ -23,9 +23,9 @@ THE SOFTWARE. """ import logging -from collections import deque import cocotb +from cocotb.queue import Queue from cocotb.triggers import RisingEdge, Timer, First, Event from cocotb.utils import get_sim_time, get_sim_steps @@ -54,7 +54,9 @@ class MiiSource(Reset): super().__init__(*args, **kwargs) self.active = False - self.queue = deque() + self.queue = Queue() + self.idle_event = Event() + self.idle_event.set() self.ifg = 12 @@ -77,31 +79,37 @@ class MiiSource(Reset): self._init_reset(reset, reset_active_level) async def send(self, frame): - self.send_nowait(frame) + frame = GmiiFrame(frame) + await self.queue.put(frame) + self.idle_event.clear() + self.queue_occupancy_bytes += len(frame) + self.queue_occupancy_frames += 1 def send_nowait(self, frame): frame = GmiiFrame(frame) + self.queue.put_nowait(frame) + self.idle_event.clear() self.queue_occupancy_bytes += len(frame) self.queue_occupancy_frames += 1 - self.queue.append(frame) def count(self): - return len(self.queue) + return self.queue.qsize() def empty(self): - return not self.queue + return self.queue.empty() def idle(self): return self.empty() and not self.active def clear(self): - self.queue.clear() + while not self.queue.empty(): + self.queue.get_nowait() + self.idle_event.set() self.queue_occupancy_bytes = 0 self.queue_occupancy_frames = 0 async def wait(self): - while not self.idle(): - await RisingEdge(self.clock) + await self.idle_event.wait() def _handle_reset(self, state): if state: @@ -133,9 +141,9 @@ class MiiSource(Reset): # in IFG ifg_cnt -= 1 - elif frame is None and self.queue: + elif frame is None and not self.queue.empty(): # send frame - frame = self.queue.popleft() + frame = self.queue.get_nowait() self.queue_occupancy_bytes -= len(frame) self.queue_occupancy_frames -= 1 frame.sim_time_start = get_sim_time() @@ -176,6 +184,7 @@ class MiiSource(Reset): self.er <= 0 self.dv <= 0 self.active = False + self.idle_event.set() class MiiSink(Reset): @@ -197,8 +206,8 @@ class MiiSink(Reset): super().__init__(*args, **kwargs) self.active = False - self.queue = deque() - self.sync = Event() + self.queue = Queue() + self.active_event = Event() self.queue_occupancy_bytes = 0 self.queue_occupancy_frames = 0 @@ -217,41 +226,46 @@ class MiiSink(Reset): self._init_reset(reset, reset_active_level) async def recv(self, compact=True): - while self.empty(): - self.sync.clear() - await self.sync.wait() - return self.recv_nowait(compact) + frame = await self.queue.get() + if self.queue.empty(): + self.active_event.clear() + self.queue_occupancy_bytes -= len(frame) + self.queue_occupancy_frames -= 1 + return frame def recv_nowait(self, compact=True): - if self.queue: - frame = self.queue.popleft() + if not self.queue.empty(): + frame = self.queue.get_nowait() + if self.queue.empty(): + self.active_event.clear() self.queue_occupancy_bytes -= len(frame) self.queue_occupancy_frames -= 1 return frame return None def count(self): - return len(self.queue) + return self.queue.qsize() def empty(self): - return not self.queue + return self.queue.empty() def idle(self): return not self.active def clear(self): - self.queue.clear() + while not self.queue.empty(): + self.queue.get_nowait() + self.active_event.clear() self.queue_occupancy_bytes = 0 self.queue_occupancy_frames = 0 async def wait(self, timeout=0, timeout_unit=None): if not self.empty(): return - self.sync.clear() if timeout: - await First(self.sync.wait(), Timer(timeout, timeout_unit)) + await First(self.active_event.wait(), Timer(timeout, timeout_unit)) else: - await self.sync.wait() + await self.active_event.wait() def _handle_reset(self, state): if state: @@ -313,8 +327,8 @@ class MiiSink(Reset): self.queue_occupancy_bytes += len(frame) self.queue_occupancy_frames += 1 - self.queue.append(frame) - self.sync.set() + self.queue.put_nowait(frame) + self.active_event.set() frame = None diff --git a/cocotbext/eth/rgmii.py b/cocotbext/eth/rgmii.py index fa95301..a651835 100644 --- a/cocotbext/eth/rgmii.py +++ b/cocotbext/eth/rgmii.py @@ -23,9 +23,9 @@ THE SOFTWARE. """ import logging -from collections import deque import cocotb +from cocotb.queue import Queue from cocotb.triggers import RisingEdge, FallingEdge, Timer, First, Event from cocotb.utils import get_sim_time, get_sim_steps @@ -56,7 +56,9 @@ class RgmiiSource(Reset): super().__init__(*args, **kwargs) self.active = False - self.queue = deque() + self.queue = Queue() + self.idle_event = Event() + self.idle_event.set() self.ifg = 12 self.mii_mode = False @@ -77,31 +79,37 @@ class RgmiiSource(Reset): self._init_reset(reset, reset_active_level) async def send(self, frame): - self.send_nowait(frame) + frame = GmiiFrame(frame) + await self.queue.put(frame) + self.idle_event.clear() + self.queue_occupancy_bytes += len(frame) + self.queue_occupancy_frames += 1 def send_nowait(self, frame): frame = GmiiFrame(frame) + self.queue.put_nowait(frame) + self.idle_event.clear() self.queue_occupancy_bytes += len(frame) self.queue_occupancy_frames += 1 - self.queue.append(frame) def count(self): - return len(self.queue) + return self.queue.qsize() def empty(self): - return not self.queue + return self.queue.empty() def idle(self): return self.empty() and not self.active def clear(self): - self.queue.clear() + while not self.queue.empty(): + self.queue.get_nowait() + self.idle_event.set() self.queue_occupancy_bytes = 0 self.queue_occupancy_frames = 0 async def wait(self): - while not self.idle(): - await RisingEdge(self.clock) + await self.idle_event.wait() def _handle_reset(self, state): if state: @@ -138,9 +146,9 @@ class RgmiiSource(Reset): # in IFG ifg_cnt -= 1 - elif frame is None and self.queue: + elif frame is None and not self.queue.empty(): # send frame - frame = self.queue.popleft() + frame = self.queue.get_nowait() self.queue_occupancy_bytes -= len(frame) self.queue_occupancy_frames -= 1 frame.sim_time_start = get_sim_time() @@ -183,6 +191,7 @@ class RgmiiSource(Reset): er = 0 en = 0 self.active = False + self.idle_event.set() await FallingEdge(self.clock) @@ -212,8 +221,8 @@ class RgmiiSink(Reset): super().__init__(*args, **kwargs) self.active = False - self.queue = deque() - self.sync = Event() + self.queue = Queue() + self.active_event = Event() self.mii_mode = False @@ -231,41 +240,46 @@ class RgmiiSink(Reset): self._init_reset(reset, reset_active_level) async def recv(self, compact=True): - while self.empty(): - self.sync.clear() - await self.sync.wait() - return self.recv_nowait(compact) + frame = await self.queue.get() + if self.queue.empty(): + self.active_event.clear() + self.queue_occupancy_bytes -= len(frame) + self.queue_occupancy_frames -= 1 + return frame def recv_nowait(self, compact=True): - if self.queue: - frame = self.queue.popleft() + if not self.queue.empty(): + frame = self.queue.get_nowait() + if self.queue.empty(): + self.active_event.clear() self.queue_occupancy_bytes -= len(frame) self.queue_occupancy_frames -= 1 return frame return None def count(self): - return len(self.queue) + return self.queue.qsize() def empty(self): - return not self.queue + return self.queue.empty() def idle(self): return not self.active def clear(self): - self.queue.clear() + while not self.queue.empty(): + self.queue.get_nowait() + self.active_event.clear() self.queue_occupancy_bytes = 0 self.queue_occupancy_frames = 0 async def wait(self, timeout=0, timeout_unit=None): if not self.empty(): return - self.sync.clear() if timeout: - await First(self.sync.wait(), Timer(timeout, timeout_unit)) + await First(self.active_event.wait(), Timer(timeout, timeout_unit)) else: - await self.sync.wait() + await self.active_event.wait() def _handle_reset(self, state): if state: @@ -342,8 +356,8 @@ class RgmiiSink(Reset): self.queue_occupancy_bytes += len(frame) self.queue_occupancy_frames += 1 - self.queue.append(frame) - self.sync.set() + self.queue.put_nowait(frame) + self.active_event.set() frame = None diff --git a/cocotbext/eth/xgmii.py b/cocotbext/eth/xgmii.py index 7be3cfd..6db1a05 100644 --- a/cocotbext/eth/xgmii.py +++ b/cocotbext/eth/xgmii.py @@ -25,9 +25,9 @@ THE SOFTWARE. import logging import struct import zlib -from collections import deque import cocotb +from cocotb.queue import Queue from cocotb.triggers import RisingEdge, Timer, First, Event from cocotb.utils import get_sim_time @@ -153,7 +153,9 @@ class XgmiiSource(Reset): super().__init__(*args, **kwargs) self.active = False - self.queue = deque() + self.queue = Queue() + self.idle_event = Event() + self.idle_event.set() self.enable_dic = True self.ifg = 12 @@ -182,31 +184,37 @@ class XgmiiSource(Reset): self._init_reset(reset, reset_active_level) async def send(self, frame): - self.send_nowait(frame) + frame = XgmiiFrame(frame) + await self.queue.put(frame) + self.idle_event.clear() + self.queue_occupancy_bytes += len(frame) + self.queue_occupancy_frames += 1 def send_nowait(self, frame): frame = XgmiiFrame(frame) + self.queue.put_nowait(frame) + self.idle_event.clear() self.queue_occupancy_bytes += len(frame) self.queue_occupancy_frames += 1 - self.queue.append(frame) def count(self): - return len(self.queue) + return self.queue.qsize() def empty(self): - return not self.queue + return self.queue.empty() def idle(self): return self.empty() and not self.active def clear(self): - self.queue.clear() + while not self.queue.empty(): + self.queue.get_nowait() + self.idle_event.set() self.queue_occupancy_bytes = 0 self.queue_occupancy_frames = 0 async def wait(self): - while not self.idle(): - await RisingEdge(self.clock) + await self.idle_event.wait() def _handle_reset(self, state): if state: @@ -243,9 +251,9 @@ class XgmiiSource(Reset): elif frame is None: # idle - if self.queue: + if not self.queue.empty(): # send frame - frame = self.queue.popleft() + frame = self.queue.get_nowait() self.queue_occupancy_bytes -= len(frame) self.queue_occupancy_frames -= 1 frame.sim_time_start = get_sim_time() @@ -309,6 +317,7 @@ class XgmiiSource(Reset): self.data <= self.idle_d self.ctrl <= self.idle_c self.active = False + self.idle_event.set() class XgmiiSink(Reset): @@ -329,8 +338,8 @@ class XgmiiSink(Reset): super().__init__(*args, **kwargs) self.active = False - self.queue = deque() - self.sync = Event() + self.queue = Queue() + self.active_event = Event() self.queue_occupancy_bytes = 0 self.queue_occupancy_frames = 0 @@ -345,41 +354,46 @@ class XgmiiSink(Reset): self._init_reset(reset, reset_active_level) async def recv(self, compact=True): - while self.empty(): - self.sync.clear() - await self.sync.wait() - return self.recv_nowait(compact) + frame = await self.queue.get() + if self.queue.empty(): + self.active_event.clear() + self.queue_occupancy_bytes -= len(frame) + self.queue_occupancy_frames -= 1 + return frame def recv_nowait(self, compact=True): - if self.queue: - frame = self.queue.popleft() + if not self.queue.empty(): + frame = self.queue.get_nowait() + if self.queue.empty(): + self.active_event.clear() self.queue_occupancy_bytes -= len(frame) self.queue_occupancy_frames -= 1 return frame return None def count(self): - return len(self.queue) + return self.queue.qsize() def empty(self): - return not self.queue + return self.queue.empty() def idle(self): return not self.active def clear(self): - self.queue.clear() + while not self.queue.empty(): + self.queue.get_nowait() + self.active_event.clear() self.queue_occupancy_bytes = 0 self.queue_occupancy_frames = 0 async def wait(self, timeout=0, timeout_unit=None): if not self.empty(): return - self.sync.clear() if timeout: - await First(self.sync.wait(), Timer(timeout, timeout_unit)) + await First(self.active_event.wait(), Timer(timeout, timeout_unit)) else: - await self.sync.wait() + await self.active_event.wait() def _handle_reset(self, state): if state: @@ -427,8 +441,8 @@ class XgmiiSink(Reset): self.queue_occupancy_bytes += len(frame) self.queue_occupancy_frames += 1 - self.queue.append(frame) - self.sync.set() + self.queue.put_nowait(frame) + self.active_event.set() frame = None else: