hdl.ast: deprecate Signal.{range,enum}.
authorwhitequark <whitequark@whitequark.org>
Fri, 11 Oct 2019 13:07:42 +0000 (13:07 +0000)
committerwhitequark <whitequark@whitequark.org>
Fri, 11 Oct 2019 13:07:42 +0000 (13:07 +0000)
Although constructor methods can improve clarity, there are many
contexts in which it is useful to use range() as a shape: notably
Layout, but also Const and AnyConst/AnyValue. Instead of duplicating
these constructor methods everywhere (which is not even easily
possible for Layout), use casting to Shape, introduced in 6aabdc0a.

Fixes #225.

examples/basic/fsm.py
examples/basic/por.py
examples/basic/uart.py
nmigen/hdl/ast.py
nmigen/hdl/mem.py
nmigen/lib/coding.py
nmigen/lib/fifo.py
nmigen/test/test_hdl_ast.py
nmigen/test/test_hdl_dsl.py
nmigen/test/test_lib_fifo.py

index 86b00dbe5a906dd6682647fedc86fb4151faf929..712718b18c282b9b761dff02ea0fc78a6ed1e6b0 100644 (file)
@@ -15,7 +15,7 @@ class UARTReceiver(Elaboratable):
     def elaborate(self, platform):
         m = Module()
 
-        ctr = Signal.range(self.divisor)
+        ctr = Signal(range(self.divisor))
         stb = Signal()
         with m.If(ctr == 0):
             m.d.sync += ctr.eq(self.divisor - 1)
index b503e4d9cb214907304de7e3f0eb00f1b227e2d3..8bdc020104ad7b217fcc716c9c5487bd2411b5d0 100644 (file)
@@ -7,7 +7,7 @@ cd_por  = ClockDomain(reset_less=True)
 cd_sync = ClockDomain()
 m.domains += cd_por, cd_sync
 
-delay = Signal.range(256, reset=255)
+delay = Signal(range(256), reset=255)
 with m.If(delay != 0):
     m.d.por += delay.eq(delay - 1)
 m.d.comb += [
index d7a9a9ceac531c465a118fe8c6d6075068ab658b..1279ae0f1cc4ceb8972029198c836e383f9279dd 100644 (file)
@@ -31,9 +31,9 @@ class UART(Elaboratable):
     def elaborate(self, platform):
         m = Module()
 
-        tx_phase = Signal.range(self.divisor)
+        tx_phase = Signal(range(self.divisor))
         tx_shreg = Signal(1 + self.data_bits + 1, reset=-1)
-        tx_count = Signal.range(len(tx_shreg) + 1)
+        tx_count = Signal(range(len(tx_shreg) + 1))
 
         m.d.comb += self.tx_o.eq(tx_shreg[0])
         with m.If(tx_count == 0):
@@ -54,9 +54,9 @@ class UART(Elaboratable):
                     tx_phase.eq(self.divisor - 1),
                 ]
 
-        rx_phase = Signal.range(self.divisor)
+        rx_phase = Signal(range(self.divisor))
         rx_shreg = Signal(1 + self.data_bits + 1, reset=-1)
-        rx_count = Signal.range(len(rx_shreg) + 1)
+        rx_count = Signal(range(len(rx_shreg) + 1))
 
         m.d.comb += self.rx_data.eq(rx_shreg[1:-1])
         with m.If(rx_count == 0):
index db4c24ea5e02f6271a52d89cc13d773ccc3a1f9b..5aba1567bb07e465f4094d9b671e21787de2ca0e 100644 (file)
@@ -35,7 +35,20 @@ class DUID:
 class Shape(typing.NamedTuple):
     """Bit width and signedness of a value.
 
-    Attributes
+    A ``Shape`` can be constructed using:
+      * explicit bit width and signedness;
+      * aliases :func:`signed` and :func:`unsigned`;
+      * casting from a variety of objects.
+
+    A ``Shape`` can be cast from:
+      * an integer, where the integer specifies the bit width;
+      * a range, where the result is wide enough to represent any element of the range, and is
+        signed if any element of the range is signed;
+      * an :class:`Enum` with all integer members or :class:`IntEnum`, where the result is wide
+        enough to represent any member of the enumeration, and is signed if any member of
+        the enumeration is signed.
+
+    Parameters
     ----------
     width : int
         The number of bits in the representation, including the sign bit (if any).
@@ -79,10 +92,12 @@ Shape.__init__ = _Shape___init__
 
 
 def unsigned(width):
+    """Shorthand for ``Shape(width, signed=False)``."""
     return Shape(width, signed=False)
 
 
 def signed(width):
+    """Shorthand for ``Shape(width, signed=True)``."""
     return Shape(width, signed=True)
 
 
@@ -806,7 +821,7 @@ class Signal(Value, DUID):
         # TODO(nmigen-0.2): move this to nmigen.compat and make it a deprecated extension
         if min is not None or max is not None:
             warnings.warn("instead of `Signal(min={min}, max={max})`, "
-                          "use `Signal.range({min}, {max})`"
+                          "use `Signal(range({min}, {max}))`"
                           .format(min=min or 0, max=max or 2),
                           DeprecationWarning, stacklevel=2 + src_loc_at)
 
@@ -846,6 +861,9 @@ class Signal(Value, DUID):
         self.reset_less = bool(reset_less)
 
         self.attrs = OrderedDict(() if attrs is None else attrs)
+
+        if decoder is None and isinstance(shape, type) and issubclass(shape, Enum):
+            decoder = shape
         if isinstance(decoder, type) and issubclass(decoder, Enum):
             def enum_decoder(value):
                 try:
@@ -857,27 +875,16 @@ class Signal(Value, DUID):
             self.decoder = decoder
 
     @classmethod
+    @deprecated("instead of `Signal.range(...)`, use `Signal(range(...))`")
     def range(cls, *args, src_loc_at=0, **kwargs):
-        """Create Signal that can represent a given range.
-
-        The parameters to ``Signal.range`` are the same as for the built-in ``range`` function.
-        That is, for any given ``range(*args)``, ``Signal.range(*args)`` can represent any
-        ``x for x in range(*args)``.
-        """
-        return cls(Shape.cast(range(*args)), src_loc_at=1 + src_loc_at, **kwargs)
+        return cls(range(*args), src_loc_at=2 + src_loc_at, **kwargs)
 
     @classmethod
+    @deprecated("instead of `Signal.enum(...)`, use `Signal(...)`")
     def enum(cls, enum_type, *, src_loc_at=0, **kwargs):
-        """Create Signal that can represent a given enumeration.
-
-        Parameters
-        ----------
-        enum : type (inheriting from :class:`enum.Enum`)
-            Enumeration to base this Signal on.
-        """
         if not issubclass(enum_type, Enum):
             raise TypeError("Type {!r} is not an enumeration")
-        return cls(Shape.cast(enum_type), src_loc_at=1 + src_loc_at, decoder=enum_type, **kwargs)
+        return cls(enum_type, src_loc_at=2 + src_loc_at, **kwargs)
 
     @classmethod
     def like(cls, other, *, name=None, name_suffix=None, src_loc_at=0, **kwargs):
index 1101dab1e5bc4a04b13f9d15097e69bc9e3dd236..1205fa1045b560a51e115f9ce7b785f688f4e8fb 100644 (file)
@@ -73,7 +73,7 @@ class ReadPort(Elaboratable):
         self.domain      = domain
         self.transparent = transparent
 
-        self.addr = Signal.range(memory.depth,
+        self.addr = Signal(range(memory.depth),
                            name="{}_r_addr".format(memory.name), src_loc_at=2)
         self.data = Signal(memory.width,
                            name="{}_r_data".format(memory.name), src_loc_at=2)
@@ -149,7 +149,7 @@ class WritePort(Elaboratable):
         self.domain       = domain
         self.granularity  = granularity
 
-        self.addr = Signal.range(memory.depth,
+        self.addr = Signal(range(memory.depth),
                            name="{}_w_addr".format(memory.name), src_loc_at=2)
         self.data = Signal(memory.width,
                            name="{}_w_data".format(memory.name), src_loc_at=2)
index 300a718ac26d224947457705ff29e3ca55463bbe..5abfbd71351308df1636f58c2f4c774c04965cab 100644 (file)
@@ -25,7 +25,7 @@ class Encoder(Elaboratable):
     ----------
     i : Signal(width), in
         One-hot input.
-    o : Signal.range(width), out
+    o : Signal(range(width)), out
         Encoded binary.
     n : Signal, out
         Invalid: either none or multiple input bits are asserted.
@@ -34,7 +34,7 @@ class Encoder(Elaboratable):
         self.width = width
 
         self.i = Signal(width)
-        self.o = Signal.range(width)
+        self.o = Signal(range(width))
         self.n = Signal()
 
     def elaborate(self, platform):
@@ -64,7 +64,7 @@ class PriorityEncoder(Elaboratable):
     ----------
     i : Signal(width), in
         Input requests.
-    o : Signal.range(width), out
+    o : Signal(range(width)), out
         Encoded binary.
     n : Signal, out
         Invalid: no input bits are asserted.
@@ -73,7 +73,7 @@ class PriorityEncoder(Elaboratable):
         self.width = width
 
         self.i = Signal(width)
-        self.o = Signal.range(width)
+        self.o = Signal(range(width))
         self.n = Signal()
 
     def elaborate(self, platform):
@@ -98,7 +98,7 @@ class Decoder(Elaboratable):
 
     Attributes
     ----------
-    i : Signal.range(width), in
+    i : Signal(range(width)), in
         Input binary.
     o : Signal(width), out
         Decoded one-hot.
@@ -108,7 +108,7 @@ class Decoder(Elaboratable):
     def __init__(self, width):
         self.width = width
 
-        self.i = Signal.range(width)
+        self.i = Signal(range(width))
         self.n = Signal()
         self.o = Signal(width)
 
index da468b06cbd42740da469bdcb90a712856e47e31..2b3d3a6b1383703bec14ef6534e533b006073229 100644 (file)
@@ -187,7 +187,7 @@ class SyncFIFO(Elaboratable, FIFOInterface):
     def __init__(self, *, width, depth, fwft=True):
         super().__init__(width=width, depth=depth, fwft=fwft)
 
-        self.level = Signal.range(depth + 1)
+        self.level = Signal(range(depth + 1))
 
     def elaborate(self, platform):
         m = Module()
@@ -210,8 +210,8 @@ class SyncFIFO(Elaboratable, FIFOInterface):
         w_port  = m.submodules.w_port = storage.write_port()
         r_port  = m.submodules.r_port = storage.read_port(
             domain="comb" if self.fwft else "sync", transparent=self.fwft)
-        produce = Signal.range(self.depth)
-        consume = Signal.range(self.depth)
+        produce = Signal(range(self.depth))
+        consume = Signal(range(self.depth))
 
         m.d.comb += [
             w_port.addr.eq(produce),
@@ -289,7 +289,7 @@ class SyncFIFOBuffered(Elaboratable, FIFOInterface):
     def __init__(self, *, width, depth):
         super().__init__(width=width, depth=depth, fwft=True)
 
-        self.level = Signal.range(depth + 1)
+        self.level = Signal(range(depth + 1))
 
     def elaborate(self, platform):
         m = Module()
index 9022ec0942b66eafcf9316f6d86ec272974299c6..0346478543819db1d742851050cb586f25872407 100644 (file)
@@ -445,7 +445,7 @@ class OperatorTestCase(FHDLTestCase):
         """)
 
     def test_matches_enum(self):
-        s = Signal.enum(SignedEnum)
+        s = Signal(SignedEnum)
         self.assertRepr(s.matches(SignedEnum.FOO), """
         (== (sig s) (const 1'sd-1))
         """)
@@ -520,7 +520,7 @@ class SliceTestCase(FHDLTestCase):
 class BitSelectTestCase(FHDLTestCase):
     def setUp(self):
         self.c = Const(0, 8)
-        self.s = Signal.range(self.c.width)
+        self.s = Signal(range(self.c.width))
 
     def test_shape(self):
         s1 = self.c.bit_select(self.s, 2)
@@ -545,7 +545,7 @@ class BitSelectTestCase(FHDLTestCase):
 class WordSelectTestCase(FHDLTestCase):
     def setUp(self):
         self.c = Const(0, 8)
-        self.s = Signal.range(self.c.width)
+        self.s = Signal(range(self.c.width))
 
     def test_shape(self):
         s1 = self.c.word_select(self.s, 2)
@@ -617,8 +617,8 @@ class ArrayTestCase(FHDLTestCase):
 
     def test_becomes_immutable(self):
         a = Array([1,2,3])
-        s1 = Signal.range(len(a))
-        s2 = Signal.range(len(a))
+        s1 = Signal(range(len(a)))
+        s2 = Signal(range(len(a)))
         v1 = a[s1]
         v2 = a[s2]
         with self.assertRaisesRegex(ValueError,
@@ -634,7 +634,7 @@ class ArrayTestCase(FHDLTestCase):
     def test_repr(self):
         a = Array([1,2,3])
         self.assertEqual(repr(a), "(array mutable [1, 2, 3])")
-        s = Signal.range(len(a))
+        s = Signal(range(len(a)))
         v = a[s]
         self.assertEqual(repr(a), "(array [1, 2, 3])")
 
@@ -642,8 +642,8 @@ class ArrayTestCase(FHDLTestCase):
 class ArrayProxyTestCase(FHDLTestCase):
     def test_index_shape(self):
         m = Array(Array(x * y for y in range(1, 4)) for x in range(1, 4))
-        a = Signal.range(3)
-        b = Signal.range(3)
+        a = Signal(range(3))
+        b = Signal(range(3))
         v = m[a][b]
         self.assertEqual(v.shape(), (4, False))
 
@@ -651,14 +651,14 @@ class ArrayProxyTestCase(FHDLTestCase):
         from collections import namedtuple
         pair = namedtuple("pair", ("p", "n"))
         a = Array(pair(i, -i) for i in range(10))
-        s = Signal.range(len(a))
+        s = Signal(range(len(a)))
         v = a[s]
         self.assertEqual(v.p.shape(), (4, False))
         self.assertEqual(v.n.shape(), (6, True))
 
     def test_repr(self):
         a = Array([1, 2, 3])
-        s = Signal.range(3)
+        s = Signal(range(3))
         v = a[s]
         self.assertEqual(repr(v), "(proxy (array [1, 2, 3]) (sig s))")
 
@@ -676,17 +676,17 @@ class SignalTestCase(FHDLTestCase):
         self.assertEqual(s4.shape(), (2, True))
         s5 = Signal(0)
         self.assertEqual(s5.shape(), (0, False))
-        s6 = Signal.range(16)
+        s6 = Signal(range(16))
         self.assertEqual(s6.shape(), (4, False))
-        s7 = Signal.range(4, 16)
+        s7 = Signal(range(4, 16))
         self.assertEqual(s7.shape(), (4, False))
-        s8 = Signal.range(-4, 16)
+        s8 = Signal(range(-4, 16))
         self.assertEqual(s8.shape(), (5, True))
-        s9 = Signal.range(-20, 16)
+        s9 = Signal(range(-20, 16))
         self.assertEqual(s9.shape(), (6, True))
-        s10 = Signal.range(0)
+        s10 = Signal(range(0))
         self.assertEqual(s10.shape(), (0, False))
-        s11 = Signal.range(1)
+        s11 = Signal(range(1))
         self.assertEqual(s11.shape(), (1, False))
         # deprecated
         with warnings.catch_warnings():
@@ -709,7 +709,7 @@ class SignalTestCase(FHDLTestCase):
 
     def test_min_max_deprecated(self):
         with self.assertWarns(DeprecationWarning,
-                msg="instead of `Signal(min=0, max=10)`, use `Signal.range(0, 10)`"):
+                msg="instead of `Signal(min=0, max=10)`, use `Signal(range(0, 10))`"):
             Signal(max=10)
         with warnings.catch_warnings():
             warnings.filterwarnings(action="ignore", category=DeprecationWarning)
@@ -755,7 +755,7 @@ class SignalTestCase(FHDLTestCase):
     def test_like(self):
         s1 = Signal.like(Signal(4))
         self.assertEqual(s1.shape(), (4, False))
-        s2 = Signal.like(Signal.range(-15, 1))
+        s2 = Signal.like(Signal(range(-15, 1)))
         self.assertEqual(s2.shape(), (5, True))
         s3 = Signal.like(Signal(4, reset=0b111, reset_less=True))
         self.assertEqual(s3.reset, 0b111)
@@ -780,9 +780,9 @@ class SignalTestCase(FHDLTestCase):
         self.assertEqual(s.decoder(3), "3")
 
     def test_enum(self):
-        s1 = Signal.enum(UnsignedEnum)
+        s1 = Signal(UnsignedEnum)
         self.assertEqual(s1.shape(), (2, False))
-        s2 = Signal.enum(SignedEnum)
+        s2 = Signal(SignedEnum)
         self.assertEqual(s2.shape(), (2, True))
         self.assertEqual(s2.decoder(SignedEnum.FOO), "FOO/-1")
 
index e45a753cb5fc068e549e382f8864a71e3190e7ca..48993ddebb831fb944416ce68cf804869c347869 100644 (file)
@@ -368,7 +368,7 @@ class DSLTestCase(FHDLTestCase):
             RED  = 1
             BLUE = 2
         m = Module()
-        se = Signal.enum(Color)
+        se = Signal(Color)
         with m.Switch(se):
             with m.Case(Color.RED):
                 m.d.comb += self.c1.eq(1)
index 1b3a919a7c1fdebac5991f3e32574a33c69caa6e..2398f8f3ad41c72672267c20ddd3df6ed4da2cac 100644 (file)
@@ -67,7 +67,7 @@ class FIFOModel(Elaboratable, FIFOInterface):
         self.r_domain = r_domain
         self.w_domain = w_domain
 
-        self.level = Signal.range(self.depth + 1)
+        self.level = Signal(range(self.depth + 1))
 
     def elaborate(self, platform):
         m = Module()
@@ -76,8 +76,8 @@ class FIFOModel(Elaboratable, FIFOInterface):
         w_port  = m.submodules.w_port = storage.write_port(domain=self.w_domain)
         r_port  = m.submodules.r_port = storage.read_port (domain="comb")
 
-        produce = Signal.range(self.depth)
-        consume = Signal.range(self.depth)
+        produce = Signal(range(self.depth))
+        consume = Signal(range(self.depth))
 
         m.d.comb += self.r_rdy.eq(self.level > 0)
         m.d.comb += r_port.addr.eq((consume + 1) % self.depth)