Before this commit, doing something like:
with m.FSM():
with m.State("FOO"):
m.next = "bAR"
with m.State("BAR"):
m.next = "FOO"
would silently create an empty state `bAR` and get stuck in it until
the module is reset. This was done intentionally (in Migen, this code
would in fact miscompile), but in retrospect was clearly a bad idea;
it turns typos into bugs, while in the rare case that branching to
a completely empty state is desired, it is trivial to define one.
Fixes #315.
self._ctrl_context = "FSM"
self.domain._depth += 1
yield fsm
+ for state_name in fsm_data["encoding"]:
+ if state_name not in fsm_data["states"]:
+ raise NameError("FSM state '{}' is referenced but not defined"
+ .format(state_name))
finally:
self.domain._depth -= 1
self._ctrl_context = None
src_loc = tracer.get_src_loc(src_loc_at=1)
fsm_data = self._get_ctrl("FSM")
if name in fsm_data["states"]:
- raise SyntaxError("FSM state '{}' is already defined".format(name))
+ raise NameError("FSM state '{}' is already defined".format(name))
if name not in fsm_data["encoding"]:
fsm_data["encoding"][name] = len(fsm_data["encoding"])
try:
with m.FSM(domain="comb"):
pass
+ def test_FSM_wrong_undefined(self):
+ m = Module()
+ with self.assertRaises(NameError,
+ msg="FSM state 'FOO' is referenced but not defined"):
+ with m.FSM() as fsm:
+ fsm.ongoing("FOO")
+
def test_FSM_wrong_redefined(self):
m = Module()
with m.FSM():
with m.State("FOO"):
pass
- with self.assertRaises(SyntaxError,
+ with self.assertRaises(NameError,
msg="FSM state 'FOO' is already defined"):
with m.State("FOO"):
pass