From f5e8c9033dde889c535171ba6beb4a72f8f03f3d Mon Sep 17 00:00:00 2001 From: whitequark Date: Sat, 15 Dec 2018 09:19:26 +0000 Subject: [PATCH] fhdl.ir: fix incorrect uses of positive to say non-negative. Also test Part and Slice properly. --- nmigen/fhdl/ast.py | 17 +++-- .../{test_fhdl_value.py => test_fhdl_ast.py} | 73 +++++++++++++++++-- 2 files changed, 74 insertions(+), 16 deletions(-) rename nmigen/test/{test_fhdl_value.py => test_fhdl_ast.py} (84%) diff --git a/nmigen/fhdl/ast.py b/nmigen/fhdl/ast.py index 37bcba3..1908a0e 100644 --- a/nmigen/fhdl/ast.py +++ b/nmigen/fhdl/ast.py @@ -236,7 +236,7 @@ class Const(Value): shape = shape, self.value < 0 self.nbits, self.signed = shape if not isinstance(self.nbits, int) or self.nbits < 0: - raise TypeError("Width must be a positive integer") + raise TypeError("Width must be a non-negative integer") self.value = self.normalize(self.value, shape) def shape(self): @@ -313,7 +313,7 @@ class Operator(Value): return obs[0] elif self.op == "m": return self._bitwise_binary_shape(obs[1], obs[2]) - raise NotImplementedError("Operator '{!r}' not implemented".format(self.op)) # :nocov: + raise NotImplementedError("Operator '{}' not implemented".format(self.op)) # :nocov: def _rhs_signals(self): return union(op._rhs_signals() for op in self.operands) @@ -344,9 +344,9 @@ def Mux(sel, val1, val0): class Slice(Value): def __init__(self, value, start, end): if not isinstance(start, int): - raise TypeError("Slice start must be integer, not {!r}".format(start)) + raise TypeError("Slice start must be an integer, not {!r}".format(start)) if not isinstance(end, int): - raise TypeError("Slice end must be integer, not {!r}".format(end)) + raise TypeError("Slice end must be an integer, not {!r}".format(end)) n = len(value) if start not in range(-n, n): @@ -381,7 +381,7 @@ class Slice(Value): class Part(Value): def __init__(self, value, offset, width): if not isinstance(width, int) or width < 0: - raise TypeError("Part width must be a positive integer, not {!r}".format(width)) + raise TypeError("Part width must be a non-negative integer, not {!r}".format(width)) super().__init__() self.value = value @@ -398,7 +398,7 @@ class Part(Value): return self.value._rhs_signals() def __repr__(self): - return "(part {} {})".format(repr(self.value), repr(self.offset), self.width) + return "(part {} {} {})".format(repr(self.value), repr(self.offset), self.width) class Cat(Value): @@ -464,7 +464,8 @@ class Repl(Value): """ def __init__(self, value, count): if not isinstance(count, int) or count < 0: - raise TypeError("Replication count must be a positive integer, not {!r}".format(count)) + raise TypeError("Replication count must be a non-negative integer, not {!r}" + .format(count)) super().__init__() self.value = Value.wrap(value) @@ -557,7 +558,7 @@ class Signal(Value, DUID): self.nbits, self.signed = shape if not isinstance(self.nbits, int) or self.nbits < 0: - raise TypeError("Width must be a positive integer, not {!r}".format(self.nbits)) + raise TypeError("Width must be a non-negative integer, not {!r}".format(self.nbits)) self.reset = int(reset) self.reset_less = bool(reset_less) diff --git a/nmigen/test/test_fhdl_value.py b/nmigen/test/test_fhdl_ast.py similarity index 84% rename from nmigen/test/test_fhdl_value.py rename to nmigen/test/test_fhdl_ast.py index 8e7dfd1..66ddec7 100644 --- a/nmigen/test/test_fhdl_value.py +++ b/nmigen/test/test_fhdl_ast.py @@ -64,9 +64,11 @@ class ConstTestCase(FHDLTestCase): self.assertEqual(Const(10).shape(), (4, False)) self.assertEqual(Const(-10).shape(), (5, True)) - self.assertEqual(Const(1, 4).shape(), (4, False)) - self.assertEqual(Const(1, (4, True)).shape(), (4, True)) + self.assertEqual(Const(1, 4).shape(), (4, False)) + self.assertEqual(Const(1, (4, True)).shape(), (4, True)) + self.assertEqual(Const(0, (0, False)).shape(), (0, False)) + def test_shape_bad(self): with self.assertRaises(TypeError): Const(1, -1) @@ -234,11 +236,53 @@ class SliceTestCase(FHDLTestCase): s2 = Const(-10)[0:2] self.assertEqual(s2.shape(), (2, False)) + def test_start_end_negative(self): + c = Const(0, 8) + s1 = Slice(c, 0, -1) + self.assertEqual((s1.start, s1.end), (0, 7)) + s1 = Slice(c, -4, -1) + self.assertEqual((s1.start, s1.end), (4, 7)) + + def test_start_end_wrong(self): + with self.assertRaises(TypeError): + Slice(0, "x", 1) + with self.assertRaises(TypeError): + Slice(0, 1, "x") + + def test_start_end_out_of_range(self): + c = Const(0, 8) + with self.assertRaises(IndexError): + Slice(c, 10, 12) + with self.assertRaises(IndexError): + Slice(c, 0, 12) + with self.assertRaises(IndexError): + Slice(c, 4, 2) + def test_repr(self): s1 = Const(10)[2] self.assertEqual(repr(s1), "(slice (const 4'd10) 2:3)") +class PartTestCase(FHDLTestCase): + def setUp(self): + self.c = Const(0, 8) + self.s = Signal(max=self.c.nbits) + + def test_shape(self): + s1 = self.c.part(self.s, 2) + self.assertEqual(s1.shape(), (2, False)) + s2 = self.c.part(self.s, 0) + self.assertEqual(s2.shape(), (0, False)) + + def test_width_bad(self): + with self.assertRaises(TypeError): + self.c.part(self.s, -1) + + def test_repr(self): + s = self.c.part(self.s, 2) + self.assertEqual(repr(s), "(part (const 8'd0) (sig s) 2)") + + class CatTestCase(FHDLTestCase): def test_shape(self): c1 = Cat(Const(10)) @@ -255,8 +299,10 @@ class CatTestCase(FHDLTestCase): class ReplTestCase(FHDLTestCase): def test_shape(self): - r1 = Repl(Const(10), 3) - self.assertEqual(r1.shape(), (12, False)) + s1 = Repl(Const(10), 3) + self.assertEqual(s1.shape(), (12, False)) + s2 = Repl(Const(10), 0) + self.assertEqual(s2.shape(), (0, False)) def test_count_wrong(self): with self.assertRaises(TypeError): @@ -265,8 +311,8 @@ class ReplTestCase(FHDLTestCase): Repl(Const(10), "str") def test_repr(self): - r1 = Repl(Const(10), 3) - self.assertEqual(repr(r1), "(repl (const 4'd10) 3)") + s = Repl(Const(10), 3) + self.assertEqual(repr(s), "(repl (const 4'd10) 3)") class SignalTestCase(FHDLTestCase): @@ -287,7 +333,10 @@ class SignalTestCase(FHDLTestCase): self.assertEqual(s7.shape(), (5, True)) s8 = Signal(min=-20, max=16) self.assertEqual(s8.shape(), (6, True)) + s9 = Signal(0) + self.assertEqual(s9.shape(), (0, False)) + def test_shape_bad(self): with self.assertRaises(ValueError): Signal(min=10, max=4) with self.assertRaises(ValueError): @@ -326,8 +375,10 @@ class SignalTestCase(FHDLTestCase): self.assertEqual(s3.reset_less, True) s4 = Signal.like(Signal(attrs={"no_retiming": True})) self.assertEqual(s4.attrs, {"no_retiming": True}) - s5 = Signal.like(10) - self.assertEqual(s5.shape(), (4, False)) + s5 = Signal.like(Signal(decoder=str)) + self.assertEqual(s5.decoder, str) + s6 = Signal.like(10) + self.assertEqual(s6.shape(), (4, False)) class ClockSignalTestCase(FHDLTestCase): @@ -340,6 +391,9 @@ class ClockSignalTestCase(FHDLTestCase): with self.assertRaises(TypeError): ClockSignal(1) + def test_shape(self): + self.assertEqual(ClockSignal().shape(), (1, False)) + def test_repr(self): s1 = ClockSignal() self.assertEqual(repr(s1), "(clk sync)") @@ -355,6 +409,9 @@ class ResetSignalTestCase(FHDLTestCase): with self.assertRaises(TypeError): ResetSignal(1) + def test_shape(self): + self.assertEqual(ResetSignal().shape(), (1, False)) + def test_repr(self): s1 = ResetSignal() self.assertEqual(repr(s1), "(rst sync)") -- 2.30.2