hdl.{ast,dsl}: add Signal.enum; coerce Enum to Value; accept Enum patterns.

Fixes #207.
This commit is contained in:
whitequark 2019-09-16 18:59:28 +00:00
parent e8f79c5539
commit 4777a7b3a2
4 changed files with 107 additions and 9 deletions

View file

@ -5,6 +5,23 @@ from ..hdl.ast import *
from .tools import *
class UnsignedEnum(Enum):
FOO = 1
BAR = 2
BAZ = 3
class SignedEnum(Enum):
FOO = -1
BAR = 0
BAZ = +1
class StringEnum(Enum):
FOO = "a"
BAR = "b"
class ValueTestCase(FHDLTestCase):
def test_wrap(self):
self.assertIsInstance(Value.wrap(0), Const)
@ -15,6 +32,19 @@ class ValueTestCase(FHDLTestCase):
msg="Object ''str'' is not an nMigen value"):
Value.wrap("str")
def test_wrap_enum(self):
e1 = Value.wrap(UnsignedEnum.FOO)
self.assertIsInstance(e1, Const)
self.assertEqual(e1.shape(), (2, False))
e2 = Value.wrap(SignedEnum.FOO)
self.assertIsInstance(e2, Const)
self.assertEqual(e2.shape(), (2, True))
def test_wrap_enum_wrong(self):
with self.assertRaises(TypeError,
msg="Only enumerations with integer values can be converted to nMigen values"):
Value.wrap(StringEnum.FOO)
def test_bool(self):
with self.assertRaises(TypeError,
msg="Attempted to convert nMigen value to boolean"):
@ -276,6 +306,12 @@ class OperatorTestCase(FHDLTestCase):
(== (& (sig s) (const 4'd12)) (const 4'd8))
""")
def test_matches_enum(self):
s = Signal.enum(SignedEnum)
self.assertRepr(s.matches(SignedEnum.FOO), """
(== (& (sig s) (const 2'd3)) (const 2'd3))
""")
def test_matches_width_wrong(self):
s = Signal(4)
with self.assertRaises(SyntaxError,
@ -295,7 +331,7 @@ class OperatorTestCase(FHDLTestCase):
def test_matches_pattern_wrong(self):
s = Signal(4)
with self.assertRaises(SyntaxError,
msg="Match pattern must be an integer or a string, not 1.0"):
msg="Match pattern must be an integer, a string, or an enumeration, not 1.0"):
s.matches(1.0)
def test_hash(self):
@ -605,6 +641,13 @@ class SignalTestCase(FHDLTestCase):
self.assertEqual(s.decoder(1), "RED/1")
self.assertEqual(s.decoder(3), "3")
def test_enum(self):
s1 = Signal.enum(UnsignedEnum)
self.assertEqual(s1.shape(), (2, False))
s2 = Signal.enum(SignedEnum)
self.assertEqual(s2.shape(), (2, True))
self.assertEqual(s2.decoder(SignedEnum.FOO), "FOO/-1")
class ClockSignalTestCase(FHDLTestCase):
def test_domain(self):

View file

@ -1,4 +1,5 @@
from collections import OrderedDict
from enum import Enum
from ..hdl.ast import *
from ..hdl.cd import *
@ -355,6 +356,23 @@ class DSLTestCase(FHDLTestCase):
)
""")
def test_Switch_enum(self):
class Color(Enum):
RED = 1
BLUE = 2
m = Module()
se = Signal.enum(Color)
with m.Switch(se):
with m.Case(Color.RED):
m.d.comb += self.c1.eq(1)
self.assertRepr(m._statements, """
(
(switch (sig se)
(case 01 (eq (sig c1) (const 1'd1)))
)
)
""")
def test_Case_width_wrong(self):
m = Module()
with m.Switch(self.w1):
@ -385,7 +403,7 @@ class DSLTestCase(FHDLTestCase):
m = Module()
with m.Switch(self.w1):
with self.assertRaises(SyntaxError,
msg="Case pattern must be an integer or a string, not 1.0"):
msg="Case pattern must be an integer, a string, or an enumeration, not 1.0"):
with m.Case(1.0):
pass