Rewrite stream resets
This commit is contained in:
@@ -29,6 +29,8 @@ import cocotb
|
|||||||
from cocotb.triggers import RisingEdge, Event, First, Timer
|
from cocotb.triggers import RisingEdge, Event, First, Timer
|
||||||
from cocotb.bus import Bus
|
from cocotb.bus import Bus
|
||||||
|
|
||||||
|
from .reset import Reset
|
||||||
|
|
||||||
|
|
||||||
class StreamTransaction:
|
class StreamTransaction:
|
||||||
|
|
||||||
@@ -48,7 +50,7 @@ class StreamTransaction:
|
|||||||
return f"{type(self).__name__}({', '.join(f'{s}={int(getattr(self, s))}' for s in self._signals)})"
|
return f"{type(self).__name__}({', '.join(f'{s}={int(getattr(self, s))}' for s in self._signals)})"
|
||||||
|
|
||||||
|
|
||||||
class StreamBase:
|
class StreamBase(Reset):
|
||||||
|
|
||||||
_signals = ["data", "valid", "ready"]
|
_signals = ["data", "valid", "ready"]
|
||||||
_optional_signals = []
|
_optional_signals = []
|
||||||
@@ -73,6 +75,8 @@ class StreamBase:
|
|||||||
|
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
self.active = False
|
||||||
|
|
||||||
self.queue = deque()
|
self.queue = deque()
|
||||||
self.queue_sync = Event()
|
self.queue_sync = Event()
|
||||||
|
|
||||||
@@ -98,6 +102,10 @@ class StreamBase:
|
|||||||
v.binstr = 'x'*len(v)
|
v.binstr = 'x'*len(v)
|
||||||
getattr(self.bus, sig).setimmediatevalue(v)
|
getattr(self.bus, sig).setimmediatevalue(v)
|
||||||
|
|
||||||
|
self._run_cr = None
|
||||||
|
|
||||||
|
self._init_reset(reset)
|
||||||
|
|
||||||
def count(self):
|
def count(self):
|
||||||
return len(self.queue)
|
return len(self.queue)
|
||||||
|
|
||||||
@@ -107,6 +115,22 @@ class StreamBase:
|
|||||||
def clear(self):
|
def clear(self):
|
||||||
self.queue.clear()
|
self.queue.clear()
|
||||||
|
|
||||||
|
def _handle_reset(self, state):
|
||||||
|
if state:
|
||||||
|
self.log.info("Reset asserted")
|
||||||
|
if self._run_cr is not None:
|
||||||
|
self._run_cr.kill()
|
||||||
|
self._run_cr = None
|
||||||
|
else:
|
||||||
|
self.log.info("Reset de-asserted")
|
||||||
|
if self._run_cr is None:
|
||||||
|
self._run_cr = cocotb.fork(self._run())
|
||||||
|
|
||||||
|
self.active = False
|
||||||
|
|
||||||
|
async def _run(self):
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
|
||||||
class StreamPause:
|
class StreamPause:
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
@@ -142,13 +166,6 @@ class StreamSource(StreamBase, StreamPause):
|
|||||||
_valid_init = 0
|
_valid_init = 0
|
||||||
_ready_init = None
|
_ready_init = None
|
||||||
|
|
||||||
def __init__(self, entity, name, clock, reset=None, *args, **kwargs):
|
|
||||||
super().__init__(entity, name, clock, reset, *args, **kwargs)
|
|
||||||
|
|
||||||
self.active = False
|
|
||||||
|
|
||||||
cocotb.fork(self._run())
|
|
||||||
|
|
||||||
async def send(self, obj):
|
async def send(self, obj):
|
||||||
self.send_nowait(obj)
|
self.send_nowait(obj)
|
||||||
|
|
||||||
@@ -162,6 +179,12 @@ class StreamSource(StreamBase, StreamPause):
|
|||||||
while not self.idle():
|
while not self.idle():
|
||||||
await RisingEdge(self.clock)
|
await RisingEdge(self.clock)
|
||||||
|
|
||||||
|
def _handle_reset(self, state):
|
||||||
|
super()._handle_reset(state)
|
||||||
|
|
||||||
|
if self.valid is not None:
|
||||||
|
self.valid <= 0
|
||||||
|
|
||||||
async def _run(self):
|
async def _run(self):
|
||||||
while True:
|
while True:
|
||||||
await RisingEdge(self.clock)
|
await RisingEdge(self.clock)
|
||||||
@@ -170,13 +193,6 @@ class StreamSource(StreamBase, StreamPause):
|
|||||||
ready_sample = self.ready is None or self.ready.value
|
ready_sample = self.ready is None or self.ready.value
|
||||||
valid_sample = self.valid is None or self.valid.value
|
valid_sample = self.valid is None or self.valid.value
|
||||||
|
|
||||||
if self.reset is not None and self.reset.value:
|
|
||||||
self.clear()
|
|
||||||
if self.valid is not None:
|
|
||||||
self.valid <= 0
|
|
||||||
self.active = False
|
|
||||||
continue
|
|
||||||
|
|
||||||
if (ready_sample and valid_sample) or (not valid_sample):
|
if (ready_sample and valid_sample) or (not valid_sample):
|
||||||
if self.queue and not self.pause:
|
if self.queue and not self.pause:
|
||||||
self.bus.drive(self.queue.popleft())
|
self.bus.drive(self.queue.popleft())
|
||||||
@@ -196,11 +212,6 @@ class StreamMonitor(StreamBase):
|
|||||||
_valid_init = None
|
_valid_init = None
|
||||||
_ready_init = None
|
_ready_init = None
|
||||||
|
|
||||||
def __init__(self, entity, name, clock, reset=None, *args, **kwargs):
|
|
||||||
super().__init__(entity, name, clock, reset, *args, **kwargs)
|
|
||||||
|
|
||||||
cocotb.fork(self._run())
|
|
||||||
|
|
||||||
async def recv(self):
|
async def recv(self):
|
||||||
while self.empty():
|
while self.empty():
|
||||||
self.queue_sync.clear()
|
self.queue_sync.clear()
|
||||||
@@ -229,10 +240,6 @@ class StreamMonitor(StreamBase):
|
|||||||
ready_sample = self.ready is None or self.ready.value
|
ready_sample = self.ready is None or self.ready.value
|
||||||
valid_sample = self.valid is None or self.valid.value
|
valid_sample = self.valid is None or self.valid.value
|
||||||
|
|
||||||
if self.reset is not None and self.reset.value:
|
|
||||||
self.clear()
|
|
||||||
continue
|
|
||||||
|
|
||||||
if ready_sample and valid_sample:
|
if ready_sample and valid_sample:
|
||||||
obj = self._transaction_obj()
|
obj = self._transaction_obj()
|
||||||
self.bus.sample(obj)
|
self.bus.sample(obj)
|
||||||
@@ -258,6 +265,12 @@ class StreamSink(StreamMonitor, StreamPause):
|
|||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def _handle_reset(self, state):
|
||||||
|
super()._handle_reset(state)
|
||||||
|
|
||||||
|
if self.ready is not None:
|
||||||
|
self.ready <= 0
|
||||||
|
|
||||||
async def _run(self):
|
async def _run(self):
|
||||||
while True:
|
while True:
|
||||||
await RisingEdge(self.clock)
|
await RisingEdge(self.clock)
|
||||||
@@ -266,12 +279,6 @@ class StreamSink(StreamMonitor, StreamPause):
|
|||||||
ready_sample = self.ready is None or self.ready.value
|
ready_sample = self.ready is None or self.ready.value
|
||||||
valid_sample = self.valid is None or self.valid.value
|
valid_sample = self.valid is None or self.valid.value
|
||||||
|
|
||||||
if self.reset is not None and self.reset.value:
|
|
||||||
self.clear()
|
|
||||||
if self.ready is not None:
|
|
||||||
self.ready <= 0
|
|
||||||
continue
|
|
||||||
|
|
||||||
if ready_sample and valid_sample:
|
if ready_sample and valid_sample:
|
||||||
obj = self._transaction_obj()
|
obj = self._transaction_obj()
|
||||||
self.bus.sample(obj)
|
self.bus.sample(obj)
|
||||||
|
|||||||
Reference in New Issue
Block a user