hdl.ast: rename `nbits` to `width`.
authorwhitequark <whitequark@whitequark.org>
Fri, 20 Sep 2019 15:35:55 +0000 (15:35 +0000)
committerwhitequark <whitequark@whitequark.org>
Fri, 20 Sep 2019 15:36:25 +0000 (15:36 +0000)
Also, replace `bits, sign = x.shape()` with more idiomatic
`width, signed = x.shape()`.

This unifies all properties corresponding to `len(x)` to `x.width`.
(Not all values have a `width` property.)

Fixes #210.

nmigen/back/pysim.py
nmigen/back/rtlil.py
nmigen/hdl/ast.py
nmigen/hdl/dsl.py
nmigen/hdl/mem.py
nmigen/hdl/xfrm.py
nmigen/test/test_build_res.py
nmigen/test/test_hdl_ast.py
nmigen/test/test_hdl_mem.py

index 57461ee84c2e6f1861136ddc2233b35853eeda7b..0f7e8c0a0c191e49f8338732e216e2f8c9ed1c8c 100644 (file)
@@ -561,7 +561,7 @@ class Simulator:
                     var_init = signal.decoder(signal.reset).expandtabs().replace(" ", "_")
                 else:
                     var_type = "wire"
-                    var_size = signal.nbits
+                    var_size = signal.width
                     var_init = signal.reset
 
                 suffix = None
index 460d1d424e51608f39de0a48f1b92faf1f20beb9..c5a0f5de50c472927a3f18b4f5de92fb7cc751a2 100644 (file)
@@ -283,12 +283,12 @@ class _ValueCompilerState:
         else:
             wire_name = signal.name
 
-        wire_curr = self.rtlil.wire(width=signal.nbits, name=wire_name,
+        wire_curr = self.rtlil.wire(width=signal.width, name=wire_name,
                                     port_id=port_id, port_kind=port_kind,
                                     attrs=signal.attrs,
                                     src=src(signal.src_loc))
         if signal in self.driven and self.driven[signal]:
-            wire_next = self.rtlil.wire(width=signal.nbits, name=wire_curr + "$next",
+            wire_next = self.rtlil.wire(width=signal.width, name=wire_curr + "$next",
                                         src=src(signal.src_loc))
         else:
             wire_next = None
@@ -403,10 +403,10 @@ class _RHSValueCompiler(_ValueCompiler):
 
     def on_Const(self, value):
         if isinstance(value.value, str):
-            return "{}'{}".format(value.nbits, value.value)
+            return "{}'{}".format(value.width, value.value)
         else:
-            value_twos_compl = value.value & ((1 << value.nbits) - 1)
-            return "{}'{:0{}b}".format(value.nbits, value_twos_compl, value.nbits)
+            value_twos_compl = value.value & ((1 << value.width) - 1)
+            return "{}'{:0{}b}".format(value.width, value_twos_compl, value.width)
 
     def on_AnyConst(self, value):
         if value in self.s.anys:
@@ -703,13 +703,13 @@ class _StatementCompiler(xfrm.StatementVisitor):
         except LegalizeValue as legalize:
             with self._case.switch(self.rhs_compiler(legalize.value),
                                    src=src(legalize.src_loc)) as switch:
-                bits, sign = legalize.value.shape()
-                tests = ["{:0{}b}".format(v, bits) for v in legalize.branches]
-                tests[-1] = "-" * bits
+                width, signed = legalize.value.shape()
+                tests = ["{:0{}b}".format(v, width) for v in legalize.branches]
+                tests[-1] = "-" * width
                 for branch, test in zip(legalize.branches, tests):
                     with self.case(switch, (test,)):
                         self._wrap_assign = False
-                        branch_value = ast.Const(branch, (bits, sign))
+                        branch_value = ast.Const(branch, (width, signed))
                         with self.state.expand_to(legalize.value, branch_value):
                             super().on_statement(stmt)
             self._wrap_assign = True
@@ -842,7 +842,7 @@ def _convert_fragment(builder, fragment, name_map, hierarchy):
                         if signal not in group_signals:
                             continue
                         if domain is None:
-                            prev_value = ast.Const(signal.reset, signal.nbits)
+                            prev_value = ast.Const(signal.reset, signal.width)
                         else:
                             prev_value = signal
                         case.assign(lhs_compiler(signal), rhs_compiler(prev_value))
@@ -871,7 +871,7 @@ def _convert_fragment(builder, fragment, name_map, hierarchy):
                         if signal not in group_signals:
                             continue
                         wire_curr, wire_next = compiler_state.resolve(signal)
-                        sync.update(wire_curr, rhs_compiler(ast.Const(signal.reset, signal.nbits)))
+                        sync.update(wire_curr, rhs_compiler(ast.Const(signal.reset, signal.width)))
 
                     # The Verilog simulator trigger needs to change at time 0, so if we haven't
                     # yet done that in some process, do it.
@@ -926,7 +926,7 @@ def _convert_fragment(builder, fragment, name_map, hierarchy):
             if wire in driven:
                 continue
             wire_curr, _ = compiler_state.wires[wire]
-            module.connect(wire_curr, rhs_compiler(ast.Const(wire.reset, wire.nbits)))
+            module.connect(wire_curr, rhs_compiler(ast.Const(wire.reset, wire.width)))
 
     # Collect the names we've given to our ports in RTLIL, and correlate these with the signals
     # represented by these ports. If we are a submodule, this will be necessary to create a cell
index 5e860fec8d4273888618a3081ee2547e120917a5..d9e3d5e37a3ac7b465f6792b409a09e183ec2252 100644 (file)
@@ -35,14 +35,14 @@ def _enum_shape(enum_type):
     max_value = max(member.value for member in enum_type)
     if not isinstance(min_value, int) or not isinstance(max_value, int):
         raise TypeError("Only enumerations with integer values can be converted to nMigen values")
-    sign = min_value < 0 or max_value < 0
-    bits = max(bits_for(min_value, sign), bits_for(max_value, sign))
-    return (bits, sign)
+    signed = min_value < 0 or max_value < 0
+    width  = max(bits_for(min_value, signed), bits_for(max_value, signed))
+    return (width, signed)
 
 
 def _enum_to_bits(enum_value):
-    bits, sign = _enum_shape(type(enum_value))
-    return format(enum_value.value & ((1 << bits) - 1), "b").rjust(bits, "0")
+    width, signed = _enum_shape(type(enum_value))
+    return format(enum_value.value & ((1 << width) - 1), "b").rjust(width, "0")
 
 
 class Value(metaclass=ABCMeta):
@@ -347,24 +347,23 @@ class Const(Value):
     ----------
     value : int
     shape : int or tuple or None
-        Either an integer `bits` or a tuple `(bits, signed)`
-        specifying the number of bits in this `Const` and whether it is
-        signed (can represent negative values). `shape` defaults
-        to the minimum width and signedness of `value`.
+        Either an integer ``width`` or a tuple ``(width, signed)`` specifying the number of bits
+        in this constant and whether it is signed (can represent negative values).
+        ``shape`` defaults to the minimum possible width and signedness of ``value``.
 
     Attributes
     ----------
-    nbits : int
+    width : int
     signed : bool
     """
     src_loc = None
 
     @staticmethod
     def normalize(value, shape):
-        nbits, signed = shape
-        mask = (1 << nbits) - 1
+        width, signed = shape
+        mask = (1 << width) - 1
         value &= mask
-        if signed and value >> (nbits - 1):
+        if signed and value >> (width - 1):
             value |= ~mask
         return value
 
@@ -375,14 +374,20 @@ class Const(Value):
             shape = bits_for(self.value), self.value < 0
         if isinstance(shape, int):
             shape = shape, self.value < 0
-        self.nbits, self.signed = shape
-        if not isinstance(self.nbits, int) or self.nbits < 0:
+        self.width, self.signed = shape
+        if not isinstance(self.width, int) or self.width < 0:
             raise TypeError("Width must be a non-negative integer, not '{!r}'"
-                            .format(self.nbits))
+                            .format(self.width))
         self.value = self.normalize(self.value, shape)
 
+    # TODO(nmigen-0.2): move this to nmigen.compat and make it a deprecated extension
+    @property
+    @deprecated("instead of `const.nbits`, use `const.width`")
+    def nbits(self):
+        return self.width
+
     def shape(self):
-        return self.nbits, self.signed
+        return self.width, self.signed
 
     def _rhs_signals(self):
         return ValueSet()
@@ -391,7 +396,7 @@ class Const(Value):
         return self.value
 
     def __repr__(self):
-        return "(const {}'{}d{})".format(self.nbits, "s" if self.signed else "", self.value)
+        return "(const {}'{}d{})".format(self.width, "s" if self.signed else "", self.value)
 
 
 C = Const  # shorthand
@@ -402,13 +407,13 @@ class AnyValue(Value, DUID):
         super().__init__(src_loc_at=src_loc_at)
         if isinstance(shape, int):
             shape = shape, False
-        self.nbits, self.signed = shape
-        if not isinstance(self.nbits, int) or self.nbits < 0:
+        self.width, self.signed = shape
+        if not isinstance(self.width, int) or self.width < 0:
             raise TypeError("Width must be a non-negative integer, not '{!r}'"
-                            .format(self.nbits))
+                            .format(self.width))
 
     def shape(self):
-        return self.nbits, self.signed
+        return self.width, self.signed
 
     def _rhs_signals(self):
         return ValueSet()
@@ -453,41 +458,41 @@ class Operator(Value):
     def shape(self):
         op_shapes = list(map(lambda x: x.shape(), self.operands))
         if len(op_shapes) == 1:
-            (a_bits, a_sign), = op_shapes
+            (a_width, a_signed), = op_shapes
             if self.op in ("+", "~"):
-                return a_bits, a_sign
+                return a_width, a_signed
             if self.op == "-":
-                if not a_sign:
-                    return a_bits + 1, True
+                if not a_signed:
+                    return a_width + 1, True
                 else:
-                    return a_bits, a_sign
+                    return a_width, a_signed
             if self.op in ("b", "r|", "r&", "r^"):
                 return 1, False
         elif len(op_shapes) == 2:
-            (a_bits, a_sign), (b_bits, b_sign) = op_shapes
+            (a_width, a_signed), (b_width, b_signed) = op_shapes
             if self.op == "+" or self.op == "-":
-                bits, sign = self._bitwise_binary_shape(*op_shapes)
-                return bits + 1, sign
+                width, signed = self._bitwise_binary_shape(*op_shapes)
+                return width + 1, signed
             if self.op == "*":
-                return a_bits + b_bits, a_sign or b_sign
+                return a_width + b_width, a_signed or b_signed
             if self.op == "%":
-                return a_bits, a_sign
+                return a_width, a_signed
             if self.op in ("<", "<=", "==", "!=", ">", ">="):
                 return 1, False
             if self.op in ("&", "^", "|"):
                 return self._bitwise_binary_shape(*op_shapes)
             if self.op == "<<":
-                if b_sign:
-                    extra = 2 ** (b_bits - 1) - 1
+                if b_signed:
+                    extra = 2 ** (b_width - 1) - 1
                 else:
-                    extra = 2 ** (b_bits)     - 1
-                return a_bits + extra, a_sign
+                    extra = 2 ** (b_width)     - 1
+                return a_width + extra, a_signed
             if self.op == ">>":
-                if b_sign:
-                    extra = 2 ** (b_bits - 1)
+                if b_signed:
+                    extra = 2 ** (b_width - 1)
                 else:
                     extra = 0
-                return a_bits + extra, a_sign
+                return a_width + extra, a_signed
         elif len(op_shapes) == 3:
             if self.op == "m":
                 s_shape, a_shape, b_shape = op_shapes
@@ -683,7 +688,7 @@ class Signal(Value, DUID):
     Parameters
     ----------
     shape : int or tuple or None
-        Either an integer ``bits`` or a tuple ``(bits, signed)`` specifying the number of bits
+        Either an integer ``width`` or a tuple ``(width, signed)`` specifying the number of bits
         in this ``Signal`` and whether it is signed (can represent negative values).
         ``shape`` defaults to 1-bit and non-signed.
     name : str
@@ -716,7 +721,7 @@ class Signal(Value, DUID):
 
     Attributes
     ----------
-    nbits : int
+    width : int
     signed : bool
     name : str
     reset : int
@@ -750,27 +755,27 @@ class Signal(Value, DUID):
                                  .format(min, max + 1))
             self.signed = min < 0 or max < 0
             if min == max:
-                self.nbits = 0
+                self.width = 0
             else:
-                self.nbits = builtins.max(bits_for(min, self.signed),
+                self.width = builtins.max(bits_for(min, self.signed),
                                           bits_for(max, self.signed))
 
         else:
             if not (min is None and max is None):
                 raise ValueError("Only one of bits/signedness or bounds may be specified")
             if isinstance(shape, int):
-                self.nbits, self.signed = shape, False
+                self.width, self.signed = shape, False
             else:
-                self.nbits, self.signed = shape
+                self.width, self.signed = shape
 
-        if not isinstance(self.nbits, int) or self.nbits < 0:
-            raise TypeError("Width must be a non-negative integer, not '{!r}'".format(self.nbits))
+        if not isinstance(self.width, int) or self.width < 0:
+            raise TypeError("Width must be a non-negative integer, not '{!r}'".format(self.width))
 
-        reset_nbits = bits_for(reset, self.signed)
-        if reset != 0 and reset_nbits > self.nbits:
+        reset_width = bits_for(reset, self.signed)
+        if reset != 0 and reset_width > self.width:
             warnings.warn("Reset value {!r} requires {} bits to represent, but the signal "
                           "only has {} bits"
-                          .format(reset, reset_nbits, self.nbits),
+                          .format(reset, reset_width, self.width),
                           SyntaxWarning, stacklevel=2 + src_loc_at)
 
         self.reset = int(reset)
@@ -800,9 +805,9 @@ class Signal(Value, DUID):
             signed = value_range.start < 0 or (value_range.stop - value_range.step) < 0
         else:
             signed = value_range.start < 0
-        nbits  = max(bits_for(value_range.start, signed),
-                     bits_for(value_range.stop - value_range.step, signed))
-        return cls((nbits, signed), src_loc_at=1 + src_loc_at, **kwargs)
+        width = max(bits_for(value_range.start, signed),
+                    bits_for(value_range.stop - value_range.step, signed))
+        return cls((width, signed), src_loc_at=1 + src_loc_at, **kwargs)
 
     @classmethod
     def enum(cls, enum_type, *, src_loc_at=0, **kwargs):
@@ -839,8 +844,19 @@ class Signal(Value, DUID):
         kw.update(kwargs)
         return cls(**kw, src_loc_at=1 + src_loc_at)
 
+    # TODO(nmigen-0.2): move this to nmigen.compat and make it a deprecated extension
+    @property
+    @deprecated("instead of `signal.nbits`, use `signal.width`")
+    def nbits(self):
+        return self.width
+
+    @nbits.setter
+    @deprecated("instead of `signal.nbits = x`, use `signal.width = x`")
+    def nbits(self, value):
+        self.width = value
+
     def shape(self):
-        return self.nbits, self.signed
+        return self.width, self.signed
 
     def _lhs_signals(self):
         return ValueSet((self,))
@@ -1028,11 +1044,11 @@ class ArrayProxy(Value):
         return (Value.wrap(elem) for elem in self.elems)
 
     def shape(self):
-        bits, sign = 0, False
-        for elem_bits, elem_sign in (elem.shape() for elem in self._iter_as_values()):
-            bits = max(bits, elem_bits + elem_sign)
-            sign = max(sign, elem_sign)
-        return bits, sign
+        width, signed = 0, False
+        for elem_width, elem_signed in (elem.shape() for elem in self._iter_as_values()):
+            width  = max(width, elem_width + elem_signed)
+            signed = max(signed, elem_signed)
+        return width, signed
 
     def _lhs_signals(self):
         signals = union((elem._lhs_signals() for elem in self._iter_as_values()), start=ValueSet())
index 024587fec4e8fcbbed62bb26808ae95c306d0ef7..8a3b561cc0b8d4e45f0052c71575986f407f49d8 100644 (file)
@@ -168,8 +168,8 @@ class Module(_ModuleBuilderRoot, Elaboratable):
 
     def _check_signed_cond(self, cond):
         cond = Value.wrap(cond)
-        bits, sign = cond.shape()
-        if sign:
+        width, signed = cond.shape()
+        if signed:
             warnings.warn("Signed values in If/Elif conditions usually result from inverting "
                           "Python booleans with ~, which leads to unexpected results: ~True is "
                           "-2, which is truthful. Replace `~flag` with `not flag`. (If this is "
@@ -405,7 +405,7 @@ class Module(_ModuleBuilderRoot, Elaboratable):
             fsm_state_src_locs = data["state_src_locs"]
             if not fsm_states:
                 return
-            fsm_signal.nbits = bits_for(len(fsm_encoding) - 1)
+            fsm_signal.width = bits_for(len(fsm_encoding) - 1)
             if fsm_reset is None:
                 fsm_signal.reset = fsm_encoding[next(iter(fsm_states))]
             else:
index 996fca41e4c70885f89bedf54123790f0ad90264..181e906faaa97006c9b3a646759509568cedcaa8 100644 (file)
@@ -95,8 +95,8 @@ class ReadPort(Elaboratable):
     def elaborate(self, platform):
         f = Instance("$memrd",
             p_MEMID=self.memory,
-            p_ABITS=self.addr.nbits,
-            p_WIDTH=self.data.nbits,
+            p_ABITS=self.addr.width,
+            p_WIDTH=self.data.width,
             p_CLK_ENABLE=self.domain != "comb",
             p_CLK_POLARITY=1,
             p_TRANSPARENT=self.transparent,
@@ -158,8 +158,8 @@ class WritePort(Elaboratable):
     def elaborate(self, platform):
         f = Instance("$memwr",
             p_MEMID=self.memory,
-            p_ABITS=self.addr.nbits,
-            p_WIDTH=self.data.nbits,
+            p_ABITS=self.addr.width,
+            p_WIDTH=self.data.width,
             p_CLK_ENABLE=1,
             p_CLK_POLARITY=1,
             p_PRIORITY=self.priority,
index ab12ffdd3a46b914bdb5ca83ecf149758d583aa8..4e3b9c922debc03bb4c894d0dc2752c5ce47c040 100644 (file)
@@ -523,7 +523,7 @@ class DomainLowerer(FragmentTransformer, ValueTransformer, StatementTransformer)
             domain = fragment.domains[domain_name]
             if domain.rst is None:
                 continue
-            stmts = [signal.eq(Const(signal.reset, signal.nbits))
+            stmts = [signal.eq(Const(signal.reset, signal.width))
                      for signal in signals if not signal.reset_less]
             fragment.add_statements(Switch(domain.rst, {1: stmts}))
 
@@ -732,7 +732,7 @@ class _ControlInserter(FragmentTransformer):
 
 class ResetInserter(_ControlInserter):
     def _insert_control(self, fragment, domain, signals):
-        stmts = [s.eq(Const(s.reset, s.nbits)) for s in signals if not s.reset_less]
+        stmts = [s.eq(Const(s.reset, s.width)) for s in signals if not s.reset_less]
         fragment.add_statements(Switch(self.controls[domain], {1: stmts}, src_loc=self.src_loc))
 
 
index 4338770ca51cbf4d271e00f37b4789aab9697ac9..c212700dbc94fe19b16f3e3da5a7f0b912ca5625 100644 (file)
@@ -81,7 +81,7 @@ class ResourceManagerTestCase(FHDLTestCase):
         self.assertEqual(len(ports), 2)
         scl, sda = ports
         self.assertEqual(ports[1].name, "i2c_0__sda__io")
-        self.assertEqual(ports[1].nbits, 1)
+        self.assertEqual(ports[1].width, 1)
 
         self.assertEqual(list(self.cm.iter_single_ended_pins()), [
             (i2c.scl, scl, {}, False),
@@ -102,9 +102,9 @@ class ResourceManagerTestCase(FHDLTestCase):
         self.assertEqual(len(ports), 2)
         p, n = ports
         self.assertEqual(p.name, "clk100_0__p")
-        self.assertEqual(p.nbits, clk100.width)
+        self.assertEqual(p.width, clk100.width)
         self.assertEqual(n.name, "clk100_0__n")
-        self.assertEqual(n.nbits, clk100.width)
+        self.assertEqual(n.width, clk100.width)
 
         self.assertEqual(list(self.cm.iter_differential_pins()), [
             (clk100, p, n, {}, False),
index e459b3dcd2a3ba2d0ed0c18267700247b9136ad7..9f2fb410d425c3cf96a19ac48303d0967de446e2 100644 (file)
@@ -381,7 +381,7 @@ class SliceTestCase(FHDLTestCase):
 class BitSelectTestCase(FHDLTestCase):
     def setUp(self):
         self.c = Const(0, 8)
-        self.s = Signal.range(self.c.nbits)
+        self.s = Signal.range(self.c.width)
 
     def test_shape(self):
         s1 = self.c.bit_select(self.s, 2)
@@ -405,7 +405,7 @@ class BitSelectTestCase(FHDLTestCase):
 class WordSelectTestCase(FHDLTestCase):
     def setUp(self):
         self.c = Const(0, 8)
-        self.s = Signal.range(self.c.nbits)
+        self.s = Signal.range(self.c.width)
 
     def test_shape(self):
         s1 = self.c.word_select(self.s, 2)
index 13ce7eddabb99aeb82584696ca9b95f02ce82797..84e1aed839f8b5a8a1a2f1c5082cc8fa19aeb337 100644 (file)
@@ -123,8 +123,8 @@ class DummyPortTestCase(FHDLTestCase):
 
     def test_sizes(self):
         p1 = DummyPort(width=8, addr_bits=2)
-        self.assertEqual(p1.addr.nbits, 2)
-        self.assertEqual(p1.data.nbits, 8)
-        self.assertEqual(p1.en.nbits, 1)
+        self.assertEqual(p1.addr.width, 2)
+        self.assertEqual(p1.data.width, 8)
+        self.assertEqual(p1.en.width, 1)
         p2 = DummyPort(width=8, addr_bits=2, granularity=2)
-        self.assertEqual(p2.en.nbits, 4)
+        self.assertEqual(p2.en.width, 4)