back.pysim: implement blocking assignment semantics correctly.

This commit is contained in:
whitequark 2018-12-14 18:47:12 +00:00
parent 120d817123
commit 70ebc6f2c1

View file

@ -1,5 +1,6 @@
import math import math
import inspect import inspect
from contextlib import contextmanager
from vcd import VCDWriter from vcd import VCDWriter
from vcd.gtkw import GTKWSave from vcd.gtkw import GTKWSave
@ -24,9 +25,6 @@ class _State:
self.curr_dirty = ValueSet() self.curr_dirty = ValueSet()
self.next_dirty = ValueSet() self.next_dirty = ValueSet()
def get(self, signal):
return self.curr[signal]
def set(self, signal, value): def set(self, signal, value):
assert isinstance(value, int) assert isinstance(value, int)
if self.next[signal] != value: if self.next[signal] != value:
@ -47,15 +45,21 @@ normalize = Const.normalize
class _RHSValueCompiler(ValueTransformer): class _RHSValueCompiler(ValueTransformer):
def __init__(self, sensitivity): def __init__(self, sensitivity=None):
self.sensitivity = sensitivity self.sensitivity = sensitivity
self.signal_mode = "next"
def on_Const(self, value): def on_Const(self, value):
return lambda state: value.value return lambda state: value.value
def on_Signal(self, value): def on_Signal(self, value):
self.sensitivity.add(value) if self.sensitivity:
return lambda state: state.get(value) self.sensitivity.add(value)
if self.signal_mode == "curr":
return lambda state: state.curr[value]
if self.signal_mode == "next":
return lambda state: state.next[value]
raise NotImplementedError # :nocov:
def on_ClockSignal(self, value): def on_ClockSignal(self, value):
raise NotImplementedError # :nocov: raise NotImplementedError # :nocov:
@ -147,6 +151,14 @@ class _StatementCompiler(StatementTransformer):
self.sensitivity = ValueSet() self.sensitivity = ValueSet()
self.rhs_compiler = _RHSValueCompiler(self.sensitivity) self.rhs_compiler = _RHSValueCompiler(self.sensitivity)
@contextmanager
def initial(self):
try:
self.rhs_compiler.signal_mode = "curr"
yield
finally:
self.rhs_compiler.signal_mode = "next"
def lhs_compiler(self, value): def lhs_compiler(self, value):
# TODO # TODO
return lambda state, arg: state.set(value, arg) return lambda state, arg: state.set(value, arg)
@ -342,20 +354,28 @@ class Simulator:
self._sync_signals.update(signals) self._sync_signals.update(signals)
self._domain_signals[domain].update(signals) self._domain_signals[domain].update(signals)
statements = [] initial_stmts = []
for signal in fragment.iter_comb(): for signal in fragment.iter_comb():
statements.append(signal.eq(signal.reset)) initial_stmts.append(signal.eq(signal.reset))
for domain, signal in fragment.iter_sync(): for domain, signal in fragment.iter_sync():
statements.append(signal.eq(signal)) initial_stmts.append(signal.eq(signal))
statements += fragment.statements
compiler = _StatementCompiler()
def make_funclet():
with compiler.initial():
funclet_init = compiler(initial_stmts)
funclet_frag = compiler(fragment.statements)
def funclet(state):
funclet_init(state)
funclet_frag(state)
return funclet
funclet = make_funclet()
def add_funclet(signal, funclet): def add_funclet(signal, funclet):
if signal not in self._funclets: if signal not in self._funclets:
self._funclets[signal] = set() self._funclets[signal] = set()
self._funclets[signal].add(funclet) self._funclets[signal].add(funclet)
compiler = _StatementCompiler()
funclet = compiler(statements)
for signal in compiler.sensitivity: for signal in compiler.sensitivity:
add_funclet(signal, funclet) add_funclet(signal, funclet)
for domain, cd in fragment.domains.items(): for domain, cd in fragment.domains.items():
@ -464,7 +484,7 @@ class Simulator:
self._passive.add(process) self._passive.add(process)
elif isinstance(cmd, Value): elif isinstance(cmd, Value):
funclet = _RHSValueCompiler(sensitivity=ValueSet())(cmd) funclet = _RHSValueCompiler()(cmd)
cmd = process.send(funclet(self._state)) cmd = process.send(funclet(self._state))
continue continue