From 10d89d81f468590bac6f1fe88901469a7dcde98d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 10 Sep 2015 20:33:45 -0700 Subject: [PATCH] new simulator: basic execution --- migen/sim.py | 162 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 162 insertions(+) create mode 100644 migen/sim.py diff --git a/migen/sim.py b/migen/sim.py new file mode 100644 index 000000000..268239651 --- /dev/null +++ b/migen/sim.py @@ -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