hdl.dsl: accept (but warn on) cases wider than switch test value.

Fixes #13.
This commit is contained in:
whitequark 2019-01-13 08:46:28 +00:00
parent cbf7bd6e31
commit 3083c1d6dd
3 changed files with 26 additions and 3 deletions

View file

@ -882,6 +882,7 @@ class Switch(Statement):
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:

View file

@ -1,6 +1,7 @@
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 *
@ -8,13 +9,17 @@ 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)
@ -195,7 +200,7 @@ class Module(_ModuleBuilderRoot):
@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
@ -211,9 +216,14 @@ class Module(_ModuleBuilderRoot):
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

View file

@ -287,6 +287,18 @@ class DSLTestCase(FHDLTestCase):
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()