hdl.{ast,dsl}: add Signal.enum; coerce Enum to Value; accept Enum patterns.
Fixes #207.
This commit is contained in:
parent
e8f79c5539
commit
4777a7b3a2
4 changed files with 107 additions and 9 deletions
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue