From 1d8f875b47a7b54abc2ee186391a2a0ad51ceb23 Mon Sep 17 00:00:00 2001 From: whitequark Date: Sat, 12 Dec 2020 12:42:12 +0000 Subject: [PATCH] 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. --- nmigen/hdl/ast.py | 5 +++-- tests/test_hdl_ast.py | 26 ++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/nmigen/hdl/ast.py b/nmigen/hdl/ast.py index 165e67d..5cdbf6e 100644 --- a/nmigen/hdl/ast.py +++ b/nmigen/hdl/ast.py @@ -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)) diff --git a/tests/test_hdl_ast.py b/tests/test_hdl_ast.py index 8565fad..af073a9 100644 --- a/tests/test_hdl_ast.py +++ b/tests/test_hdl_ast.py @@ -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"): []}) -- 2.30.2