Skip to content

Commit

Permalink
hdl.dsl: accept (but warn on) cases wider than switch test value.
Browse files Browse the repository at this point in the history
  • Loading branch information
whitequark committed Jan 13, 2019
1 parent cbf7bd6 commit 3083c1d
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 3 deletions.
1 change: 1 addition & 0 deletions nmigen/hdl/ast.py
Original file line number Diff line number Diff line change
Expand Up @@ -882,6 +882,7 @@ def __init__(self, test, cases):
for key, stmts in cases.items():
if isinstance(key, (bool, int)):
key = "{:0{}b}".format(key, len(self.test))
assert len(key) <= len(self.test)
elif isinstance(key, str):
assert len(key) == len(self.test)
else:
Expand Down
16 changes: 13 additions & 3 deletions nmigen/hdl/dsl.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
from collections import OrderedDict, namedtuple
from collections.abc import Iterable
from contextlib import contextmanager
import warnings

from ..tools import flatten, bits_for
from .ast import *
from .ir import *
from .xfrm import *


__all__ = ["Module", "SyntaxError"]
__all__ = ["Module", "SyntaxError", "SyntaxWarning"]


class SyntaxError(Exception):
pass


class SyntaxWarning(Warning):
pass


class _ModuleBuilderProxy:
def __init__(self, builder, depth):
object.__setattr__(self, "_builder", builder)
Expand Down Expand Up @@ -195,7 +200,7 @@ def Else(self):
@contextmanager
def Switch(self, test):
self._check_context("Switch", context=None)
switch_data = self._set_ctrl("Switch", {"test": test, "cases": OrderedDict()})
switch_data = self._set_ctrl("Switch", {"test": Value.wrap(test), "cases": OrderedDict()})
try:
self._ctrl_context = "Switch"
self.domain._depth += 1
Expand All @@ -211,9 +216,14 @@ def Case(self, value=None):
switch_data = self._get_ctrl("Switch")
if value is None:
value = "-" * len(switch_data["test"])
if isinstance(value, str) and len(switch_data["test"]) != len(value):
if isinstance(value, str) and len(value) != len(switch_data["test"]):
raise SyntaxError("Case value '{}' must have the same width as test (which is {})"
.format(value, len(switch_data["test"])))
if isinstance(value, int) and bits_for(value) > len(switch_data["test"]):
warnings.warn("Case value '{:b}' is wider than test (which has width {}); "
"comparison will be made against truncated value"
.format(value, len(switch_data["test"])), SyntaxWarning, stacklevel=3)
value &= (1 << len(switch_data["test"])) - 1
try:
_outer_case, self._statements = self._statements, []
self._ctrl_context = None
Expand Down
12 changes: 12 additions & 0 deletions nmigen/test/test_hdl_dsl.py
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,18 @@ def test_Case_width_wrong(self):
msg="Case value '--' must have the same width as test (which is 4)"):
with m.Case("--"):
pass
with self.assertWarns(SyntaxWarning,
msg="Case value '10110' is wider than test (which has width 4); comparison "
"will be made against truncated value"):
with m.Case(0b10110):
pass
self.assertRepr(m._statements, """
(
(switch (sig w1)
(case 0110 )
)
)
""")

def test_Case_outside_Switch_wrong(self):
m = Module()
Expand Down

0 comments on commit 3083c1d

Please sign in to comment.