Use cocotb async queues

This commit is contained in:
Alex Forencich
2021-03-17 18:13:04 -07:00
parent a81d43216e
commit 5855644670
4 changed files with 164 additions and 108 deletions

View File

@@ -25,9 +25,9 @@ THE SOFTWARE.
import logging import logging
import struct import struct
import zlib import zlib
from collections import deque
import cocotb import cocotb
from cocotb.queue import Queue
from cocotb.triggers import RisingEdge, Timer, First, Event from cocotb.triggers import RisingEdge, Timer, First, Event
from cocotb.utils import get_sim_time, get_sim_steps from cocotb.utils import get_sim_time, get_sim_steps
@@ -152,7 +152,9 @@ class GmiiSource(Reset):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.active = False self.active = False
self.queue = deque() self.queue = Queue()
self.idle_event = Event()
self.idle_event.set()
self.ifg = 12 self.ifg = 12
self.mii_mode = False self.mii_mode = False
@@ -176,31 +178,37 @@ class GmiiSource(Reset):
self._init_reset(reset, reset_active_level) self._init_reset(reset, reset_active_level)
async def send(self, frame): 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): def send_nowait(self, frame):
frame = GmiiFrame(frame) frame = GmiiFrame(frame)
self.queue.put_nowait(frame)
self.idle_event.clear()
self.queue_occupancy_bytes += len(frame) self.queue_occupancy_bytes += len(frame)
self.queue_occupancy_frames += 1 self.queue_occupancy_frames += 1
self.queue.append(frame)
def count(self): def count(self):
return len(self.queue) return self.queue.qsize()
def empty(self): def empty(self):
return not self.queue return self.queue.empty()
def idle(self): def idle(self):
return self.empty() and not self.active return self.empty() and not self.active
def clear(self): 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_bytes = 0
self.queue_occupancy_frames = 0 self.queue_occupancy_frames = 0
async def wait(self): async def wait(self):
while not self.idle(): await self.idle_event.wait()
await RisingEdge(self.clock)
def _handle_reset(self, state): def _handle_reset(self, state):
if state: if state:
@@ -232,9 +240,9 @@ class GmiiSource(Reset):
# in IFG # in IFG
ifg_cnt -= 1 ifg_cnt -= 1
elif frame is None and self.queue: elif frame is None and not self.queue.empty():
# send frame # send frame
frame = self.queue.popleft() frame = self.queue.get_nowait()
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() frame.sim_time_start = get_sim_time()
@@ -279,6 +287,7 @@ class GmiiSource(Reset):
self.er <= 0 self.er <= 0
self.dv <= 0 self.dv <= 0
self.active = False self.active = False
self.idle_event.set()
class GmiiSink(Reset): class GmiiSink(Reset):
@@ -301,8 +310,8 @@ class GmiiSink(Reset):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.active = False self.active = False
self.queue = deque() self.queue = Queue()
self.sync = Event() self.active_event = Event()
self.mii_mode = False self.mii_mode = False
@@ -323,41 +332,46 @@ class GmiiSink(Reset):
self._init_reset(reset, reset_active_level) self._init_reset(reset, reset_active_level)
async def recv(self, compact=True): async def recv(self, compact=True):
while self.empty(): frame = await self.queue.get()
self.sync.clear() if self.queue.empty():
await self.sync.wait() self.active_event.clear()
return self.recv_nowait(compact) self.queue_occupancy_bytes -= len(frame)
self.queue_occupancy_frames -= 1
return frame
def recv_nowait(self, compact=True): def recv_nowait(self, compact=True):
if self.queue: if not self.queue.empty():
frame = self.queue.popleft() frame = self.queue.get_nowait()
if self.queue.empty():
self.active_event.clear()
self.queue_occupancy_bytes -= len(frame) self.queue_occupancy_bytes -= len(frame)
self.queue_occupancy_frames -= 1 self.queue_occupancy_frames -= 1
return frame return frame
return None return None
def count(self): def count(self):
return len(self.queue) return self.queue.qsize()
def empty(self): def empty(self):
return not self.queue return self.queue.empty()
def idle(self): def idle(self):
return not self.active return not self.active
def clear(self): 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_bytes = 0
self.queue_occupancy_frames = 0 self.queue_occupancy_frames = 0
async def wait(self, timeout=0, timeout_unit=None): async def wait(self, timeout=0, timeout_unit=None):
if not self.empty(): if not self.empty():
return return
self.sync.clear()
if timeout: if timeout:
await First(self.sync.wait(), Timer(timeout, timeout_unit)) await First(self.active_event.wait(), Timer(timeout, timeout_unit))
else: else:
await self.sync.wait() await self.active_event.wait()
def _handle_reset(self, state): def _handle_reset(self, state):
if state: if state:
@@ -424,8 +438,8 @@ class GmiiSink(Reset):
self.queue_occupancy_bytes += len(frame) self.queue_occupancy_bytes += len(frame)
self.queue_occupancy_frames += 1 self.queue_occupancy_frames += 1
self.queue.append(frame) self.queue.put_nowait(frame)
self.sync.set() self.active_event.set()
frame = None frame = None

View File

@@ -23,9 +23,9 @@ THE SOFTWARE.
""" """
import logging import logging
from collections import deque
import cocotb import cocotb
from cocotb.queue import Queue
from cocotb.triggers import RisingEdge, Timer, First, Event from cocotb.triggers import RisingEdge, Timer, First, Event
from cocotb.utils import get_sim_time, get_sim_steps from cocotb.utils import get_sim_time, get_sim_steps
@@ -54,7 +54,9 @@ class MiiSource(Reset):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.active = False self.active = False
self.queue = deque() self.queue = Queue()
self.idle_event = Event()
self.idle_event.set()
self.ifg = 12 self.ifg = 12
@@ -77,31 +79,37 @@ class MiiSource(Reset):
self._init_reset(reset, reset_active_level) self._init_reset(reset, reset_active_level)
async def send(self, frame): 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): def send_nowait(self, frame):
frame = GmiiFrame(frame) frame = GmiiFrame(frame)
self.queue.put_nowait(frame)
self.idle_event.clear()
self.queue_occupancy_bytes += len(frame) self.queue_occupancy_bytes += len(frame)
self.queue_occupancy_frames += 1 self.queue_occupancy_frames += 1
self.queue.append(frame)
def count(self): def count(self):
return len(self.queue) return self.queue.qsize()
def empty(self): def empty(self):
return not self.queue return self.queue.empty()
def idle(self): def idle(self):
return self.empty() and not self.active return self.empty() and not self.active
def clear(self): 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_bytes = 0
self.queue_occupancy_frames = 0 self.queue_occupancy_frames = 0
async def wait(self): async def wait(self):
while not self.idle(): await self.idle_event.wait()
await RisingEdge(self.clock)
def _handle_reset(self, state): def _handle_reset(self, state):
if state: if state:
@@ -133,9 +141,9 @@ class MiiSource(Reset):
# in IFG # in IFG
ifg_cnt -= 1 ifg_cnt -= 1
elif frame is None and self.queue: elif frame is None and not self.queue.empty():
# send frame # send frame
frame = self.queue.popleft() frame = self.queue.get_nowait()
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() frame.sim_time_start = get_sim_time()
@@ -176,6 +184,7 @@ class MiiSource(Reset):
self.er <= 0 self.er <= 0
self.dv <= 0 self.dv <= 0
self.active = False self.active = False
self.idle_event.set()
class MiiSink(Reset): class MiiSink(Reset):
@@ -197,8 +206,8 @@ class MiiSink(Reset):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.active = False self.active = False
self.queue = deque() self.queue = Queue()
self.sync = Event() self.active_event = Event()
self.queue_occupancy_bytes = 0 self.queue_occupancy_bytes = 0
self.queue_occupancy_frames = 0 self.queue_occupancy_frames = 0
@@ -217,41 +226,46 @@ class MiiSink(Reset):
self._init_reset(reset, reset_active_level) self._init_reset(reset, reset_active_level)
async def recv(self, compact=True): async def recv(self, compact=True):
while self.empty(): frame = await self.queue.get()
self.sync.clear() if self.queue.empty():
await self.sync.wait() self.active_event.clear()
return self.recv_nowait(compact) self.queue_occupancy_bytes -= len(frame)
self.queue_occupancy_frames -= 1
return frame
def recv_nowait(self, compact=True): def recv_nowait(self, compact=True):
if self.queue: if not self.queue.empty():
frame = self.queue.popleft() frame = self.queue.get_nowait()
if self.queue.empty():
self.active_event.clear()
self.queue_occupancy_bytes -= len(frame) self.queue_occupancy_bytes -= len(frame)
self.queue_occupancy_frames -= 1 self.queue_occupancy_frames -= 1
return frame return frame
return None return None
def count(self): def count(self):
return len(self.queue) return self.queue.qsize()
def empty(self): def empty(self):
return not self.queue return self.queue.empty()
def idle(self): def idle(self):
return not self.active return not self.active
def clear(self): 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_bytes = 0
self.queue_occupancy_frames = 0 self.queue_occupancy_frames = 0
async def wait(self, timeout=0, timeout_unit=None): async def wait(self, timeout=0, timeout_unit=None):
if not self.empty(): if not self.empty():
return return
self.sync.clear()
if timeout: if timeout:
await First(self.sync.wait(), Timer(timeout, timeout_unit)) await First(self.active_event.wait(), Timer(timeout, timeout_unit))
else: else:
await self.sync.wait() await self.active_event.wait()
def _handle_reset(self, state): def _handle_reset(self, state):
if state: if state:
@@ -313,8 +327,8 @@ class MiiSink(Reset):
self.queue_occupancy_bytes += len(frame) self.queue_occupancy_bytes += len(frame)
self.queue_occupancy_frames += 1 self.queue_occupancy_frames += 1
self.queue.append(frame) self.queue.put_nowait(frame)
self.sync.set() self.active_event.set()
frame = None frame = None

View File

@@ -23,9 +23,9 @@ THE SOFTWARE.
""" """
import logging import logging
from collections import deque
import cocotb import cocotb
from cocotb.queue import Queue
from cocotb.triggers import RisingEdge, FallingEdge, Timer, First, Event from cocotb.triggers import RisingEdge, FallingEdge, Timer, First, Event
from cocotb.utils import get_sim_time, get_sim_steps from cocotb.utils import get_sim_time, get_sim_steps
@@ -56,7 +56,9 @@ class RgmiiSource(Reset):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.active = False self.active = False
self.queue = deque() self.queue = Queue()
self.idle_event = Event()
self.idle_event.set()
self.ifg = 12 self.ifg = 12
self.mii_mode = False self.mii_mode = False
@@ -77,31 +79,37 @@ class RgmiiSource(Reset):
self._init_reset(reset, reset_active_level) self._init_reset(reset, reset_active_level)
async def send(self, frame): 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): def send_nowait(self, frame):
frame = GmiiFrame(frame) frame = GmiiFrame(frame)
self.queue.put_nowait(frame)
self.idle_event.clear()
self.queue_occupancy_bytes += len(frame) self.queue_occupancy_bytes += len(frame)
self.queue_occupancy_frames += 1 self.queue_occupancy_frames += 1
self.queue.append(frame)
def count(self): def count(self):
return len(self.queue) return self.queue.qsize()
def empty(self): def empty(self):
return not self.queue return self.queue.empty()
def idle(self): def idle(self):
return self.empty() and not self.active return self.empty() and not self.active
def clear(self): 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_bytes = 0
self.queue_occupancy_frames = 0 self.queue_occupancy_frames = 0
async def wait(self): async def wait(self):
while not self.idle(): await self.idle_event.wait()
await RisingEdge(self.clock)
def _handle_reset(self, state): def _handle_reset(self, state):
if state: if state:
@@ -138,9 +146,9 @@ class RgmiiSource(Reset):
# in IFG # in IFG
ifg_cnt -= 1 ifg_cnt -= 1
elif frame is None and self.queue: elif frame is None and not self.queue.empty():
# send frame # send frame
frame = self.queue.popleft() frame = self.queue.get_nowait()
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() frame.sim_time_start = get_sim_time()
@@ -183,6 +191,7 @@ class RgmiiSource(Reset):
er = 0 er = 0
en = 0 en = 0
self.active = False self.active = False
self.idle_event.set()
await FallingEdge(self.clock) await FallingEdge(self.clock)
@@ -212,8 +221,8 @@ class RgmiiSink(Reset):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.active = False self.active = False
self.queue = deque() self.queue = Queue()
self.sync = Event() self.active_event = Event()
self.mii_mode = False self.mii_mode = False
@@ -231,41 +240,46 @@ class RgmiiSink(Reset):
self._init_reset(reset, reset_active_level) self._init_reset(reset, reset_active_level)
async def recv(self, compact=True): async def recv(self, compact=True):
while self.empty(): frame = await self.queue.get()
self.sync.clear() if self.queue.empty():
await self.sync.wait() self.active_event.clear()
return self.recv_nowait(compact) self.queue_occupancy_bytes -= len(frame)
self.queue_occupancy_frames -= 1
return frame
def recv_nowait(self, compact=True): def recv_nowait(self, compact=True):
if self.queue: if not self.queue.empty():
frame = self.queue.popleft() frame = self.queue.get_nowait()
if self.queue.empty():
self.active_event.clear()
self.queue_occupancy_bytes -= len(frame) self.queue_occupancy_bytes -= len(frame)
self.queue_occupancy_frames -= 1 self.queue_occupancy_frames -= 1
return frame return frame
return None return None
def count(self): def count(self):
return len(self.queue) return self.queue.qsize()
def empty(self): def empty(self):
return not self.queue return self.queue.empty()
def idle(self): def idle(self):
return not self.active return not self.active
def clear(self): 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_bytes = 0
self.queue_occupancy_frames = 0 self.queue_occupancy_frames = 0
async def wait(self, timeout=0, timeout_unit=None): async def wait(self, timeout=0, timeout_unit=None):
if not self.empty(): if not self.empty():
return return
self.sync.clear()
if timeout: if timeout:
await First(self.sync.wait(), Timer(timeout, timeout_unit)) await First(self.active_event.wait(), Timer(timeout, timeout_unit))
else: else:
await self.sync.wait() await self.active_event.wait()
def _handle_reset(self, state): def _handle_reset(self, state):
if state: if state:
@@ -342,8 +356,8 @@ class RgmiiSink(Reset):
self.queue_occupancy_bytes += len(frame) self.queue_occupancy_bytes += len(frame)
self.queue_occupancy_frames += 1 self.queue_occupancy_frames += 1
self.queue.append(frame) self.queue.put_nowait(frame)
self.sync.set() self.active_event.set()
frame = None frame = None

View File

@@ -25,9 +25,9 @@ THE SOFTWARE.
import logging import logging
import struct import struct
import zlib import zlib
from collections import deque
import cocotb import cocotb
from cocotb.queue import Queue
from cocotb.triggers import RisingEdge, Timer, First, Event from cocotb.triggers import RisingEdge, Timer, First, Event
from cocotb.utils import get_sim_time from cocotb.utils import get_sim_time
@@ -153,7 +153,9 @@ class XgmiiSource(Reset):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.active = False self.active = False
self.queue = deque() self.queue = Queue()
self.idle_event = Event()
self.idle_event.set()
self.enable_dic = True self.enable_dic = True
self.ifg = 12 self.ifg = 12
@@ -182,31 +184,37 @@ class XgmiiSource(Reset):
self._init_reset(reset, reset_active_level) self._init_reset(reset, reset_active_level)
async def send(self, frame): 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): def send_nowait(self, frame):
frame = XgmiiFrame(frame) frame = XgmiiFrame(frame)
self.queue.put_nowait(frame)
self.idle_event.clear()
self.queue_occupancy_bytes += len(frame) self.queue_occupancy_bytes += len(frame)
self.queue_occupancy_frames += 1 self.queue_occupancy_frames += 1
self.queue.append(frame)
def count(self): def count(self):
return len(self.queue) return self.queue.qsize()
def empty(self): def empty(self):
return not self.queue return self.queue.empty()
def idle(self): def idle(self):
return self.empty() and not self.active return self.empty() and not self.active
def clear(self): 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_bytes = 0
self.queue_occupancy_frames = 0 self.queue_occupancy_frames = 0
async def wait(self): async def wait(self):
while not self.idle(): await self.idle_event.wait()
await RisingEdge(self.clock)
def _handle_reset(self, state): def _handle_reset(self, state):
if state: if state:
@@ -243,9 +251,9 @@ class XgmiiSource(Reset):
elif frame is None: elif frame is None:
# idle # idle
if self.queue: if not self.queue.empty():
# send frame # send frame
frame = self.queue.popleft() frame = self.queue.get_nowait()
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() frame.sim_time_start = get_sim_time()
@@ -309,6 +317,7 @@ class XgmiiSource(Reset):
self.data <= self.idle_d self.data <= self.idle_d
self.ctrl <= self.idle_c self.ctrl <= self.idle_c
self.active = False self.active = False
self.idle_event.set()
class XgmiiSink(Reset): class XgmiiSink(Reset):
@@ -329,8 +338,8 @@ class XgmiiSink(Reset):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.active = False self.active = False
self.queue = deque() self.queue = Queue()
self.sync = Event() self.active_event = Event()
self.queue_occupancy_bytes = 0 self.queue_occupancy_bytes = 0
self.queue_occupancy_frames = 0 self.queue_occupancy_frames = 0
@@ -345,41 +354,46 @@ class XgmiiSink(Reset):
self._init_reset(reset, reset_active_level) self._init_reset(reset, reset_active_level)
async def recv(self, compact=True): async def recv(self, compact=True):
while self.empty(): frame = await self.queue.get()
self.sync.clear() if self.queue.empty():
await self.sync.wait() self.active_event.clear()
return self.recv_nowait(compact) self.queue_occupancy_bytes -= len(frame)
self.queue_occupancy_frames -= 1
return frame
def recv_nowait(self, compact=True): def recv_nowait(self, compact=True):
if self.queue: if not self.queue.empty():
frame = self.queue.popleft() frame = self.queue.get_nowait()
if self.queue.empty():
self.active_event.clear()
self.queue_occupancy_bytes -= len(frame) self.queue_occupancy_bytes -= len(frame)
self.queue_occupancy_frames -= 1 self.queue_occupancy_frames -= 1
return frame return frame
return None return None
def count(self): def count(self):
return len(self.queue) return self.queue.qsize()
def empty(self): def empty(self):
return not self.queue return self.queue.empty()
def idle(self): def idle(self):
return not self.active return not self.active
def clear(self): 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_bytes = 0
self.queue_occupancy_frames = 0 self.queue_occupancy_frames = 0
async def wait(self, timeout=0, timeout_unit=None): async def wait(self, timeout=0, timeout_unit=None):
if not self.empty(): if not self.empty():
return return
self.sync.clear()
if timeout: if timeout:
await First(self.sync.wait(), Timer(timeout, timeout_unit)) await First(self.active_event.wait(), Timer(timeout, timeout_unit))
else: else:
await self.sync.wait() await self.active_event.wait()
def _handle_reset(self, state): def _handle_reset(self, state):
if state: if state:
@@ -427,8 +441,8 @@ class XgmiiSink(Reset):
self.queue_occupancy_bytes += len(frame) self.queue_occupancy_bytes += len(frame)
self.queue_occupancy_frames += 1 self.queue_occupancy_frames += 1
self.queue.append(frame) self.queue.put_nowait(frame)
self.sync.set() self.active_event.set()
frame = None frame = None
else: else: