Commit c285c129 authored by whitequark's avatar whitequark
Browse files

genlib/fsm: allow subclassing FSM and overriding control functionality.

This is be useful for writing "generalized FSMs", for example:

  * an FSM that is expanded at build time into a pipeline, to switch
    through more than one state per cycle;
  * an FSM specialized for making parsers that work over an arbitrary
    datapath width.
parent dd78f381
...@@ -86,6 +86,7 @@ class _LowerNext(NodeTransformer): ...@@ -86,6 +86,7 @@ class _LowerNext(NodeTransformer):
else: else:
return node return node
class FSM(Module): class FSM(Module):
""" """
Finite state machine Finite state machine
...@@ -216,16 +217,6 @@ class FSM(Module): ...@@ -216,16 +217,6 @@ class FSM(Module):
self.next_state = Signal(max=nstates) self.next_state = Signal(max=nstates)
self.next_state._enumeration = {n: "{}:{}".format(n, s) for n, s in self.decoding.items()} self.next_state._enumeration = {n: "{}:{}".format(n, s) for n, s in self.decoding.items()}
ln = _LowerNext(self.next_state, self.encoding, self.state_aliases)
cases = dict((self.encoding[k], ln.visit(v)) for k, v in self.actions.items() if v)
self.comb += [
self.next_state.eq(self.state),
Case(self.state, cases).makedefault(self.encoding[self.reset_state])
]
self.sync += self.state.eq(self.next_state)
for register, next_value_ce, next_value in ln.registers:
self.sync += If(next_value_ce, register.eq(next_value))
# drive entering/leaving signals # drive entering/leaving signals
for state, signal in self.before_leaving_signals.items(): for state, signal in self.before_leaving_signals.items():
encoded = self.encoding[state] encoded = self.encoding[state]
...@@ -235,3 +226,19 @@ class FSM(Module): ...@@ -235,3 +226,19 @@ class FSM(Module):
for state, signal in self.before_entering_signals.items(): for state, signal in self.before_entering_signals.items():
encoded = self.encoding[state] encoded = self.encoding[state]
self.comb += signal.eq(~(self.state == encoded) & (self.next_state == encoded)) self.comb += signal.eq(~(self.state == encoded) & (self.next_state == encoded))
# Allow overriding and extending control functionality (Next*) in subclasses.
self._finalize_sync(self._lower_controls())
def _lower_controls(self):
return _LowerNext(self.next_state, self.encoding, self.state_aliases)
def _finalize_sync(self, ls):
cases = dict((self.encoding[k], ls.visit(v)) for k, v in self.actions.items() if v)
self.comb += [
self.next_state.eq(self.state),
Case(self.state, cases).makedefault(self.encoding[self.reset_state])
]
self.sync += self.state.eq(self.next_state)
for register, next_value_ce, next_value in ls.registers:
self.sync += If(next_value_ce, register.eq(next_value))
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment