new simulator: basic execution
This commit is contained in:
parent
49ef182305
commit
10d89d81f4
|
@ -0,0 +1,162 @@
|
||||||
|
import operator
|
||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
|
from migen.fhdl.std import *
|
||||||
|
from migen.fhdl.structure import _Operator, _Assign, _Fragment
|
||||||
|
from migen.fhdl.tools import list_inputs
|
||||||
|
|
||||||
|
|
||||||
|
class ClockState:
|
||||||
|
def __init__(self, period, times_before_tick):
|
||||||
|
self.period = period
|
||||||
|
self.times_before_tick = times_before_tick
|
||||||
|
|
||||||
|
|
||||||
|
class TimeManager:
|
||||||
|
def __init__(self, description):
|
||||||
|
self.clocks = dict()
|
||||||
|
|
||||||
|
for k, v in description.items():
|
||||||
|
if not isinstance(v, tuple):
|
||||||
|
v = v, 0
|
||||||
|
self.clocks[k] = ClockState(v[0], v[0] - v[1])
|
||||||
|
|
||||||
|
def tick(self):
|
||||||
|
r = set()
|
||||||
|
dt = min(cs.times_before_tick for cs in self.clocks.values())
|
||||||
|
for k, cs in self.clocks.items():
|
||||||
|
if cs.times_before_tick == dt:
|
||||||
|
r.add(k)
|
||||||
|
cs.times_before_tick -= dt
|
||||||
|
if not cs.times_before_tick:
|
||||||
|
cs.times_before_tick += cs.period
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
|
str2op = {
|
||||||
|
"~": operator.invert,
|
||||||
|
"+": operator.add,
|
||||||
|
"-": operator.sub,
|
||||||
|
"*": operator.mul,
|
||||||
|
|
||||||
|
">>>": operator.rshift,
|
||||||
|
"<<<": operator.lshift,
|
||||||
|
|
||||||
|
"&": operator.and_,
|
||||||
|
"^": operator.xor,
|
||||||
|
"|": operator.or_,
|
||||||
|
|
||||||
|
"<": operator.lt,
|
||||||
|
"<=": operator.le,
|
||||||
|
"==": operator.eq,
|
||||||
|
"!=": operator.ne,
|
||||||
|
">": operator.gt,
|
||||||
|
">=": operator.ge,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class Evaluator:
|
||||||
|
def __init__(self):
|
||||||
|
self.signal_values = dict()
|
||||||
|
self.modifications = dict()
|
||||||
|
|
||||||
|
def commit(self):
|
||||||
|
r = set()
|
||||||
|
for k, v in self.modifications.items():
|
||||||
|
if k not in self.signal_values or self.signal_values[k] != v:
|
||||||
|
self.signal_values[k] = v
|
||||||
|
r.add(k)
|
||||||
|
self.modifications.clear()
|
||||||
|
return r
|
||||||
|
|
||||||
|
def _eval(self, node):
|
||||||
|
if isinstance(node, (int, bool)):
|
||||||
|
return node
|
||||||
|
elif isinstance(node, Signal):
|
||||||
|
try:
|
||||||
|
return self.signal_values[node]
|
||||||
|
except KeyError:
|
||||||
|
return node.reset
|
||||||
|
elif isinstance(node, _Operator):
|
||||||
|
operands = [self._eval(o) for o in node.operands]
|
||||||
|
if node.op == "-":
|
||||||
|
if len(operands) == 1:
|
||||||
|
return -operands[0]
|
||||||
|
else:
|
||||||
|
return operands[0] - operands[1]
|
||||||
|
else:
|
||||||
|
return str2op[node.op](*operands)
|
||||||
|
else:
|
||||||
|
# TODO: Cat, Slice, Array, ClockSignal, ResetSignal, Memory
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def execute(self, statements):
|
||||||
|
for s in statements:
|
||||||
|
if isinstance(s, _Assign):
|
||||||
|
value = self._eval(s.r)
|
||||||
|
if isinstance(s.l, Signal):
|
||||||
|
value = value & (2**s.l.nbits - 1)
|
||||||
|
if s.l.signed and (value & 2**(s.l.nbits - 1)):
|
||||||
|
value -= 2**s.l.nbits
|
||||||
|
self.modifications[s.l] = value
|
||||||
|
else:
|
||||||
|
# TODO: Cat, Slice, Array, ClockSignal, ResetSignal, Memory
|
||||||
|
raise NotImplementedError
|
||||||
|
elif isinstance(s, If):
|
||||||
|
if self._eval(s.cond):
|
||||||
|
self.execute(s.t)
|
||||||
|
else:
|
||||||
|
self.execute(s.f)
|
||||||
|
else:
|
||||||
|
# TODO: Case
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: instances via Iverilog/VPI
|
||||||
|
# TODO: VCD output
|
||||||
|
class Simulator:
|
||||||
|
def __init__(self, fragment_or_module, generators, clocks={"sys": 100}):
|
||||||
|
if isinstance(fragment_or_module, _Fragment):
|
||||||
|
self.fragment = fragment_or_module
|
||||||
|
else:
|
||||||
|
self.fragment = fragment_or_module.get_fragment()
|
||||||
|
if not isinstance(generators, dict):
|
||||||
|
generators = {"sys": generators}
|
||||||
|
self.generators = dict()
|
||||||
|
for k, v in generators.items():
|
||||||
|
if isinstance(v, list):
|
||||||
|
self.generators[k] = v
|
||||||
|
else:
|
||||||
|
self.generators[k] = [v]
|
||||||
|
|
||||||
|
# TODO: insert_resets
|
||||||
|
self.time = TimeManager(clocks)
|
||||||
|
self.evaluator = Evaluator()
|
||||||
|
|
||||||
|
self.comb_dependent_statements = defaultdict(list)
|
||||||
|
for statement in self.fragment.comb:
|
||||||
|
for signal in list_inputs(statement):
|
||||||
|
self.comb_dependent_statements[signal].append(statement)
|
||||||
|
|
||||||
|
def _comb_propagate(self, modified):
|
||||||
|
while modified:
|
||||||
|
for signal in modified:
|
||||||
|
self.evaluator.execute(self.comb_dependent_statements[signal])
|
||||||
|
modified = self.evaluator.commit()
|
||||||
|
|
||||||
|
def _continue_simulation(self):
|
||||||
|
# TODO: passive generators
|
||||||
|
return any(self.generators.values())
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
self.evaluator.execute(self.fragment.comb)
|
||||||
|
self._comb_propagate(self.evaluator.commit())
|
||||||
|
|
||||||
|
while True:
|
||||||
|
print(self.evaluator.signal_values)
|
||||||
|
cds = self.time.tick()
|
||||||
|
for cd in cds:
|
||||||
|
self.evaluator.execute(self.fragment.sync[cd])
|
||||||
|
self._comb_propagate(self.evaluator.commit())
|
||||||
|
if not self._continue_simulation():
|
||||||
|
break
|
Loading…
Reference in New Issue