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: 73ed87030902
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: 470d66934f9b
Choose a head ref
  • 2 commits
  • 4 files changed
  • 1 contributor

Commits on Dec 27, 2018

  1. hdl.mem: add missing __all__.

    whitequark committed Dec 27, 2018
    Copy the full SHA
    de50cce View commit details
  2. hdl.dsl: add support for fsm.ongoing().

    whitequark committed Dec 27, 2018
    Copy the full SHA
    470d669 View commit details
Showing with 60 additions and 13 deletions.
  1. +6 −2 examples/fsm.py
  2. +22 −9 nmigen/hdl/dsl.py
  3. +3 −0 nmigen/hdl/mem.py
  4. +29 −2 nmigen/test/test_hdl_dsl.py
8 changes: 6 additions & 2 deletions examples/fsm.py
Original file line number Diff line number Diff line change
@@ -24,7 +24,7 @@ def get_fragment(self, platform):
m.d.sync += ctr.eq(ctr - 1)

bit = Signal(3)
with m.FSM():
with m.FSM() as fsm:
with m.State("START"):
with m.If(~self.i):
m.next = "DATA"
@@ -46,12 +46,16 @@ def get_fragment(self, platform):
m.next = "DONE"
with m.Else():
m.next = "ERROR"

with m.State("DONE"):
m.d.comb += self.rdy.eq(1)
with m.If(self.ack):
m.next = "START"

m.d.comb += self.err.eq(fsm.ongoing("ERROR"))
with m.State("ERROR"):
m.d.comb += self.err.eq(1)
pass

return m.lower(platform)


31 changes: 22 additions & 9 deletions nmigen/hdl/dsl.py
Original file line number Diff line number Diff line change
@@ -92,7 +92,16 @@ def __setattr__(self, name, domain):
self._builder._add_domain(domain)


_FSM = namedtuple("_FSM", ("state", "encoding", "decoding"))
class FSM:
def __init__(self, state, encoding, decoding):
self.state = state
self.encoding = encoding
self.decoding = decoding

def ongoing(self, name):
if name not in self.encoding:
self.encoding[name] = len(self.encoding)
return self.state == self.encoding[name]


class Module(_ModuleBuilderRoot):
@@ -221,16 +230,18 @@ def FSM(self, reset=None, domain="sync", name="fsm"):
fsm_data = self._set_ctrl("FSM", {
"name": name,
"signal": Signal(name="{}_state".format(name)),
"reset": reset,
"domain": domain,
"encoding": OrderedDict(),
"decoding": OrderedDict(),
"states": OrderedDict(),
})
if reset is not None:
fsm_data["encoding"][reset] = 0
self._generated[name] = fsm = \
FSM(fsm_data["signal"], fsm_data["encoding"], fsm_data["decoding"])
try:
self._ctrl_context = "FSM"
self.domain._depth += 1
yield
yield fsm
finally:
self.domain._depth -= 1
self._ctrl_context = None
@@ -301,17 +312,19 @@ def _pop_ctrl(self):
self._statements.append(Switch(switch_test, switch_cases))

if name == "FSM":
fsm_signal, fsm_encoding, fsm_states = data["signal"], data["encoding"], data["states"]
fsm_signal, fsm_reset, fsm_encoding, fsm_decoding, fsm_states = \
data["signal"], data["reset"], data["encoding"], data["decoding"], data["states"]
fsm_signal.nbits = bits_for(len(fsm_encoding) - 1)
if fsm_reset is None:
fsm_signal.reset = fsm_encoding[next(iter(fsm_states))]
else:
fsm_signal.reset = fsm_encoding[fsm_reset]
# The FSM is encoded such that the state with encoding 0 is always the reset state.
fsm_decoding = OrderedDict({n: s for s, n in fsm_encoding.items()})
fsm_decoding.update((n, s) for s, n in fsm_encoding.items())
fsm_signal.decoder = lambda n: "{}/{}".format(fsm_decoding[n], n)
self._statements.append(Switch(fsm_signal,
OrderedDict((fsm_encoding[name], stmts) for name, stmts in fsm_states.items())))

fsm_name = data["name"]
self._generated[fsm_name] = _FSM(fsm_signal, fsm_encoding, fsm_decoding)

def _add_statement(self, assigns, domain, depth, compat_mode=False):
def domain_name(domain):
if domain is None:
3 changes: 3 additions & 0 deletions nmigen/hdl/mem.py
Original file line number Diff line number Diff line change
@@ -5,6 +5,9 @@
from .ir import Instance


__all__ = ["Memory"]


class Memory:
def __init__(self, width, depth, init=None, name=None, simulate=True):
if not isinstance(width, int) or width < 0:
31 changes: 29 additions & 2 deletions nmigen/test/test_hdl_dsl.py
Original file line number Diff line number Diff line change
@@ -365,12 +365,39 @@ def test_FSM_reset(self):
self.assertRepr(m._statements, """
(
(switch (sig fsm_state)
(case 1
(case 0
(eq (sig a) (const 1'd0))
(eq (sig fsm_state) (const 1'd1))
)
(case 1
(eq (sig fsm_state) (const 1'd0))
)
)
)
""")

def test_FSM_ongoing(self):
a = Signal()
b = Signal()
m = Module()
with m.FSM() as fsm:
m.d.comb += b.eq(fsm.ongoing("SECOND"))
with m.State("FIRST"):
pass
m.d.comb += a.eq(fsm.ongoing("FIRST"))
with m.State("SECOND"):
pass
m._flush()
self.assertEqual(m._generated["fsm"].state.reset, 1)
self.maxDiff = 10000
self.assertRepr(m._statements, """
(
(eq (sig b) (== (sig fsm_state) (const 1'd0)))
(eq (sig a) (== (sig fsm_state) (const 1'd1)))
(switch (sig fsm_state)
(case 1
)
(case 0
(eq (sig fsm_state) (const 1'd1))
)
)
)