Skip to content

Commit 818c8bc

Browse files
committed
hdl.ast: normalize case values to two's complement, not signed binary.
This was an especially insidious bug because the minus character is valid in case values but has a completely different meaning (wildcard rather than sign). Fixes #559.
1 parent 4e7e0b3 commit 818c8bc

File tree

2 files changed

+29
-2
lines changed

2 files changed

+29
-2
lines changed

nmigen/hdl/ast.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1499,13 +1499,14 @@ def __init__(self, test, cases, *, src_loc=None, src_loc_at=0, case_src_locs={})
14991499
keys = (keys,)
15001500
# Map: 2 -> "0010"; "0010" -> "0010"
15011501
new_keys = ()
1502+
key_mask = (1 << len(self.test)) - 1
15021503
for key in keys:
15031504
if isinstance(key, str):
15041505
key = "".join(key.split()) # remove whitespace
15051506
elif isinstance(key, int):
1506-
key = format(key, "b").rjust(len(self.test), "0")
1507+
key = format(key & key_mask, "b").rjust(len(self.test), "0")
15071508
elif isinstance(key, Enum):
1508-
key = format(key.value, "b").rjust(len(self.test), "0")
1509+
key = format(key.value & key_mask, "b").rjust(len(self.test), "0")
15091510
else:
15101511
raise TypeError("Object {!r} cannot be used as a switch key"
15111512
.format(key))

tests/test_hdl_ast.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1107,3 +1107,29 @@ class InitialTestCase(FHDLTestCase):
11071107
def test_initial(self):
11081108
i = Initial()
11091109
self.assertEqual(i.shape(), unsigned(1))
1110+
1111+
1112+
class SwitchTestCase(FHDLTestCase):
1113+
def test_default_case(self):
1114+
s = Switch(Const(0), {None: []})
1115+
self.assertEqual(s.cases, {(): []})
1116+
1117+
def test_int_case(self):
1118+
s = Switch(Const(0, 8), {10: []})
1119+
self.assertEqual(s.cases, {("00001010",): []})
1120+
1121+
def test_int_neg_case(self):
1122+
s = Switch(Const(0, 8), {-10: []})
1123+
self.assertEqual(s.cases, {("11110110",): []})
1124+
1125+
def test_enum_case(self):
1126+
s = Switch(Const(0, UnsignedEnum), {UnsignedEnum.FOO: []})
1127+
self.assertEqual(s.cases, {("01",): []})
1128+
1129+
def test_str_case(self):
1130+
s = Switch(Const(0, 8), {"0000 11\t01": []})
1131+
self.assertEqual(s.cases, {("00001101",): []})
1132+
1133+
def test_two_cases(self):
1134+
s = Switch(Const(0, 8), {("00001111", 123): []})
1135+
self.assertEqual(s.cases, {("00001111", "01111011"): []})

0 commit comments

Comments
 (0)