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.
This commit is contained in:
whitequark 2020-12-12 12:42:12 +00:00
parent 4e7e0b33d5
commit 818c8bc464
2 changed files with 29 additions and 2 deletions

View file

@ -1499,13 +1499,14 @@ class Switch(Statement):
keys = (keys,)
# Map: 2 -> "0010"; "0010" -> "0010"
new_keys = ()
key_mask = (1 << len(self.test)) - 1
for key in keys:
if isinstance(key, str):
key = "".join(key.split()) # remove whitespace
elif isinstance(key, int):
key = format(key, "b").rjust(len(self.test), "0")
key = format(key & key_mask, "b").rjust(len(self.test), "0")
elif isinstance(key, Enum):
key = format(key.value, "b").rjust(len(self.test), "0")
key = format(key.value & key_mask, "b").rjust(len(self.test), "0")
else:
raise TypeError("Object {!r} cannot be used as a switch key"
.format(key))

View file

@ -1107,3 +1107,29 @@ class InitialTestCase(FHDLTestCase):
def test_initial(self):
i = Initial()
self.assertEqual(i.shape(), unsigned(1))
class SwitchTestCase(FHDLTestCase):
def test_default_case(self):
s = Switch(Const(0), {None: []})
self.assertEqual(s.cases, {(): []})
def test_int_case(self):
s = Switch(Const(0, 8), {10: []})
self.assertEqual(s.cases, {("00001010",): []})
def test_int_neg_case(self):
s = Switch(Const(0, 8), {-10: []})
self.assertEqual(s.cases, {("11110110",): []})
def test_enum_case(self):
s = Switch(Const(0, UnsignedEnum), {UnsignedEnum.FOO: []})
self.assertEqual(s.cases, {("01",): []})
def test_str_case(self):
s = Switch(Const(0, 8), {"0000 11\t01": []})
self.assertEqual(s.cases, {("00001101",): []})
def test_two_cases(self):
s = Switch(Const(0, 8), {("00001111", 123): []})
self.assertEqual(s.cases, {("00001111", "01111011"): []})