sim._pycoro: avoid spurious wakeups.

This bug was introduced in commit e435a217.
This commit is contained in:
whitequark 2020-07-22 14:32:45 +00:00
parent d71e19e27c
commit 1321c4591d

View file

@ -1,7 +1,7 @@
import inspect import inspect
from ..hdl import * from ..hdl import *
from ..hdl.ast import Statement from ..hdl.ast import Statement, SignalSet
from ._cmds import * from ._cmds import *
from ._core import Process from ._core import Process
from ._pyrtl import _ValueCompiler, _RHSValueCompiler, _StatementCompiler from ._pyrtl import _ValueCompiler, _RHSValueCompiler, _StatementCompiler
@ -28,7 +28,7 @@ class PyCoroProcess(Process):
"result": None, "result": None,
**_ValueCompiler.helpers **_ValueCompiler.helpers
} }
self.waits_on = set() self.waits_on = SignalSet()
def src_loc(self): def src_loc(self):
coroutine = self.coroutine coroutine = self.coroutine
@ -40,14 +40,20 @@ class PyCoroProcess(Process):
frame = coroutine.cr_frame frame = coroutine.cr_frame
return "{}:{}".format(inspect.getfile(frame), inspect.getlineno(frame)) return "{}:{}".format(inspect.getfile(frame), inspect.getlineno(frame))
def add_trigger(self, signal, trigger=None):
self.state.add_trigger(self, signal, trigger=trigger)
self.waits_on.add(signal)
def clear_triggers(self):
for signal in self.waits_on:
self.state.remove_trigger(self, signal)
self.waits_on.clear()
def run(self): def run(self):
if self.coroutine is None: if self.coroutine is None:
return return
if self.waits_on: self.clear_triggers()
for signal in self.waits_on:
self.state.remove_trigger(self, signal)
self.waits_on.clear()
response = None response = None
while True: while True:
@ -76,10 +82,9 @@ class PyCoroProcess(Process):
raise NameError("Received command {!r} that refers to a nonexistent " raise NameError("Received command {!r} that refers to a nonexistent "
"domain {!r} from process {!r}" "domain {!r} from process {!r}"
.format(command, command.domain, self.src_loc())) .format(command, command.domain, self.src_loc()))
self.state.add_trigger(self, domain.clk, self.add_trigger(domain.clk, trigger=1 if domain.clk_edge == "pos" else 0)
trigger=1 if domain.clk_edge == "pos" else 0)
if domain.rst is not None and domain.async_reset: if domain.rst is not None and domain.async_reset:
self.state.add_trigger(self, domain.rst, trigger=1) self.add_trigger(domain.rst, trigger=1)
return return
elif type(command) is Settle: elif type(command) is Settle: