def __init__(self, fragment_or_module, generators, clocks={"sys": 10}, vcd_name=None, special_overrides={}): if isinstance(fragment_or_module, _Fragment): self.fragment = fragment_or_module else: self.fragment = fragment_or_module.get_fragment() mta = MemoryToArray() mta.transform_fragment(None, self.fragment) overrides = {AsyncResetSynchronizer: DummyAsyncResetSynchronizer} overrides.update(special_overrides) fs, lowered = lower_specials(overrides=overrides, specials=self.fragment.specials) self.fragment += fs self.fragment.specials -= lowered if self.fragment.specials: raise ValueError("Could not lower all specials", self.fragment.specials) if not isinstance(generators, dict): generators = {"sys": generators} self.generators = dict() self.passive_generators = set() for k, v in generators.items(): if (isinstance(v, collections.Iterable) and not inspect.isgenerator(v)): self.generators[k] = list(v) else: self.generators[k] = [v] clocks = collections.OrderedDict(sorted(clocks.items(), key=operator.itemgetter(0))) self.time = TimeManager(clocks) for clock in clocks.keys(): if clock not in self.fragment.clock_domains: cd = ClockDomain(name=clock, reset_less=True) cd.clk.reset = C(self.time.clocks[clock].high) self.fragment.clock_domains.append(cd) insert_resets(self.fragment) # comb signals return to their reset value if nothing assigns them self.fragment.comb[0:0] = [s.eq(s.reset) for s in list_targets(self.fragment.comb)] self.evaluator = Evaluator(self.fragment.clock_domains, mta.replacements) if vcd_name is None: self.vcd = DummyVCDWriter() else: self.vcd = VCDWriter(vcd_name) signals = list_signals(self.fragment) for cd in self.fragment.clock_domains: signals.add(cd.clk) if cd.rst is not None: signals.add(cd.rst) for memory_array in mta.replacements.values(): signals |= set(memory_array) self.vcd.init(signals) for signal in sorted(signals, key=lambda x: x.duid): self.vcd.set(signal, signal.reset.value)
def __init__(self, fragment_or_module, generators, clocks={"sys": 10}, vcd_name=None, special_overrides={}): if isinstance(fragment_or_module, _Fragment): self.fragment = fragment_or_module else: self.fragment = fragment_or_module.get_fragment() mta = MemoryToArray() mta.transform_fragment(None, self.fragment) overrides = {AsyncResetSynchronizer: DummyAsyncResetSynchronizer} overrides.update(special_overrides) f, lowered = lower_specials(overrides, self.fragment) if self.fragment.specials: raise ValueError("Could not lower all specials", self.fragment.specials) if not isinstance(generators, dict): generators = {"sys": generators} self.generators = dict() self.passive_generators = set() for k, v in generators.items(): if (isinstance(v, collections.Iterable) and not inspect.isgenerator(v)): self.generators[k] = list(v) else: self.generators[k] = [v] clocks = collections.OrderedDict(sorted(clocks.items(), key=operator.itemgetter(0))) self.time = TimeManager(clocks) for clock in clocks.keys(): if clock not in self.fragment.clock_domains: cd = ClockDomain(name=clock, reset_less=True) cd.clk.reset = C(self.time.clocks[clock].high) self.fragment.clock_domains.append(cd) insert_resets(self.fragment) # comb signals return to their reset value if nothing assigns them self.fragment.comb[0:0] = [s.eq(s.reset) for s in list_targets(self.fragment.comb)] self.evaluator = Evaluator(self.fragment.clock_domains, mta.replacements) if vcd_name is None: self.vcd = DummyVCDWriter() else: self.vcd = VCDWriter(vcd_name) signals = list_signals(self.fragment) for cd in self.fragment.clock_domains: signals.add(cd.clk) if cd.rst is not None: signals.add(cd.rst) for memory_array in mta.replacements.values(): signals |= set(memory_array) self.vcd.init(signals) for signal in sorted(signals, key=lambda x: x.duid): self.vcd.set(signal, signal.reset.value)
class Simulator: def __init__(self, fragment_or_module, generators, clocks={"sys": 10}, vcd_name=None, special_overrides={}): if isinstance(fragment_or_module, _Fragment): self.fragment = fragment_or_module else: self.fragment = fragment_or_module.get_fragment() mta = MemoryToArray() mta.transform_fragment(None, self.fragment) overrides = {AsyncResetSynchronizer: DummyAsyncResetSynchronizer} overrides.update(special_overrides) fs, lowered = lower_specials(overrides=overrides, specials=self.fragment.specials) self.fragment += fs self.fragment.specials -= lowered if self.fragment.specials: raise ValueError("Could not lower all specials", self.fragment.specials) if not isinstance(generators, dict): generators = {"sys": generators} self.generators = dict() self.passive_generators = set() for k, v in generators.items(): if (isinstance(v, collections.Iterable) and not inspect.isgenerator(v)): self.generators[k] = list(v) else: self.generators[k] = [v] clocks = collections.OrderedDict(sorted(clocks.items(), key=operator.itemgetter(0))) self.time = TimeManager(clocks) for clock in clocks.keys(): if clock not in self.fragment.clock_domains: cd = ClockDomain(name=clock, reset_less=True) cd.clk.reset = C(self.time.clocks[clock].high) self.fragment.clock_domains.append(cd) insert_resets(self.fragment) # comb signals return to their reset value if nothing assigns them self.fragment.comb[0:0] = [s.eq(s.reset) for s in list_targets(self.fragment.comb)] self.evaluator = Evaluator(self.fragment.clock_domains, mta.replacements) if vcd_name is None: self.vcd = DummyVCDWriter() else: self.vcd = VCDWriter(vcd_name) signals = list_signals(self.fragment) for cd in self.fragment.clock_domains: signals.add(cd.clk) if cd.rst is not None: signals.add(cd.rst) for memory_array in mta.replacements.values(): signals |= set(memory_array) self.vcd.init(signals) for signal in sorted(signals, key=lambda x: x.duid): self.vcd.set(signal, signal.reset.value) def __enter__(self): return self def __exit__(self, type, value, traceback): self.close() def close(self): self.vcd.close() def _commit_and_comb_propagate(self): # TODO: optimize all_modified = set() modified = self.evaluator.commit() all_modified |= modified while modified: self.evaluator.execute(self.fragment.comb) modified = self.evaluator.commit() all_modified |= modified for signal in all_modified: self.vcd.set(signal, self.evaluator.signal_values[signal]) def _evalexec_nested_lists(self, x): if isinstance(x, list): return [self._evalexec_nested_lists(e) for e in x] elif isinstance(x, _Value): return self.evaluator.eval(x) elif isinstance(x, _Statement): self.evaluator.execute([x]) return None else: raise ValueError def _process_generators(self, cd): exhausted = [] for generator in self.generators[cd]: reply = None while True: try: request = generator.send(reply) if request is None: break # next cycle elif isinstance(request, str): if request == "passive": self.passive_generators.add(generator) elif request == "active": self.passive_generators.discard(generator) else: raise ValueError("Unknown simulator command: '{}'" .format(request)) else: reply = self._evalexec_nested_lists(request) except StopIteration: exhausted.append(generator) break for generator in exhausted: self.generators[cd].remove(generator) def _continue_simulation(self): for cd_generators in self.generators.values(): if set(cd_generators) - self.passive_generators: return True return False def run(self): self.evaluator.execute(self.fragment.comb) self._commit_and_comb_propagate() while True: dt, rising, falling = self.time.tick() self.vcd.delay(dt) for cd in rising: self.evaluator.assign(self.fragment.clock_domains[cd].clk, 1) if cd in self.fragment.sync: self.evaluator.execute(self.fragment.sync[cd]) if cd in self.generators: self._process_generators(cd) for cd in falling: self.evaluator.assign(self.fragment.clock_domains[cd].clk, 0) self._commit_and_comb_propagate() if not self._continue_simulation(): break
class Simulator: def __init__(self, fragment_or_module, generators, clocks={"sys": 10}, vcd_name=None): if isinstance(fragment_or_module, _Fragment): self.fragment = fragment_or_module else: self.fragment = fragment_or_module.get_fragment() mta = MemoryToArray() mta.transform_fragment(None, self.fragment) fs, lowered = lower_specials(overrides={}, specials=self.fragment.specials) self.fragment += fs self.fragment.specials -= lowered # FIXME: Remaining replaced ports workaround remaining_memory_ports = set() for s in self.fragment.specials: if isinstance(s, _MemoryPort): remaining_memory_ports.add(s) self.fragment.specials -= remaining_memory_ports # FIXME: Remaining replaced ports workaround if self.fragment.specials: raise ValueError("Could not lower all specials", self.fragment.specials) if not isinstance(generators, dict): generators = {"sys": generators} self.generators = dict() self.passive_generators = set() for k, v in generators.items(): if (isinstance(v, collections.Iterable) and not inspect.isgenerator(v)): self.generators[k] = list(v) else: self.generators[k] = [v] clocks = collections.OrderedDict(sorted(clocks.items(), key=operator.itemgetter(0))) self.time = TimeManager(clocks) for clock in clocks.keys(): if clock not in self.fragment.clock_domains: cd = ClockDomain(name=clock, reset_less=True) cd.clk.reset = C(self.time.clocks[clock].high) self.fragment.clock_domains.append(cd) insert_resets(self.fragment) # comb signals return to their reset value if nothing assigns them self.fragment.comb[0:0] = [s.eq(s.reset) for s in list_targets(self.fragment.comb)] self.evaluator = Evaluator(self.fragment.clock_domains, mta.replacements) if vcd_name is None: self.vcd = DummyVCDWriter() else: self.vcd = VCDWriter(vcd_name) signals = list_signals(self.fragment) for cd in self.fragment.clock_domains: signals.add(cd.clk) if cd.rst is not None: signals.add(cd.rst) for memory_array in mta.replacements.values(): signals |= set(memory_array) self.vcd.init(signals) for signal in sorted(signals, key=lambda x: x.duid): self.vcd.set(signal, signal.reset.value) def __enter__(self): return self def __exit__(self, type, value, traceback): self.close() def close(self): self.vcd.close() def _commit_and_comb_propagate(self): # TODO: optimize all_modified = set() modified = self.evaluator.commit() all_modified |= modified while modified: self.evaluator.execute(self.fragment.comb) modified = self.evaluator.commit() all_modified |= modified for signal in all_modified: self.vcd.set(signal, self.evaluator.signal_values[signal]) def _evalexec_nested_lists(self, x): if isinstance(x, list): return [self._evalexec_nested_lists(e) for e in x] elif isinstance(x, _Value): return self.evaluator.eval(x) elif isinstance(x, _Statement): self.evaluator.execute([x]) return None else: raise ValueError def _process_generators(self, cd): exhausted = [] for generator in self.generators[cd]: reply = None while True: try: request = generator.send(reply) if request is None: break # next cycle elif isinstance(request, str): if request == "passive": self.passive_generators.add(generator) elif request == "active": self.passive_generators.discard(generator) else: raise ValueError("Unknown simulator command: '{}'" .format(request)) else: reply = self._evalexec_nested_lists(request) except StopIteration: exhausted.append(generator) break for generator in exhausted: self.generators[cd].remove(generator) def _continue_simulation(self): for cd_generators in self.generators.values(): if set(cd_generators) - self.passive_generators: return True return False def run(self): self.evaluator.execute(self.fragment.comb) self._commit_and_comb_propagate() while True: dt, rising, falling = self.time.tick() self.vcd.delay(dt) for cd in rising: self.evaluator.assign(self.fragment.clock_domains[cd].clk, 1) if cd in self.fragment.sync: self.evaluator.execute(self.fragment.sync[cd]) if cd in self.generators: self._process_generators(cd) for cd in falling: self.evaluator.assign(self.fragment.clock_domains[cd].clk, 0) self._commit_and_comb_propagate() if not self._continue_simulation(): break