Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: m-labs/nmigen
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 151d079f0144
Choose a base ref
...
head repository: m-labs/nmigen
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 7d3f7f277ac1
Choose a head ref
  • 3 commits
  • 2 files changed
  • 1 contributor

Commits on Dec 14, 2018

  1. back.pysim: allow processes to evaluate expressions.

    whitequark committed Dec 14, 2018
    Copy the full SHA
    3ad79ec View commit details
  2. Copy the full SHA
    7fc9f98 View commit details
  3. back.pysim: accept (and evaluate) generator functions.

    whitequark committed Dec 14, 2018
    Copy the full SHA
    7d3f7f2 View commit details
Showing with 80 additions and 50 deletions.
  1. +74 −47 nmigen/back/pysim.py
  2. +6 −3 nmigen/fhdl/ast.py
121 changes: 74 additions & 47 deletions nmigen/back/pysim.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import math
import inspect
from vcd import VCDWriter
from vcd.gtkw import GTKWSave

@@ -223,9 +224,30 @@ def __init__(self, fragment, vcd_file=None, gtkw_file=None, gtkw_signals=()):
self._gtkw_file = gtkw_file
self._gtkw_signals = gtkw_signals

def _check_process(self, process):
if inspect.isgeneratorfunction(process):
process = process()
if not inspect.isgenerator(process):
raise TypeError("Cannot add a process '{!r}' because it is not a generator or"
"a generator function"
.format(process))
return process

def add_process(self, process):
process = self._check_process(process)
self._processes.add(process)

def add_sync_process(self, process, domain="sync"):
process = self._check_process(process)
def sync_process():
try:
result = process.send(None)
while True:
result = process.send((yield (result or Tick(domain))))
except StopIteration:
pass
self.add_process(sync_process())

def add_clock(self, period, domain="sync"):
if self._fastest_clock == self._epsilon or period < self._fastest_clock:
self._fastest_clock = period
@@ -242,16 +264,6 @@ def clk_process():
yield Delay(half_period)
self.add_process(clk_process())

def add_sync_process(self, process, domain="sync"):
def sync_process():
try:
result = process.send(None)
while True:
result = process.send((yield (result or Tick(domain))))
except StopIteration:
pass
self.add_process(sync_process())

def __enter__(self):
if self._vcd_file:
self._vcd_writer = VCDWriter(self._vcd_file, timescale="100 ps",
@@ -281,6 +293,9 @@ def add_fragment(fragment, hierarchy=("top",)):
normalize(signal.reset, signal.shape())
self._state.curr_dirty.add(signal)

if not self._vcd_writer:
continue

if signal not in self._vcd_signals:
self._vcd_signals[signal] = set()

@@ -421,46 +436,58 @@ def _commit_sync_signals(self, domains):

def _run_process(self, process):
try:
stmt = process.send(None)
cmd = process.send(None)
while True:
if isinstance(cmd, Delay):
if cmd.interval is None:
interval = self._epsilon
else:
interval = cmd.interval
self._wait_deadline[process] = self._timestamp + interval
self._suspended.add(process)

elif isinstance(cmd, Tick):
self._wait_tick[process] = cmd.domain
self._suspended.add(process)

elif isinstance(cmd, Passive):
self._passive.add(process)

elif isinstance(cmd, Value):
funclet = _RHSValueCompiler(sensitivity=ValueSet())(cmd)
cmd = process.send(funclet(self._state))
continue

elif isinstance(cmd, Assign):
lhs_signals = cmd.lhs._lhs_signals()
for signal in lhs_signals:
if not signal in self._signals:
raise ValueError("Process {!r} sent a request to set signal '{!r}', "
"which is not a part of simulation"
.format(process, signal))
if signal in self._comb_signals:
raise ValueError("Process {!r} sent a request to set signal '{!r}', "
"which is a part of combinatorial assignment in "
"simulation"
.format(process, signal))

funclet = _StatementCompiler()(cmd)
funclet(self._state)

domains = set()
for signal in lhs_signals:
self._commit_signal(signal, domains)
self._commit_sync_signals(domains)

else:
raise TypeError("Received unsupported command '{!r}' from process {!r}"
.format(cmd, process))

break

except StopIteration:
self._processes.remove(process)
self._passive.discard(process)
return

if isinstance(stmt, Delay):
self._wait_deadline[process] = self._timestamp + stmt.interval
self._suspended.add(process)

elif isinstance(stmt, Tick):
self._wait_tick[process] = stmt.domain
self._suspended.add(process)

elif isinstance(stmt, Passive):
self._passive.add(process)

elif isinstance(stmt, Assign):
lhs_signals = stmt.lhs._lhs_signals()
for signal in lhs_signals:
if not signal in self._signals:
raise ValueError("Process {!r} sent a request to set signal '{!r}', "
"which is not a part of simulation"
.format(process, signal))
if signal in self._comb_signals:
raise ValueError("Process {!r} sent a request to set signal '{!r}', "
"which is a part of combinatorial assignment in simulation"
.format(process, signal))

funclet = _StatementCompiler()(stmt)
funclet(self._state)

domains = set()
for signal in lhs_signals:
self._commit_signal(signal, domains)
self._commit_sync_signals(domains)

else:
raise TypeError("Received unsupported statement '{!r}' from process {!r}"
.format(stmt, process))

def step(self, run_passive=False):
deadline = None
9 changes: 6 additions & 3 deletions nmigen/fhdl/ast.py
Original file line number Diff line number Diff line change
@@ -702,14 +702,17 @@ def __repr__(self):


class Delay(Statement):
def __init__(self, interval):
self.interval = float(interval)
def __init__(self, interval=None):
self.interval = None if interval is None else float(interval)

def _rhs_signals(self):
return ValueSet()

def __repr__(self):
return "(delay {:.3}us)".format(self.interval * 10e6)
if self.interval is None:
return "(delay ε)"
else:
return "(delay {:.3}us)".format(self.interval * 10e6)


class Tick(Statement):