From: whitequark Date: Sat, 15 Dec 2018 16:13:53 +0000 (+0000) Subject: hdl: appropriately rename tests. NFC. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=93f50abe3f8af3eebf8d379d2dfb67019a665510;p=nmigen.git hdl: appropriately rename tests. NFC. --- diff --git a/nmigen/test/test_fhdl_ast.py b/nmigen/test/test_fhdl_ast.py deleted file mode 100644 index 0fde4c6..0000000 --- a/nmigen/test/test_fhdl_ast.py +++ /dev/null @@ -1,436 +0,0 @@ -from ..hdl.ast import * -from .tools import * - - -class ValueTestCase(FHDLTestCase): - def test_wrap(self): - self.assertIsInstance(Value.wrap(0), Const) - self.assertIsInstance(Value.wrap(True), Const) - c = Const(0) - self.assertIs(Value.wrap(c), c) - with self.assertRaises(TypeError): - Value.wrap("str") - - def test_bool(self): - with self.assertRaises(TypeError): - if Const(0): - pass - - def test_len(self): - self.assertEqual(len(Const(10)), 4) - - def test_getitem_int(self): - s1 = Const(10)[0] - self.assertIsInstance(s1, Slice) - self.assertEqual(s1.start, 0) - self.assertEqual(s1.end, 1) - s2 = Const(10)[-1] - self.assertIsInstance(s2, Slice) - self.assertEqual(s2.start, 3) - self.assertEqual(s2.end, 4) - with self.assertRaises(IndexError): - Const(10)[5] - - def test_getitem_slice(self): - s1 = Const(10)[1:3] - self.assertIsInstance(s1, Slice) - self.assertEqual(s1.start, 1) - self.assertEqual(s1.end, 3) - s2 = Const(10)[1:-2] - self.assertIsInstance(s2, Slice) - self.assertEqual(s2.start, 1) - self.assertEqual(s2.end, 2) - s3 = Const(31)[::2] - self.assertIsInstance(s3, Cat) - self.assertIsInstance(s3.operands[0], Slice) - self.assertEqual(s3.operands[0].start, 0) - self.assertEqual(s3.operands[0].end, 1) - self.assertIsInstance(s3.operands[1], Slice) - self.assertEqual(s3.operands[1].start, 2) - self.assertEqual(s3.operands[1].end, 3) - self.assertIsInstance(s3.operands[2], Slice) - self.assertEqual(s3.operands[2].start, 4) - self.assertEqual(s3.operands[2].end, 5) - - def test_getitem_wrong(self): - with self.assertRaises(TypeError): - Const(31)["str"] - - -class ConstTestCase(FHDLTestCase): - def test_shape(self): - self.assertEqual(Const(0).shape(), (1, False)) - self.assertEqual(Const(1).shape(), (1, False)) - 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(0, (0, False)).shape(), (0, False)) - - def test_shape_bad(self): - with self.assertRaises(TypeError): - Const(1, -1) - - def test_normalization(self): - self.assertEqual(Const(0b10110, (5, True)).value, -10) - - def test_value(self): - self.assertEqual(Const(10).value, 10) - - def test_repr(self): - self.assertEqual(repr(Const(10)), "(const 4'd10)") - self.assertEqual(repr(Const(-10)), "(const 5'sd-10)") - - def test_hash(self): - with self.assertRaises(TypeError): - hash(Const(0)) - - -class OperatorTestCase(FHDLTestCase): - def test_bool(self): - v = Const(0, 4).bool() - self.assertEqual(repr(v), "(b (const 4'd0))") - self.assertEqual(v.shape(), (1, False)) - - def test_invert(self): - v = ~Const(0, 4) - self.assertEqual(repr(v), "(~ (const 4'd0))") - self.assertEqual(v.shape(), (4, False)) - - def test_neg(self): - v1 = -Const(0, (4, False)) - self.assertEqual(repr(v1), "(- (const 4'd0))") - self.assertEqual(v1.shape(), (5, True)) - v2 = -Const(0, (4, True)) - self.assertEqual(repr(v2), "(- (const 4'sd0))") - self.assertEqual(v2.shape(), (4, True)) - - def test_add(self): - v1 = Const(0, (4, False)) + Const(0, (6, False)) - self.assertEqual(repr(v1), "(+ (const 4'd0) (const 6'd0))") - self.assertEqual(v1.shape(), (7, False)) - v2 = Const(0, (4, True)) + Const(0, (6, True)) - self.assertEqual(v2.shape(), (7, True)) - v3 = Const(0, (4, True)) + Const(0, (4, False)) - self.assertEqual(v3.shape(), (6, True)) - v4 = Const(0, (4, False)) + Const(0, (4, True)) - self.assertEqual(v4.shape(), (6, True)) - v5 = 10 + Const(0, 4) - self.assertEqual(v5.shape(), (5, False)) - - def test_sub(self): - v1 = Const(0, (4, False)) - Const(0, (6, False)) - self.assertEqual(repr(v1), "(- (const 4'd0) (const 6'd0))") - self.assertEqual(v1.shape(), (7, False)) - v2 = Const(0, (4, True)) - Const(0, (6, True)) - self.assertEqual(v2.shape(), (7, True)) - v3 = Const(0, (4, True)) - Const(0, (4, False)) - self.assertEqual(v3.shape(), (6, True)) - v4 = Const(0, (4, False)) - Const(0, (4, True)) - self.assertEqual(v4.shape(), (6, True)) - v5 = 10 - Const(0, 4) - self.assertEqual(v5.shape(), (5, False)) - - def test_mul(self): - v1 = Const(0, (4, False)) * Const(0, (6, False)) - self.assertEqual(repr(v1), "(* (const 4'd0) (const 6'd0))") - self.assertEqual(v1.shape(), (10, False)) - v2 = Const(0, (4, True)) * Const(0, (6, True)) - self.assertEqual(v2.shape(), (9, True)) - v3 = Const(0, (4, True)) * Const(0, (4, False)) - self.assertEqual(v3.shape(), (8, True)) - v5 = 10 * Const(0, 4) - self.assertEqual(v5.shape(), (8, False)) - - def test_and(self): - v1 = Const(0, (4, False)) & Const(0, (6, False)) - self.assertEqual(repr(v1), "(& (const 4'd0) (const 6'd0))") - self.assertEqual(v1.shape(), (6, False)) - v2 = Const(0, (4, True)) & Const(0, (6, True)) - self.assertEqual(v2.shape(), (6, True)) - v3 = Const(0, (4, True)) & Const(0, (4, False)) - self.assertEqual(v3.shape(), (5, True)) - v4 = Const(0, (4, False)) & Const(0, (4, True)) - self.assertEqual(v4.shape(), (5, True)) - v5 = 10 & Const(0, 4) - self.assertEqual(v5.shape(), (4, False)) - - def test_or(self): - v1 = Const(0, (4, False)) | Const(0, (6, False)) - self.assertEqual(repr(v1), "(| (const 4'd0) (const 6'd0))") - self.assertEqual(v1.shape(), (6, False)) - v2 = Const(0, (4, True)) | Const(0, (6, True)) - self.assertEqual(v2.shape(), (6, True)) - v3 = Const(0, (4, True)) | Const(0, (4, False)) - self.assertEqual(v3.shape(), (5, True)) - v4 = Const(0, (4, False)) | Const(0, (4, True)) - self.assertEqual(v4.shape(), (5, True)) - v5 = 10 | Const(0, 4) - self.assertEqual(v5.shape(), (4, False)) - - def test_xor(self): - v1 = Const(0, (4, False)) ^ Const(0, (6, False)) - self.assertEqual(repr(v1), "(^ (const 4'd0) (const 6'd0))") - self.assertEqual(v1.shape(), (6, False)) - v2 = Const(0, (4, True)) ^ Const(0, (6, True)) - self.assertEqual(v2.shape(), (6, True)) - v3 = Const(0, (4, True)) ^ Const(0, (4, False)) - self.assertEqual(v3.shape(), (5, True)) - v4 = Const(0, (4, False)) ^ Const(0, (4, True)) - self.assertEqual(v4.shape(), (5, True)) - v5 = 10 ^ Const(0, 4) - self.assertEqual(v5.shape(), (4, False)) - - def test_shl(self): - v1 = Const(1, 4) << Const(4) - self.assertEqual(repr(v1), "(<< (const 4'd1) (const 3'd4))") - self.assertEqual(v1.shape(), (11, False)) - v2 = Const(1, 4) << Const(-3) - self.assertEqual(v2.shape(), (7, False)) - - def test_shr(self): - v1 = Const(1, 4) >> Const(4) - self.assertEqual(repr(v1), "(>> (const 4'd1) (const 3'd4))") - self.assertEqual(v1.shape(), (4, False)) - v2 = Const(1, 4) >> Const(-3) - self.assertEqual(v2.shape(), (8, False)) - - def test_lt(self): - v = Const(0, 4) < Const(0, 6) - self.assertEqual(repr(v), "(< (const 4'd0) (const 6'd0))") - self.assertEqual(v.shape(), (1, False)) - - def test_le(self): - v = Const(0, 4) <= Const(0, 6) - self.assertEqual(repr(v), "(<= (const 4'd0) (const 6'd0))") - self.assertEqual(v.shape(), (1, False)) - - def test_gt(self): - v = Const(0, 4) > Const(0, 6) - self.assertEqual(repr(v), "(> (const 4'd0) (const 6'd0))") - self.assertEqual(v.shape(), (1, False)) - - def test_ge(self): - v = Const(0, 4) >= Const(0, 6) - self.assertEqual(repr(v), "(>= (const 4'd0) (const 6'd0))") - self.assertEqual(v.shape(), (1, False)) - - def test_eq(self): - v = Const(0, 4) == Const(0, 6) - self.assertEqual(repr(v), "(== (const 4'd0) (const 6'd0))") - self.assertEqual(v.shape(), (1, False)) - - def test_ne(self): - v = Const(0, 4) != Const(0, 6) - self.assertEqual(repr(v), "(!= (const 4'd0) (const 6'd0))") - self.assertEqual(v.shape(), (1, False)) - - def test_mux(self): - s = Const(0) - v1 = Mux(s, Const(0, (4, False)), Const(0, (6, False))) - self.assertEqual(repr(v1), "(m (const 1'd0) (const 4'd0) (const 6'd0))") - self.assertEqual(v1.shape(), (6, False)) - v2 = Mux(s, Const(0, (4, True)), Const(0, (6, True))) - self.assertEqual(v2.shape(), (6, True)) - v3 = Mux(s, Const(0, (4, True)), Const(0, (4, False))) - self.assertEqual(v3.shape(), (5, True)) - v4 = Mux(s, Const(0, (4, False)), Const(0, (4, True))) - self.assertEqual(v4.shape(), (5, True)) - - def test_bool(self): - v = Const(0).bool() - self.assertEqual(repr(v), "(b (const 1'd0))") - self.assertEqual(v.shape(), (1, False)) - - def test_hash(self): - with self.assertRaises(TypeError): - hash(Const(0) + Const(0)) - - -class SliceTestCase(FHDLTestCase): - def test_shape(self): - s1 = Const(10)[2] - self.assertEqual(s1.shape(), (1, False)) - 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)) - self.assertEqual(c1.shape(), (4, False)) - c2 = Cat(Const(10), Const(1)) - self.assertEqual(c2.shape(), (5, False)) - c3 = Cat(Const(10), Const(1), Const(0)) - self.assertEqual(c3.shape(), (6, False)) - - def test_repr(self): - c1 = Cat(Const(10), Const(1)) - self.assertEqual(repr(c1), "(cat (const 4'd10) (const 1'd1))") - - -class ReplTestCase(FHDLTestCase): - def test_shape(self): - 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): - Repl(Const(10), -1) - with self.assertRaises(TypeError): - Repl(Const(10), "str") - - def test_repr(self): - s = Repl(Const(10), 3) - self.assertEqual(repr(s), "(repl (const 4'd10) 3)") - - -class SignalTestCase(FHDLTestCase): - def test_shape(self): - s1 = Signal() - self.assertEqual(s1.shape(), (1, False)) - s2 = Signal(2) - self.assertEqual(s2.shape(), (2, False)) - s3 = Signal((2, False)) - self.assertEqual(s3.shape(), (2, False)) - s4 = Signal((2, True)) - self.assertEqual(s4.shape(), (2, True)) - s5 = Signal(max=16) - self.assertEqual(s5.shape(), (4, False)) - s6 = Signal(min=4, max=16) - self.assertEqual(s6.shape(), (4, False)) - s7 = Signal(min=-4, max=16) - 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): - Signal(2, min=10) - with self.assertRaises(TypeError): - Signal(-10) - - def test_name(self): - s1 = Signal() - self.assertEqual(s1.name, "s1") - s2 = Signal(name="sig") - self.assertEqual(s2.name, "sig") - - def test_reset(self): - s1 = Signal(4, reset=0b111, reset_less=True) - self.assertEqual(s1.reset, 0b111) - self.assertEqual(s1.reset_less, True) - - def test_attrs(self): - s1 = Signal() - self.assertEqual(s1.attrs, {}) - s2 = Signal(attrs={"no_retiming": True}) - self.assertEqual(s2.attrs, {"no_retiming": True}) - - def test_repr(self): - s1 = Signal() - self.assertEqual(repr(s1), "(sig s1)") - - def test_like(self): - s1 = Signal.like(Signal(4)) - self.assertEqual(s1.shape(), (4, False)) - s2 = Signal.like(Signal(min=-15)) - self.assertEqual(s2.shape(), (5, True)) - s3 = Signal.like(Signal(4, reset=0b111, reset_less=True)) - self.assertEqual(s3.reset, 0b111) - self.assertEqual(s3.reset_less, True) - s4 = Signal.like(Signal(attrs={"no_retiming": True})) - self.assertEqual(s4.attrs, {"no_retiming": True}) - s5 = Signal.like(Signal(decoder=str)) - self.assertEqual(s5.decoder, str) - s6 = Signal.like(10) - self.assertEqual(s6.shape(), (4, False)) - - -class ClockSignalTestCase(FHDLTestCase): - def test_domain(self): - s1 = ClockSignal() - self.assertEqual(s1.domain, "sync") - s2 = ClockSignal("pix") - self.assertEqual(s2.domain, "pix") - - 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)") - - -class ResetSignalTestCase(FHDLTestCase): - def test_domain(self): - s1 = ResetSignal() - self.assertEqual(s1.domain, "sync") - s2 = ResetSignal("pix") - self.assertEqual(s2.domain, "pix") - - 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)") diff --git a/nmigen/test/test_fhdl_cd.py b/nmigen/test/test_fhdl_cd.py deleted file mode 100644 index 8e7dcdf..0000000 --- a/nmigen/test/test_fhdl_cd.py +++ /dev/null @@ -1,57 +0,0 @@ -from ..hdl.cd import * -from .tools import * - - -class ClockDomainCase(FHDLTestCase): - def test_name(self): - sync = ClockDomain() - self.assertEqual(sync.name, "sync") - self.assertEqual(sync.clk.name, "clk") - self.assertEqual(sync.rst.name, "rst") - pix = ClockDomain() - self.assertEqual(pix.name, "pix") - self.assertEqual(pix.clk.name, "pix_clk") - self.assertEqual(pix.rst.name, "pix_rst") - cd_pix = ClockDomain() - self.assertEqual(pix.name, "pix") - dom = [ClockDomain("foo")][0] - self.assertEqual(dom.name, "foo") - with self.assertRaises(ValueError, - msg="Clock domain name must be specified explicitly"): - ClockDomain() - - def test_with_reset(self): - pix = ClockDomain() - self.assertIsNotNone(pix.clk) - self.assertIsNotNone(pix.rst) - self.assertFalse(pix.async_reset) - - def test_without_reset(self): - pix = ClockDomain(reset_less=True) - self.assertIsNotNone(pix.clk) - self.assertIsNone(pix.rst) - self.assertFalse(pix.async_reset) - - def test_async_reset(self): - pix = ClockDomain(async_reset=True) - self.assertIsNotNone(pix.clk) - self.assertIsNotNone(pix.rst) - self.assertTrue(pix.async_reset) - - def test_rename(self): - sync = ClockDomain() - self.assertEqual(sync.name, "sync") - self.assertEqual(sync.clk.name, "clk") - self.assertEqual(sync.rst.name, "rst") - sync.rename("pix") - self.assertEqual(sync.name, "pix") - self.assertEqual(sync.clk.name, "pix_clk") - self.assertEqual(sync.rst.name, "pix_rst") - - def test_rename_reset_less(self): - sync = ClockDomain(reset_less=True) - self.assertEqual(sync.name, "sync") - self.assertEqual(sync.clk.name, "clk") - sync.rename("pix") - self.assertEqual(sync.name, "pix") - self.assertEqual(sync.clk.name, "pix_clk") diff --git a/nmigen/test/test_fhdl_dsl.py b/nmigen/test/test_fhdl_dsl.py deleted file mode 100644 index f156880..0000000 --- a/nmigen/test/test_fhdl_dsl.py +++ /dev/null @@ -1,375 +0,0 @@ -from ..hdl.ast import * -from ..hdl.dsl import * -from .tools import * - - -class DSLTestCase(FHDLTestCase): - def setUp(self): - self.s1 = Signal() - self.s2 = Signal() - self.s3 = Signal() - self.c1 = Signal() - self.c2 = Signal() - self.c3 = Signal() - self.w1 = Signal(4) - - def test_d_comb(self): - m = Module() - m.d.comb += self.c1.eq(1) - m._flush() - self.assertEqual(m._driving[self.c1], None) - self.assertRepr(m._statements, """( - (eq (sig c1) (const 1'd1)) - )""") - - def test_d_sync(self): - m = Module() - m.d.sync += self.c1.eq(1) - m._flush() - self.assertEqual(m._driving[self.c1], "sync") - self.assertRepr(m._statements, """( - (eq (sig c1) (const 1'd1)) - )""") - - def test_d_pix(self): - m = Module() - m.d.pix += self.c1.eq(1) - m._flush() - self.assertEqual(m._driving[self.c1], "pix") - self.assertRepr(m._statements, """( - (eq (sig c1) (const 1'd1)) - )""") - - def test_d_index(self): - m = Module() - m.d["pix"] += self.c1.eq(1) - m._flush() - self.assertEqual(m._driving[self.c1], "pix") - self.assertRepr(m._statements, """( - (eq (sig c1) (const 1'd1)) - )""") - - def test_d_no_conflict(self): - m = Module() - m.d.comb += self.w1[0].eq(1) - m.d.comb += self.w1[1].eq(1) - - def test_d_conflict(self): - m = Module() - with self.assertRaises(SyntaxError, - msg="Driver-driver conflict: trying to drive (sig c1) from d.sync, but it " - "is already driven from d.comb"): - m.d.comb += self.c1.eq(1) - m.d.sync += self.c1.eq(1) - - def test_d_wrong(self): - m = Module() - with self.assertRaises(AttributeError, - msg="Cannot assign 'd.pix' attribute; did you mean 'd.pix +='?"): - m.d.pix = None - - def test_d_asgn_wrong(self): - m = Module() - with self.assertRaises(SyntaxError, - msg="Only assignments may be appended to d.sync"): - m.d.sync += Switch(self.s1, {}) - - def test_comb_wrong(self): - m = Module() - with self.assertRaises(AttributeError, - msg="'Module' object has no attribute 'comb'; did you mean 'd.comb'?"): - m.comb += self.c1.eq(1) - - def test_sync_wrong(self): - m = Module() - with self.assertRaises(AttributeError, - msg="'Module' object has no attribute 'sync'; did you mean 'd.sync'?"): - m.sync += self.c1.eq(1) - - def test_attr_wrong(self): - m = Module() - with self.assertRaises(AttributeError, - msg="'Module' object has no attribute 'nonexistentattr'"): - m.nonexistentattr - - def test_If(self): - m = Module() - with m.If(self.s1): - m.d.comb += self.c1.eq(1) - m._flush() - self.assertRepr(m._statements, """ - ( - (switch (cat (sig s1)) - (case 1 (eq (sig c1) (const 1'd1))) - ) - ) - """) - - def test_If_Elif(self): - m = Module() - with m.If(self.s1): - m.d.comb += self.c1.eq(1) - with m.Elif(self.s2): - m.d.sync += self.c2.eq(0) - m._flush() - self.assertRepr(m._statements, """ - ( - (switch (cat (sig s1) (sig s2)) - (case -1 (eq (sig c1) (const 1'd1))) - (case 1- (eq (sig c2) (const 1'd0))) - ) - ) - """) - - def test_If_Elif_Else(self): - m = Module() - with m.If(self.s1): - m.d.comb += self.c1.eq(1) - with m.Elif(self.s2): - m.d.sync += self.c2.eq(0) - with m.Else(): - m.d.comb += self.c3.eq(1) - m._flush() - self.assertRepr(m._statements, """ - ( - (switch (cat (sig s1) (sig s2)) - (case -1 (eq (sig c1) (const 1'd1))) - (case 1- (eq (sig c2) (const 1'd0))) - (case -- (eq (sig c3) (const 1'd1))) - ) - ) - """) - - def test_If_If(self): - m = Module() - with m.If(self.s1): - m.d.comb += self.c1.eq(1) - with m.If(self.s2): - m.d.comb += self.c2.eq(1) - m._flush() - self.assertRepr(m._statements, """ - ( - (switch (cat (sig s1)) - (case 1 (eq (sig c1) (const 1'd1))) - ) - (switch (cat (sig s2)) - (case 1 (eq (sig c2) (const 1'd1))) - ) - ) - """) - - def test_If_nested_If(self): - m = Module() - with m.If(self.s1): - m.d.comb += self.c1.eq(1) - with m.If(self.s2): - m.d.comb += self.c2.eq(1) - m._flush() - self.assertRepr(m._statements, """ - ( - (switch (cat (sig s1)) - (case 1 (eq (sig c1) (const 1'd1)) - (switch (cat (sig s2)) - (case 1 (eq (sig c2) (const 1'd1))) - ) - ) - ) - ) - """) - - def test_If_dangling_Else(self): - m = Module() - with m.If(self.s1): - m.d.comb += self.c1.eq(1) - with m.If(self.s2): - m.d.comb += self.c2.eq(1) - with m.Else(): - m.d.comb += self.c3.eq(1) - m._flush() - self.assertRepr(m._statements, """ - ( - (switch (cat (sig s1)) - (case 1 - (eq (sig c1) (const 1'd1)) - (switch (cat (sig s2)) - (case 1 (eq (sig c2) (const 1'd1))) - ) - ) - (case - - (eq (sig c3) (const 1'd1)) - ) - ) - ) - """) - - def test_Elif_wrong(self): - m = Module() - with self.assertRaises(SyntaxError, - msg="Elif without preceding If"): - with m.Elif(self.s2): - pass - - def test_Else_wrong(self): - m = Module() - with self.assertRaises(SyntaxError, - msg="Else without preceding If/Elif"): - with m.Else(): - pass - - def test_If_wide(self): - m = Module() - with m.If(self.w1): - m.d.comb += self.c1.eq(1) - m._flush() - self.assertRepr(m._statements, """ - ( - (switch (cat (b (sig w1))) - (case 1 (eq (sig c1) (const 1'd1))) - ) - ) - """) - - def test_Switch(self): - m = Module() - with m.Switch(self.w1): - with m.Case(3): - m.d.comb += self.c1.eq(1) - with m.Case("11--"): - m.d.comb += self.c2.eq(1) - m._flush() - self.assertRepr(m._statements, """ - ( - (switch (sig w1) - (case 0011 (eq (sig c1) (const 1'd1))) - (case 11-- (eq (sig c2) (const 1'd1))) - ) - ) - """) - - def test_Switch_default(self): - m = Module() - with m.Switch(self.w1): - with m.Case(3): - m.d.comb += self.c1.eq(1) - with m.Case(): - m.d.comb += self.c2.eq(1) - m._flush() - self.assertRepr(m._statements, """ - ( - (switch (sig w1) - (case 0011 (eq (sig c1) (const 1'd1))) - (case ---- (eq (sig c2) (const 1'd1))) - ) - ) - """) - - def test_Switch_const_test(self): - m = Module() - with m.Switch(1): - with m.Case(1): - m.d.comb += self.c1.eq(1) - m._flush() - self.assertRepr(m._statements, """ - ( - (switch (const 1'd1) - (case 1 (eq (sig c1) (const 1'd1))) - ) - ) - """) - - def test_Case_width_wrong(self): - m = Module() - with m.Switch(self.w1): - with self.assertRaises(SyntaxError, - msg="Case value '--' must have the same width as test (which is 4)"): - with m.Case("--"): - pass - - def test_Case_outside_Switch_wrong(self): - m = Module() - with self.assertRaises(SyntaxError, - msg="Case is not permitted outside of Switch"): - with m.Case(): - pass - - def test_If_inside_Switch_wrong(self): - m = Module() - with m.Switch(self.s1): - with self.assertRaises(SyntaxError, - msg="If is not permitted inside of Switch"): - with m.If(self.s2): - pass - - def test_auto_pop_ctrl(self): - m = Module() - with m.If(self.w1): - m.d.comb += self.c1.eq(1) - m.d.comb += self.c2.eq(1) - self.assertRepr(m._statements, """ - ( - (switch (cat (b (sig w1))) - (case 1 (eq (sig c1) (const 1'd1))) - ) - (eq (sig c2) (const 1'd1)) - ) - """) - - def test_submodule_anon(self): - m1 = Module() - m2 = Module() - m1.submodules += m2 - self.assertEqual(m1._submodules, [(m2, None)]) - - def test_submodule_anon_multi(self): - m1 = Module() - m2 = Module() - m3 = Module() - m1.submodules += m2, m3 - self.assertEqual(m1._submodules, [(m2, None), (m3, None)]) - - def test_submodule_named(self): - m1 = Module() - m2 = Module() - m1.submodules.foo = m2 - self.assertEqual(m1._submodules, [(m2, "foo")]) - - def test_submodule_wrong(self): - m = Module() - with self.assertRaises(TypeError, - msg="Trying to add '1', which does not implement .get_fragment(), as a submodule"): - m.submodules.foo = 1 - with self.assertRaises(TypeError, - msg="Trying to add '1', which does not implement .get_fragment(), as a submodule"): - m.submodules += 1 - - def test_lower(self): - m1 = Module() - m1.d.comb += self.c1.eq(self.s1) - m2 = Module() - m2.d.comb += self.c2.eq(self.s2) - m2.d.sync += self.c3.eq(self.s3) - m1.submodules.foo = m2 - - f1 = m1.lower(platform=None) - self.assertRepr(f1.statements, """ - ( - (eq (sig c1) (sig s1)) - ) - """) - self.assertEqual(f1.drivers, { - None: ValueSet((self.c1,)) - }) - self.assertEqual(len(f1.subfragments), 1) - (f2, f2_name), = f1.subfragments - self.assertEqual(f2_name, "foo") - self.assertRepr(f2.statements, """ - ( - (eq (sig c2) (sig s2)) - (eq (sig c3) (sig s3)) - ) - """) - self.assertEqual(f2.drivers, { - None: ValueSet((self.c2,)), - "sync": ValueSet((self.c3,)) - }) - self.assertEqual(len(f2.subfragments), 0) diff --git a/nmigen/test/test_fhdl_ir.py b/nmigen/test/test_fhdl_ir.py deleted file mode 100644 index fcc1b2e..0000000 --- a/nmigen/test/test_fhdl_ir.py +++ /dev/null @@ -1,393 +0,0 @@ -from ..hdl.ast import * -from ..hdl.cd import * -from ..hdl.ir import * -from .tools import * - - -class FragmentDriversTestCase(FHDLTestCase): - def test_empty(self): - f = Fragment() - self.assertEqual(list(f.iter_comb()), []) - self.assertEqual(list(f.iter_sync()), []) - - -class FragmentPortsTestCase(FHDLTestCase): - def setUp(self): - self.s1 = Signal() - self.s2 = Signal() - self.s3 = Signal() - self.c1 = Signal() - self.c2 = Signal() - self.c3 = Signal() - - def test_empty(self): - f = Fragment() - self.assertEqual(list(f.iter_ports()), []) - - f._propagate_ports(ports=()) - self.assertEqual(f.ports, ValueDict([])) - - def test_iter_signals(self): - f = Fragment() - f.add_ports(self.s1, self.s2, kind="io") - self.assertEqual(ValueSet((self.s1, self.s2)), f.iter_signals()) - - def test_self_contained(self): - f = Fragment() - f.add_statements( - self.c1.eq(self.s1), - self.s1.eq(self.c1) - ) - - f._propagate_ports(ports=()) - self.assertEqual(f.ports, ValueDict([])) - - def test_infer_input(self): - f = Fragment() - f.add_statements( - self.c1.eq(self.s1) - ) - - f._propagate_ports(ports=()) - self.assertEqual(f.ports, ValueDict([ - (self.s1, "i") - ])) - - def test_request_output(self): - f = Fragment() - f.add_statements( - self.c1.eq(self.s1) - ) - - f._propagate_ports(ports=(self.c1,)) - self.assertEqual(f.ports, ValueDict([ - (self.s1, "i"), - (self.c1, "o") - ])) - - def test_input_in_subfragment(self): - f1 = Fragment() - f1.add_statements( - self.c1.eq(self.s1) - ) - f2 = Fragment() - f2.add_statements( - self.s1.eq(0) - ) - f1.add_subfragment(f2) - f1._propagate_ports(ports=()) - self.assertEqual(f1.ports, ValueDict()) - self.assertEqual(f2.ports, ValueDict([ - (self.s1, "o"), - ])) - - def test_input_only_in_subfragment(self): - f1 = Fragment() - f2 = Fragment() - f2.add_statements( - self.c1.eq(self.s1) - ) - f1.add_subfragment(f2) - f1._propagate_ports(ports=()) - self.assertEqual(f1.ports, ValueDict([ - (self.s1, "i"), - ])) - self.assertEqual(f2.ports, ValueDict([ - (self.s1, "i"), - ])) - - def test_output_from_subfragment(self): - f1 = Fragment() - f1.add_statements( - self.c1.eq(0) - ) - f2 = Fragment() - f2.add_statements( - self.c2.eq(1) - ) - f1.add_subfragment(f2) - - f1._propagate_ports(ports=(self.c2,)) - self.assertEqual(f1.ports, ValueDict([ - (self.c2, "o"), - ])) - self.assertEqual(f2.ports, ValueDict([ - (self.c2, "o"), - ])) - - def test_input_cd(self): - sync = ClockDomain() - f = Fragment() - f.add_statements( - self.c1.eq(self.s1) - ) - f.add_domains(sync) - f.add_driver(self.c1, "sync") - - f._propagate_ports(ports=()) - self.assertEqual(f.ports, ValueDict([ - (self.s1, "i"), - (sync.clk, "i"), - (sync.rst, "i"), - ])) - - def test_input_cd_reset_less(self): - sync = ClockDomain(reset_less=True) - f = Fragment() - f.add_statements( - self.c1.eq(self.s1) - ) - f.add_domains(sync) - f.add_driver(self.c1, "sync") - - f._propagate_ports(ports=()) - self.assertEqual(f.ports, ValueDict([ - (self.s1, "i"), - (sync.clk, "i"), - ])) - - -class FragmentDomainsTestCase(FHDLTestCase): - def test_iter_signals(self): - cd1 = ClockDomain() - cd2 = ClockDomain(reset_less=True) - s1 = Signal() - s2 = Signal() - - f = Fragment() - f.add_domains(cd1, cd2) - f.add_driver(s1, "cd1") - self.assertEqual(ValueSet((cd1.clk, cd1.rst, s1)), f.iter_signals()) - f.add_driver(s2, "cd2") - self.assertEqual(ValueSet((cd1.clk, cd1.rst, cd2.clk, s1, s2)), f.iter_signals()) - - def test_propagate_up(self): - cd = ClockDomain() - - f1 = Fragment() - f2 = Fragment() - f1.add_subfragment(f2) - f2.add_domains(cd) - - f1._propagate_domains_up() - self.assertEqual(f1.domains, {"cd": cd}) - - def test_domain_conflict(self): - cda = ClockDomain("sync") - cdb = ClockDomain("sync") - - fa = Fragment() - fa.add_domains(cda) - fb = Fragment() - fb.add_domains(cdb) - f = Fragment() - f.add_subfragment(fa, "a") - f.add_subfragment(fb, "b") - - f._propagate_domains_up() - self.assertEqual(f.domains, {"a_sync": cda, "b_sync": cdb}) - (fa, _), (fb, _) = f.subfragments - self.assertEqual(fa.domains, {"a_sync": cda}) - self.assertEqual(fb.domains, {"b_sync": cdb}) - - def test_domain_conflict_anon(self): - cda = ClockDomain("sync") - cdb = ClockDomain("sync") - - fa = Fragment() - fa.add_domains(cda) - fb = Fragment() - fb.add_domains(cdb) - f = Fragment() - f.add_subfragment(fa, "a") - f.add_subfragment(fb) - - with self.assertRaises(DomainError, - msg="Domain 'sync' is defined by subfragments 'a', of fragment " - "'top'; it is necessary to either rename subfragment domains explicitly, " - "or give names to subfragments"): - f._propagate_domains_up() - - def test_domain_conflict_name(self): - cda = ClockDomain("sync") - cdb = ClockDomain("sync") - - fa = Fragment() - fa.add_domains(cda) - fb = Fragment() - fb.add_domains(cdb) - f = Fragment() - f.add_subfragment(fa, "x") - f.add_subfragment(fb, "x") - - with self.assertRaises(DomainError, - msg="Domain 'sync' is defined by subfragments #0, #1 of fragment 'top', some " - "of which have identical names; it is necessary to either rename subfragment " - "domains explicitly, or give distinct names to subfragments"): - f._propagate_domains_up() - - def test_propagate_down(self): - cd = ClockDomain() - - f1 = Fragment() - f2 = Fragment() - f1.add_domains(cd) - f1.add_subfragment(f2) - - f1._propagate_domains_down() - self.assertEqual(f2.domains, {"cd": cd}) - - def test_propagate_down_idempotent(self): - cd = ClockDomain() - - f1 = Fragment() - f1.add_domains(cd) - f2 = Fragment() - f2.add_domains(cd) - f1.add_subfragment(f2) - - f1._propagate_domains_down() - self.assertEqual(f1.domains, {"cd": cd}) - self.assertEqual(f2.domains, {"cd": cd}) - - def test_propagate(self): - cd = ClockDomain() - - f1 = Fragment() - f2 = Fragment() - f1.add_domains(cd) - f1.add_subfragment(f2) - - f1._propagate_domains(ensure_sync_exists=False) - self.assertEqual(f1.domains, {"cd": cd}) - self.assertEqual(f2.domains, {"cd": cd}) - - def test_propagate_ensure_sync(self): - f1 = Fragment() - f2 = Fragment() - f1.add_subfragment(f2) - - f1._propagate_domains(ensure_sync_exists=True) - self.assertEqual(f1.domains.keys(), {"sync"}) - self.assertEqual(f2.domains.keys(), {"sync"}) - self.assertEqual(f1.domains["sync"], f2.domains["sync"]) - - -class FragmentDriverConflictTestCase(FHDLTestCase): - def setUp_self_sub(self): - self.s1 = Signal() - self.c1 = Signal() - self.c2 = Signal() - - self.f1 = Fragment() - self.f1.add_statements(self.c1.eq(0)) - self.f1.add_driver(self.s1) - self.f1.add_driver(self.c1, "sync") - - self.f1a = Fragment() - self.f1.add_subfragment(self.f1a, "f1a") - - self.f2 = Fragment() - self.f2.add_statements(self.c2.eq(1)) - self.f2.add_driver(self.s1) - self.f2.add_driver(self.c2, "sync") - self.f1.add_subfragment(self.f2) - - self.f1b = Fragment() - self.f1.add_subfragment(self.f1b, "f1b") - - self.f2a = Fragment() - self.f2.add_subfragment(self.f2a, "f2a") - - def test_conflict_self_sub(self): - self.setUp_self_sub() - - self.f1._resolve_driver_conflicts(mode="silent") - self.assertEqual(self.f1.subfragments, [ - (self.f1a, "f1a"), - (self.f1b, "f1b"), - (self.f2a, "f2a"), - ]) - self.assertRepr(self.f1.statements, """ - ( - (eq (sig c1) (const 1'd0)) - (eq (sig c2) (const 1'd1)) - ) - """) - self.assertEqual(self.f1.drivers, { - None: ValueSet((self.s1,)), - "sync": ValueSet((self.c1, self.c2)), - }) - - def test_conflict_self_sub_error(self): - self.setUp_self_sub() - - with self.assertRaises(DriverConflict, - msg="Signal '(sig s1)' is driven from multiple fragments: top, top."): - self.f1._resolve_driver_conflicts(mode="error") - - def test_conflict_self_sub_warning(self): - self.setUp_self_sub() - - with self.assertWarns(DriverConflict, - msg="Signal '(sig s1)' is driven from multiple fragments: top, top.; " - "hierarchy will be flattened"): - self.f1._resolve_driver_conflicts(mode="warn") - - def setUp_sub_sub(self): - self.s1 = Signal() - self.c1 = Signal() - self.c2 = Signal() - - self.f1 = Fragment() - - self.f2 = Fragment() - self.f2.add_driver(self.s1) - self.f2.add_statements(self.c1.eq(0)) - self.f1.add_subfragment(self.f2) - - self.f3 = Fragment() - self.f3.add_driver(self.s1) - self.f3.add_statements(self.c2.eq(1)) - self.f1.add_subfragment(self.f3) - - def test_conflict_sub_sub(self): - self.setUp_sub_sub() - - self.f1._resolve_driver_conflicts(mode="silent") - self.assertEqual(self.f1.subfragments, []) - self.assertRepr(self.f1.statements, """ - ( - (eq (sig c1) (const 1'd0)) - (eq (sig c2) (const 1'd1)) - ) - """) - - def setUp_self_subsub(self): - self.s1 = Signal() - self.c1 = Signal() - self.c2 = Signal() - - self.f1 = Fragment() - self.f1.add_driver(self.s1) - - self.f2 = Fragment() - self.f2.add_statements(self.c1.eq(0)) - self.f1.add_subfragment(self.f2) - - self.f3 = Fragment() - self.f3.add_driver(self.s1) - self.f3.add_statements(self.c2.eq(1)) - self.f2.add_subfragment(self.f3) - - def test_conflict_self_subsub(self): - self.setUp_self_subsub() - - self.f1._resolve_driver_conflicts(mode="silent") - self.assertEqual(self.f1.subfragments, []) - self.assertRepr(self.f1.statements, """ - ( - (eq (sig c1) (const 1'd0)) - (eq (sig c2) (const 1'd1)) - ) - """) diff --git a/nmigen/test/test_fhdl_xfrm.py b/nmigen/test/test_fhdl_xfrm.py deleted file mode 100644 index 428bad7..0000000 --- a/nmigen/test/test_fhdl_xfrm.py +++ /dev/null @@ -1,316 +0,0 @@ -from ..hdl.ast import * -from ..hdl.cd import * -from ..hdl.ir import * -from ..hdl.xfrm import * -from .tools import * - - -class DomainRenamerTestCase(FHDLTestCase): - def setUp(self): - self.s1 = Signal() - self.s2 = Signal() - self.s3 = Signal() - self.s4 = Signal() - self.s5 = Signal() - self.c1 = Signal() - - def test_rename_signals(self): - f = Fragment() - f.add_statements( - self.s1.eq(ClockSignal()), - ResetSignal().eq(self.s2), - self.s3.eq(0), - self.s4.eq(ClockSignal("other")), - self.s5.eq(ResetSignal("other")), - ) - f.add_driver(self.s1, None) - f.add_driver(self.s2, None) - f.add_driver(self.s3, "sync") - - f = DomainRenamer("pix")(f) - self.assertRepr(f.statements, """ - ( - (eq (sig s1) (clk pix)) - (eq (rst pix) (sig s2)) - (eq (sig s3) (const 1'd0)) - (eq (sig s4) (clk other)) - (eq (sig s5) (rst other)) - ) - """) - self.assertEqual(f.drivers, { - None: ValueSet((self.s1, self.s2)), - "pix": ValueSet((self.s3,)), - }) - - def test_rename_multi(self): - f = Fragment() - f.add_statements( - self.s1.eq(ClockSignal()), - self.s2.eq(ResetSignal("other")), - ) - - f = DomainRenamer({"sync": "pix", "other": "pix2"})(f) - self.assertRepr(f.statements, """ - ( - (eq (sig s1) (clk pix)) - (eq (sig s2) (rst pix2)) - ) - """) - - def test_rename_cd(self): - cd_sync = ClockDomain() - cd_pix = ClockDomain() - - f = Fragment() - f.add_domains(cd_sync, cd_pix) - - f = DomainRenamer("ext")(f) - self.assertEqual(cd_sync.name, "ext") - self.assertEqual(f.domains, { - "ext": cd_sync, - "pix": cd_pix, - }) - - def test_rename_cd_subfragment(self): - cd_sync = ClockDomain() - cd_pix = ClockDomain() - - f1 = Fragment() - f1.add_domains(cd_sync, cd_pix) - f2 = Fragment() - f2.add_domains(cd_sync) - f1.add_subfragment(f2) - - f1 = DomainRenamer("ext")(f1) - self.assertEqual(cd_sync.name, "ext") - self.assertEqual(f1.domains, { - "ext": cd_sync, - "pix": cd_pix, - }) - - -class DomainLowererTestCase(FHDLTestCase): - def setUp(self): - self.s = Signal() - - def test_lower_clk(self): - sync = ClockDomain() - f = Fragment() - f.add_statements( - self.s.eq(ClockSignal("sync")) - ) - - f = DomainLowerer({"sync": sync})(f) - self.assertRepr(f.statements, """ - ( - (eq (sig s) (sig clk)) - ) - """) - - def test_lower_rst(self): - sync = ClockDomain() - f = Fragment() - f.add_statements( - self.s.eq(ResetSignal("sync")) - ) - - f = DomainLowerer({"sync": sync})(f) - self.assertRepr(f.statements, """ - ( - (eq (sig s) (sig rst)) - ) - """) - - def test_lower_rst_reset_less(self): - sync = ClockDomain(reset_less=True) - f = Fragment() - f.add_statements( - self.s.eq(ResetSignal("sync", allow_reset_less=True)) - ) - - f = DomainLowerer({"sync": sync})(f) - self.assertRepr(f.statements, """ - ( - (eq (sig s) (const 1'd0)) - ) - """) - - def test_lower_wrong_domain(self): - sync = ClockDomain() - f = Fragment() - f.add_statements( - self.s.eq(ClockSignal("xxx")) - ) - - with self.assertRaises(DomainError, - msg="Signal (clk xxx) refers to nonexistent domain 'xxx'"): - DomainLowerer({"sync": sync})(f) - - def test_lower_wrong_reset_less_domain(self): - sync = ClockDomain(reset_less=True) - f = Fragment() - f.add_statements( - self.s.eq(ResetSignal("sync")) - ) - - with self.assertRaises(DomainError, - msg="Signal (rst sync) refers to reset of reset-less domain 'sync'"): - DomainLowerer({"sync": sync})(f) - - -class ResetInserterTestCase(FHDLTestCase): - def setUp(self): - self.s1 = Signal() - self.s2 = Signal(reset=1) - self.s3 = Signal(reset=1, reset_less=True) - self.c1 = Signal() - - def test_reset_default(self): - f = Fragment() - f.add_statements( - self.s1.eq(1) - ) - f.add_driver(self.s1, "sync") - - f = ResetInserter(self.c1)(f) - self.assertRepr(f.statements, """ - ( - (eq (sig s1) (const 1'd1)) - (switch (sig c1) - (case 1 (eq (sig s1) (const 1'd0))) - ) - ) - """) - - def test_reset_cd(self): - f = Fragment() - f.add_statements( - self.s1.eq(1), - self.s2.eq(0), - ) - f.add_domains(ClockDomain("sync")) - f.add_driver(self.s1, "sync") - f.add_driver(self.s2, "pix") - - f = ResetInserter({"pix": self.c1})(f) - self.assertRepr(f.statements, """ - ( - (eq (sig s1) (const 1'd1)) - (eq (sig s2) (const 1'd0)) - (switch (sig c1) - (case 1 (eq (sig s2) (const 1'd1))) - ) - ) - """) - - def test_reset_value(self): - f = Fragment() - f.add_statements( - self.s2.eq(0) - ) - f.add_driver(self.s2, "sync") - - f = ResetInserter(self.c1)(f) - self.assertRepr(f.statements, """ - ( - (eq (sig s2) (const 1'd0)) - (switch (sig c1) - (case 1 (eq (sig s2) (const 1'd1))) - ) - ) - """) - - def test_reset_less(self): - f = Fragment() - f.add_statements( - self.s3.eq(0) - ) - f.add_driver(self.s3, "sync") - - f = ResetInserter(self.c1)(f) - self.assertRepr(f.statements, """ - ( - (eq (sig s3) (const 1'd0)) - (switch (sig c1) - (case 1 ) - ) - ) - """) - - -class CEInserterTestCase(FHDLTestCase): - def setUp(self): - self.s1 = Signal() - self.s2 = Signal() - self.s3 = Signal() - self.c1 = Signal() - - def test_ce_default(self): - f = Fragment() - f.add_statements( - self.s1.eq(1) - ) - f.add_driver(self.s1, "sync") - - f = CEInserter(self.c1)(f) - self.assertRepr(f.statements, """ - ( - (eq (sig s1) (const 1'd1)) - (switch (sig c1) - (case 0 (eq (sig s1) (sig s1))) - ) - ) - """) - - def test_ce_cd(self): - f = Fragment() - f.add_statements( - self.s1.eq(1), - self.s2.eq(0), - ) - f.add_driver(self.s1, "sync") - f.add_driver(self.s2, "pix") - - f = CEInserter({"pix": self.c1})(f) - self.assertRepr(f.statements, """ - ( - (eq (sig s1) (const 1'd1)) - (eq (sig s2) (const 1'd0)) - (switch (sig c1) - (case 0 (eq (sig s2) (sig s2))) - ) - ) - """) - - def test_ce_subfragment(self): - f1 = Fragment() - f1.add_statements( - self.s1.eq(1) - ) - f1.add_driver(self.s1, "sync") - - f2 = Fragment() - f2.add_statements( - self.s2.eq(1) - ) - f2.add_driver(self.s2, "sync") - f1.add_subfragment(f2) - - f1 = CEInserter(self.c1)(f1) - (f2, _), = f1.subfragments - self.assertRepr(f1.statements, """ - ( - (eq (sig s1) (const 1'd1)) - (switch (sig c1) - (case 0 (eq (sig s1) (sig s1))) - ) - ) - """) - self.assertRepr(f2.statements, """ - ( - (eq (sig s2) (const 1'd1)) - (switch (sig c1) - (case 0 (eq (sig s2) (sig s2))) - ) - ) - """) diff --git a/nmigen/test/test_hdl_ast.py b/nmigen/test/test_hdl_ast.py new file mode 100644 index 0000000..0fde4c6 --- /dev/null +++ b/nmigen/test/test_hdl_ast.py @@ -0,0 +1,436 @@ +from ..hdl.ast import * +from .tools import * + + +class ValueTestCase(FHDLTestCase): + def test_wrap(self): + self.assertIsInstance(Value.wrap(0), Const) + self.assertIsInstance(Value.wrap(True), Const) + c = Const(0) + self.assertIs(Value.wrap(c), c) + with self.assertRaises(TypeError): + Value.wrap("str") + + def test_bool(self): + with self.assertRaises(TypeError): + if Const(0): + pass + + def test_len(self): + self.assertEqual(len(Const(10)), 4) + + def test_getitem_int(self): + s1 = Const(10)[0] + self.assertIsInstance(s1, Slice) + self.assertEqual(s1.start, 0) + self.assertEqual(s1.end, 1) + s2 = Const(10)[-1] + self.assertIsInstance(s2, Slice) + self.assertEqual(s2.start, 3) + self.assertEqual(s2.end, 4) + with self.assertRaises(IndexError): + Const(10)[5] + + def test_getitem_slice(self): + s1 = Const(10)[1:3] + self.assertIsInstance(s1, Slice) + self.assertEqual(s1.start, 1) + self.assertEqual(s1.end, 3) + s2 = Const(10)[1:-2] + self.assertIsInstance(s2, Slice) + self.assertEqual(s2.start, 1) + self.assertEqual(s2.end, 2) + s3 = Const(31)[::2] + self.assertIsInstance(s3, Cat) + self.assertIsInstance(s3.operands[0], Slice) + self.assertEqual(s3.operands[0].start, 0) + self.assertEqual(s3.operands[0].end, 1) + self.assertIsInstance(s3.operands[1], Slice) + self.assertEqual(s3.operands[1].start, 2) + self.assertEqual(s3.operands[1].end, 3) + self.assertIsInstance(s3.operands[2], Slice) + self.assertEqual(s3.operands[2].start, 4) + self.assertEqual(s3.operands[2].end, 5) + + def test_getitem_wrong(self): + with self.assertRaises(TypeError): + Const(31)["str"] + + +class ConstTestCase(FHDLTestCase): + def test_shape(self): + self.assertEqual(Const(0).shape(), (1, False)) + self.assertEqual(Const(1).shape(), (1, False)) + 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(0, (0, False)).shape(), (0, False)) + + def test_shape_bad(self): + with self.assertRaises(TypeError): + Const(1, -1) + + def test_normalization(self): + self.assertEqual(Const(0b10110, (5, True)).value, -10) + + def test_value(self): + self.assertEqual(Const(10).value, 10) + + def test_repr(self): + self.assertEqual(repr(Const(10)), "(const 4'd10)") + self.assertEqual(repr(Const(-10)), "(const 5'sd-10)") + + def test_hash(self): + with self.assertRaises(TypeError): + hash(Const(0)) + + +class OperatorTestCase(FHDLTestCase): + def test_bool(self): + v = Const(0, 4).bool() + self.assertEqual(repr(v), "(b (const 4'd0))") + self.assertEqual(v.shape(), (1, False)) + + def test_invert(self): + v = ~Const(0, 4) + self.assertEqual(repr(v), "(~ (const 4'd0))") + self.assertEqual(v.shape(), (4, False)) + + def test_neg(self): + v1 = -Const(0, (4, False)) + self.assertEqual(repr(v1), "(- (const 4'd0))") + self.assertEqual(v1.shape(), (5, True)) + v2 = -Const(0, (4, True)) + self.assertEqual(repr(v2), "(- (const 4'sd0))") + self.assertEqual(v2.shape(), (4, True)) + + def test_add(self): + v1 = Const(0, (4, False)) + Const(0, (6, False)) + self.assertEqual(repr(v1), "(+ (const 4'd0) (const 6'd0))") + self.assertEqual(v1.shape(), (7, False)) + v2 = Const(0, (4, True)) + Const(0, (6, True)) + self.assertEqual(v2.shape(), (7, True)) + v3 = Const(0, (4, True)) + Const(0, (4, False)) + self.assertEqual(v3.shape(), (6, True)) + v4 = Const(0, (4, False)) + Const(0, (4, True)) + self.assertEqual(v4.shape(), (6, True)) + v5 = 10 + Const(0, 4) + self.assertEqual(v5.shape(), (5, False)) + + def test_sub(self): + v1 = Const(0, (4, False)) - Const(0, (6, False)) + self.assertEqual(repr(v1), "(- (const 4'd0) (const 6'd0))") + self.assertEqual(v1.shape(), (7, False)) + v2 = Const(0, (4, True)) - Const(0, (6, True)) + self.assertEqual(v2.shape(), (7, True)) + v3 = Const(0, (4, True)) - Const(0, (4, False)) + self.assertEqual(v3.shape(), (6, True)) + v4 = Const(0, (4, False)) - Const(0, (4, True)) + self.assertEqual(v4.shape(), (6, True)) + v5 = 10 - Const(0, 4) + self.assertEqual(v5.shape(), (5, False)) + + def test_mul(self): + v1 = Const(0, (4, False)) * Const(0, (6, False)) + self.assertEqual(repr(v1), "(* (const 4'd0) (const 6'd0))") + self.assertEqual(v1.shape(), (10, False)) + v2 = Const(0, (4, True)) * Const(0, (6, True)) + self.assertEqual(v2.shape(), (9, True)) + v3 = Const(0, (4, True)) * Const(0, (4, False)) + self.assertEqual(v3.shape(), (8, True)) + v5 = 10 * Const(0, 4) + self.assertEqual(v5.shape(), (8, False)) + + def test_and(self): + v1 = Const(0, (4, False)) & Const(0, (6, False)) + self.assertEqual(repr(v1), "(& (const 4'd0) (const 6'd0))") + self.assertEqual(v1.shape(), (6, False)) + v2 = Const(0, (4, True)) & Const(0, (6, True)) + self.assertEqual(v2.shape(), (6, True)) + v3 = Const(0, (4, True)) & Const(0, (4, False)) + self.assertEqual(v3.shape(), (5, True)) + v4 = Const(0, (4, False)) & Const(0, (4, True)) + self.assertEqual(v4.shape(), (5, True)) + v5 = 10 & Const(0, 4) + self.assertEqual(v5.shape(), (4, False)) + + def test_or(self): + v1 = Const(0, (4, False)) | Const(0, (6, False)) + self.assertEqual(repr(v1), "(| (const 4'd0) (const 6'd0))") + self.assertEqual(v1.shape(), (6, False)) + v2 = Const(0, (4, True)) | Const(0, (6, True)) + self.assertEqual(v2.shape(), (6, True)) + v3 = Const(0, (4, True)) | Const(0, (4, False)) + self.assertEqual(v3.shape(), (5, True)) + v4 = Const(0, (4, False)) | Const(0, (4, True)) + self.assertEqual(v4.shape(), (5, True)) + v5 = 10 | Const(0, 4) + self.assertEqual(v5.shape(), (4, False)) + + def test_xor(self): + v1 = Const(0, (4, False)) ^ Const(0, (6, False)) + self.assertEqual(repr(v1), "(^ (const 4'd0) (const 6'd0))") + self.assertEqual(v1.shape(), (6, False)) + v2 = Const(0, (4, True)) ^ Const(0, (6, True)) + self.assertEqual(v2.shape(), (6, True)) + v3 = Const(0, (4, True)) ^ Const(0, (4, False)) + self.assertEqual(v3.shape(), (5, True)) + v4 = Const(0, (4, False)) ^ Const(0, (4, True)) + self.assertEqual(v4.shape(), (5, True)) + v5 = 10 ^ Const(0, 4) + self.assertEqual(v5.shape(), (4, False)) + + def test_shl(self): + v1 = Const(1, 4) << Const(4) + self.assertEqual(repr(v1), "(<< (const 4'd1) (const 3'd4))") + self.assertEqual(v1.shape(), (11, False)) + v2 = Const(1, 4) << Const(-3) + self.assertEqual(v2.shape(), (7, False)) + + def test_shr(self): + v1 = Const(1, 4) >> Const(4) + self.assertEqual(repr(v1), "(>> (const 4'd1) (const 3'd4))") + self.assertEqual(v1.shape(), (4, False)) + v2 = Const(1, 4) >> Const(-3) + self.assertEqual(v2.shape(), (8, False)) + + def test_lt(self): + v = Const(0, 4) < Const(0, 6) + self.assertEqual(repr(v), "(< (const 4'd0) (const 6'd0))") + self.assertEqual(v.shape(), (1, False)) + + def test_le(self): + v = Const(0, 4) <= Const(0, 6) + self.assertEqual(repr(v), "(<= (const 4'd0) (const 6'd0))") + self.assertEqual(v.shape(), (1, False)) + + def test_gt(self): + v = Const(0, 4) > Const(0, 6) + self.assertEqual(repr(v), "(> (const 4'd0) (const 6'd0))") + self.assertEqual(v.shape(), (1, False)) + + def test_ge(self): + v = Const(0, 4) >= Const(0, 6) + self.assertEqual(repr(v), "(>= (const 4'd0) (const 6'd0))") + self.assertEqual(v.shape(), (1, False)) + + def test_eq(self): + v = Const(0, 4) == Const(0, 6) + self.assertEqual(repr(v), "(== (const 4'd0) (const 6'd0))") + self.assertEqual(v.shape(), (1, False)) + + def test_ne(self): + v = Const(0, 4) != Const(0, 6) + self.assertEqual(repr(v), "(!= (const 4'd0) (const 6'd0))") + self.assertEqual(v.shape(), (1, False)) + + def test_mux(self): + s = Const(0) + v1 = Mux(s, Const(0, (4, False)), Const(0, (6, False))) + self.assertEqual(repr(v1), "(m (const 1'd0) (const 4'd0) (const 6'd0))") + self.assertEqual(v1.shape(), (6, False)) + v2 = Mux(s, Const(0, (4, True)), Const(0, (6, True))) + self.assertEqual(v2.shape(), (6, True)) + v3 = Mux(s, Const(0, (4, True)), Const(0, (4, False))) + self.assertEqual(v3.shape(), (5, True)) + v4 = Mux(s, Const(0, (4, False)), Const(0, (4, True))) + self.assertEqual(v4.shape(), (5, True)) + + def test_bool(self): + v = Const(0).bool() + self.assertEqual(repr(v), "(b (const 1'd0))") + self.assertEqual(v.shape(), (1, False)) + + def test_hash(self): + with self.assertRaises(TypeError): + hash(Const(0) + Const(0)) + + +class SliceTestCase(FHDLTestCase): + def test_shape(self): + s1 = Const(10)[2] + self.assertEqual(s1.shape(), (1, False)) + 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)) + self.assertEqual(c1.shape(), (4, False)) + c2 = Cat(Const(10), Const(1)) + self.assertEqual(c2.shape(), (5, False)) + c3 = Cat(Const(10), Const(1), Const(0)) + self.assertEqual(c3.shape(), (6, False)) + + def test_repr(self): + c1 = Cat(Const(10), Const(1)) + self.assertEqual(repr(c1), "(cat (const 4'd10) (const 1'd1))") + + +class ReplTestCase(FHDLTestCase): + def test_shape(self): + 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): + Repl(Const(10), -1) + with self.assertRaises(TypeError): + Repl(Const(10), "str") + + def test_repr(self): + s = Repl(Const(10), 3) + self.assertEqual(repr(s), "(repl (const 4'd10) 3)") + + +class SignalTestCase(FHDLTestCase): + def test_shape(self): + s1 = Signal() + self.assertEqual(s1.shape(), (1, False)) + s2 = Signal(2) + self.assertEqual(s2.shape(), (2, False)) + s3 = Signal((2, False)) + self.assertEqual(s3.shape(), (2, False)) + s4 = Signal((2, True)) + self.assertEqual(s4.shape(), (2, True)) + s5 = Signal(max=16) + self.assertEqual(s5.shape(), (4, False)) + s6 = Signal(min=4, max=16) + self.assertEqual(s6.shape(), (4, False)) + s7 = Signal(min=-4, max=16) + 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): + Signal(2, min=10) + with self.assertRaises(TypeError): + Signal(-10) + + def test_name(self): + s1 = Signal() + self.assertEqual(s1.name, "s1") + s2 = Signal(name="sig") + self.assertEqual(s2.name, "sig") + + def test_reset(self): + s1 = Signal(4, reset=0b111, reset_less=True) + self.assertEqual(s1.reset, 0b111) + self.assertEqual(s1.reset_less, True) + + def test_attrs(self): + s1 = Signal() + self.assertEqual(s1.attrs, {}) + s2 = Signal(attrs={"no_retiming": True}) + self.assertEqual(s2.attrs, {"no_retiming": True}) + + def test_repr(self): + s1 = Signal() + self.assertEqual(repr(s1), "(sig s1)") + + def test_like(self): + s1 = Signal.like(Signal(4)) + self.assertEqual(s1.shape(), (4, False)) + s2 = Signal.like(Signal(min=-15)) + self.assertEqual(s2.shape(), (5, True)) + s3 = Signal.like(Signal(4, reset=0b111, reset_less=True)) + self.assertEqual(s3.reset, 0b111) + self.assertEqual(s3.reset_less, True) + s4 = Signal.like(Signal(attrs={"no_retiming": True})) + self.assertEqual(s4.attrs, {"no_retiming": True}) + s5 = Signal.like(Signal(decoder=str)) + self.assertEqual(s5.decoder, str) + s6 = Signal.like(10) + self.assertEqual(s6.shape(), (4, False)) + + +class ClockSignalTestCase(FHDLTestCase): + def test_domain(self): + s1 = ClockSignal() + self.assertEqual(s1.domain, "sync") + s2 = ClockSignal("pix") + self.assertEqual(s2.domain, "pix") + + 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)") + + +class ResetSignalTestCase(FHDLTestCase): + def test_domain(self): + s1 = ResetSignal() + self.assertEqual(s1.domain, "sync") + s2 = ResetSignal("pix") + self.assertEqual(s2.domain, "pix") + + 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)") diff --git a/nmigen/test/test_hdl_cd.py b/nmigen/test/test_hdl_cd.py new file mode 100644 index 0000000..8e7dcdf --- /dev/null +++ b/nmigen/test/test_hdl_cd.py @@ -0,0 +1,57 @@ +from ..hdl.cd import * +from .tools import * + + +class ClockDomainCase(FHDLTestCase): + def test_name(self): + sync = ClockDomain() + self.assertEqual(sync.name, "sync") + self.assertEqual(sync.clk.name, "clk") + self.assertEqual(sync.rst.name, "rst") + pix = ClockDomain() + self.assertEqual(pix.name, "pix") + self.assertEqual(pix.clk.name, "pix_clk") + self.assertEqual(pix.rst.name, "pix_rst") + cd_pix = ClockDomain() + self.assertEqual(pix.name, "pix") + dom = [ClockDomain("foo")][0] + self.assertEqual(dom.name, "foo") + with self.assertRaises(ValueError, + msg="Clock domain name must be specified explicitly"): + ClockDomain() + + def test_with_reset(self): + pix = ClockDomain() + self.assertIsNotNone(pix.clk) + self.assertIsNotNone(pix.rst) + self.assertFalse(pix.async_reset) + + def test_without_reset(self): + pix = ClockDomain(reset_less=True) + self.assertIsNotNone(pix.clk) + self.assertIsNone(pix.rst) + self.assertFalse(pix.async_reset) + + def test_async_reset(self): + pix = ClockDomain(async_reset=True) + self.assertIsNotNone(pix.clk) + self.assertIsNotNone(pix.rst) + self.assertTrue(pix.async_reset) + + def test_rename(self): + sync = ClockDomain() + self.assertEqual(sync.name, "sync") + self.assertEqual(sync.clk.name, "clk") + self.assertEqual(sync.rst.name, "rst") + sync.rename("pix") + self.assertEqual(sync.name, "pix") + self.assertEqual(sync.clk.name, "pix_clk") + self.assertEqual(sync.rst.name, "pix_rst") + + def test_rename_reset_less(self): + sync = ClockDomain(reset_less=True) + self.assertEqual(sync.name, "sync") + self.assertEqual(sync.clk.name, "clk") + sync.rename("pix") + self.assertEqual(sync.name, "pix") + self.assertEqual(sync.clk.name, "pix_clk") diff --git a/nmigen/test/test_hdl_dsl.py b/nmigen/test/test_hdl_dsl.py new file mode 100644 index 0000000..f156880 --- /dev/null +++ b/nmigen/test/test_hdl_dsl.py @@ -0,0 +1,375 @@ +from ..hdl.ast import * +from ..hdl.dsl import * +from .tools import * + + +class DSLTestCase(FHDLTestCase): + def setUp(self): + self.s1 = Signal() + self.s2 = Signal() + self.s3 = Signal() + self.c1 = Signal() + self.c2 = Signal() + self.c3 = Signal() + self.w1 = Signal(4) + + def test_d_comb(self): + m = Module() + m.d.comb += self.c1.eq(1) + m._flush() + self.assertEqual(m._driving[self.c1], None) + self.assertRepr(m._statements, """( + (eq (sig c1) (const 1'd1)) + )""") + + def test_d_sync(self): + m = Module() + m.d.sync += self.c1.eq(1) + m._flush() + self.assertEqual(m._driving[self.c1], "sync") + self.assertRepr(m._statements, """( + (eq (sig c1) (const 1'd1)) + )""") + + def test_d_pix(self): + m = Module() + m.d.pix += self.c1.eq(1) + m._flush() + self.assertEqual(m._driving[self.c1], "pix") + self.assertRepr(m._statements, """( + (eq (sig c1) (const 1'd1)) + )""") + + def test_d_index(self): + m = Module() + m.d["pix"] += self.c1.eq(1) + m._flush() + self.assertEqual(m._driving[self.c1], "pix") + self.assertRepr(m._statements, """( + (eq (sig c1) (const 1'd1)) + )""") + + def test_d_no_conflict(self): + m = Module() + m.d.comb += self.w1[0].eq(1) + m.d.comb += self.w1[1].eq(1) + + def test_d_conflict(self): + m = Module() + with self.assertRaises(SyntaxError, + msg="Driver-driver conflict: trying to drive (sig c1) from d.sync, but it " + "is already driven from d.comb"): + m.d.comb += self.c1.eq(1) + m.d.sync += self.c1.eq(1) + + def test_d_wrong(self): + m = Module() + with self.assertRaises(AttributeError, + msg="Cannot assign 'd.pix' attribute; did you mean 'd.pix +='?"): + m.d.pix = None + + def test_d_asgn_wrong(self): + m = Module() + with self.assertRaises(SyntaxError, + msg="Only assignments may be appended to d.sync"): + m.d.sync += Switch(self.s1, {}) + + def test_comb_wrong(self): + m = Module() + with self.assertRaises(AttributeError, + msg="'Module' object has no attribute 'comb'; did you mean 'd.comb'?"): + m.comb += self.c1.eq(1) + + def test_sync_wrong(self): + m = Module() + with self.assertRaises(AttributeError, + msg="'Module' object has no attribute 'sync'; did you mean 'd.sync'?"): + m.sync += self.c1.eq(1) + + def test_attr_wrong(self): + m = Module() + with self.assertRaises(AttributeError, + msg="'Module' object has no attribute 'nonexistentattr'"): + m.nonexistentattr + + def test_If(self): + m = Module() + with m.If(self.s1): + m.d.comb += self.c1.eq(1) + m._flush() + self.assertRepr(m._statements, """ + ( + (switch (cat (sig s1)) + (case 1 (eq (sig c1) (const 1'd1))) + ) + ) + """) + + def test_If_Elif(self): + m = Module() + with m.If(self.s1): + m.d.comb += self.c1.eq(1) + with m.Elif(self.s2): + m.d.sync += self.c2.eq(0) + m._flush() + self.assertRepr(m._statements, """ + ( + (switch (cat (sig s1) (sig s2)) + (case -1 (eq (sig c1) (const 1'd1))) + (case 1- (eq (sig c2) (const 1'd0))) + ) + ) + """) + + def test_If_Elif_Else(self): + m = Module() + with m.If(self.s1): + m.d.comb += self.c1.eq(1) + with m.Elif(self.s2): + m.d.sync += self.c2.eq(0) + with m.Else(): + m.d.comb += self.c3.eq(1) + m._flush() + self.assertRepr(m._statements, """ + ( + (switch (cat (sig s1) (sig s2)) + (case -1 (eq (sig c1) (const 1'd1))) + (case 1- (eq (sig c2) (const 1'd0))) + (case -- (eq (sig c3) (const 1'd1))) + ) + ) + """) + + def test_If_If(self): + m = Module() + with m.If(self.s1): + m.d.comb += self.c1.eq(1) + with m.If(self.s2): + m.d.comb += self.c2.eq(1) + m._flush() + self.assertRepr(m._statements, """ + ( + (switch (cat (sig s1)) + (case 1 (eq (sig c1) (const 1'd1))) + ) + (switch (cat (sig s2)) + (case 1 (eq (sig c2) (const 1'd1))) + ) + ) + """) + + def test_If_nested_If(self): + m = Module() + with m.If(self.s1): + m.d.comb += self.c1.eq(1) + with m.If(self.s2): + m.d.comb += self.c2.eq(1) + m._flush() + self.assertRepr(m._statements, """ + ( + (switch (cat (sig s1)) + (case 1 (eq (sig c1) (const 1'd1)) + (switch (cat (sig s2)) + (case 1 (eq (sig c2) (const 1'd1))) + ) + ) + ) + ) + """) + + def test_If_dangling_Else(self): + m = Module() + with m.If(self.s1): + m.d.comb += self.c1.eq(1) + with m.If(self.s2): + m.d.comb += self.c2.eq(1) + with m.Else(): + m.d.comb += self.c3.eq(1) + m._flush() + self.assertRepr(m._statements, """ + ( + (switch (cat (sig s1)) + (case 1 + (eq (sig c1) (const 1'd1)) + (switch (cat (sig s2)) + (case 1 (eq (sig c2) (const 1'd1))) + ) + ) + (case - + (eq (sig c3) (const 1'd1)) + ) + ) + ) + """) + + def test_Elif_wrong(self): + m = Module() + with self.assertRaises(SyntaxError, + msg="Elif without preceding If"): + with m.Elif(self.s2): + pass + + def test_Else_wrong(self): + m = Module() + with self.assertRaises(SyntaxError, + msg="Else without preceding If/Elif"): + with m.Else(): + pass + + def test_If_wide(self): + m = Module() + with m.If(self.w1): + m.d.comb += self.c1.eq(1) + m._flush() + self.assertRepr(m._statements, """ + ( + (switch (cat (b (sig w1))) + (case 1 (eq (sig c1) (const 1'd1))) + ) + ) + """) + + def test_Switch(self): + m = Module() + with m.Switch(self.w1): + with m.Case(3): + m.d.comb += self.c1.eq(1) + with m.Case("11--"): + m.d.comb += self.c2.eq(1) + m._flush() + self.assertRepr(m._statements, """ + ( + (switch (sig w1) + (case 0011 (eq (sig c1) (const 1'd1))) + (case 11-- (eq (sig c2) (const 1'd1))) + ) + ) + """) + + def test_Switch_default(self): + m = Module() + with m.Switch(self.w1): + with m.Case(3): + m.d.comb += self.c1.eq(1) + with m.Case(): + m.d.comb += self.c2.eq(1) + m._flush() + self.assertRepr(m._statements, """ + ( + (switch (sig w1) + (case 0011 (eq (sig c1) (const 1'd1))) + (case ---- (eq (sig c2) (const 1'd1))) + ) + ) + """) + + def test_Switch_const_test(self): + m = Module() + with m.Switch(1): + with m.Case(1): + m.d.comb += self.c1.eq(1) + m._flush() + self.assertRepr(m._statements, """ + ( + (switch (const 1'd1) + (case 1 (eq (sig c1) (const 1'd1))) + ) + ) + """) + + def test_Case_width_wrong(self): + m = Module() + with m.Switch(self.w1): + with self.assertRaises(SyntaxError, + msg="Case value '--' must have the same width as test (which is 4)"): + with m.Case("--"): + pass + + def test_Case_outside_Switch_wrong(self): + m = Module() + with self.assertRaises(SyntaxError, + msg="Case is not permitted outside of Switch"): + with m.Case(): + pass + + def test_If_inside_Switch_wrong(self): + m = Module() + with m.Switch(self.s1): + with self.assertRaises(SyntaxError, + msg="If is not permitted inside of Switch"): + with m.If(self.s2): + pass + + def test_auto_pop_ctrl(self): + m = Module() + with m.If(self.w1): + m.d.comb += self.c1.eq(1) + m.d.comb += self.c2.eq(1) + self.assertRepr(m._statements, """ + ( + (switch (cat (b (sig w1))) + (case 1 (eq (sig c1) (const 1'd1))) + ) + (eq (sig c2) (const 1'd1)) + ) + """) + + def test_submodule_anon(self): + m1 = Module() + m2 = Module() + m1.submodules += m2 + self.assertEqual(m1._submodules, [(m2, None)]) + + def test_submodule_anon_multi(self): + m1 = Module() + m2 = Module() + m3 = Module() + m1.submodules += m2, m3 + self.assertEqual(m1._submodules, [(m2, None), (m3, None)]) + + def test_submodule_named(self): + m1 = Module() + m2 = Module() + m1.submodules.foo = m2 + self.assertEqual(m1._submodules, [(m2, "foo")]) + + def test_submodule_wrong(self): + m = Module() + with self.assertRaises(TypeError, + msg="Trying to add '1', which does not implement .get_fragment(), as a submodule"): + m.submodules.foo = 1 + with self.assertRaises(TypeError, + msg="Trying to add '1', which does not implement .get_fragment(), as a submodule"): + m.submodules += 1 + + def test_lower(self): + m1 = Module() + m1.d.comb += self.c1.eq(self.s1) + m2 = Module() + m2.d.comb += self.c2.eq(self.s2) + m2.d.sync += self.c3.eq(self.s3) + m1.submodules.foo = m2 + + f1 = m1.lower(platform=None) + self.assertRepr(f1.statements, """ + ( + (eq (sig c1) (sig s1)) + ) + """) + self.assertEqual(f1.drivers, { + None: ValueSet((self.c1,)) + }) + self.assertEqual(len(f1.subfragments), 1) + (f2, f2_name), = f1.subfragments + self.assertEqual(f2_name, "foo") + self.assertRepr(f2.statements, """ + ( + (eq (sig c2) (sig s2)) + (eq (sig c3) (sig s3)) + ) + """) + self.assertEqual(f2.drivers, { + None: ValueSet((self.c2,)), + "sync": ValueSet((self.c3,)) + }) + self.assertEqual(len(f2.subfragments), 0) diff --git a/nmigen/test/test_hdl_ir.py b/nmigen/test/test_hdl_ir.py new file mode 100644 index 0000000..fcc1b2e --- /dev/null +++ b/nmigen/test/test_hdl_ir.py @@ -0,0 +1,393 @@ +from ..hdl.ast import * +from ..hdl.cd import * +from ..hdl.ir import * +from .tools import * + + +class FragmentDriversTestCase(FHDLTestCase): + def test_empty(self): + f = Fragment() + self.assertEqual(list(f.iter_comb()), []) + self.assertEqual(list(f.iter_sync()), []) + + +class FragmentPortsTestCase(FHDLTestCase): + def setUp(self): + self.s1 = Signal() + self.s2 = Signal() + self.s3 = Signal() + self.c1 = Signal() + self.c2 = Signal() + self.c3 = Signal() + + def test_empty(self): + f = Fragment() + self.assertEqual(list(f.iter_ports()), []) + + f._propagate_ports(ports=()) + self.assertEqual(f.ports, ValueDict([])) + + def test_iter_signals(self): + f = Fragment() + f.add_ports(self.s1, self.s2, kind="io") + self.assertEqual(ValueSet((self.s1, self.s2)), f.iter_signals()) + + def test_self_contained(self): + f = Fragment() + f.add_statements( + self.c1.eq(self.s1), + self.s1.eq(self.c1) + ) + + f._propagate_ports(ports=()) + self.assertEqual(f.ports, ValueDict([])) + + def test_infer_input(self): + f = Fragment() + f.add_statements( + self.c1.eq(self.s1) + ) + + f._propagate_ports(ports=()) + self.assertEqual(f.ports, ValueDict([ + (self.s1, "i") + ])) + + def test_request_output(self): + f = Fragment() + f.add_statements( + self.c1.eq(self.s1) + ) + + f._propagate_ports(ports=(self.c1,)) + self.assertEqual(f.ports, ValueDict([ + (self.s1, "i"), + (self.c1, "o") + ])) + + def test_input_in_subfragment(self): + f1 = Fragment() + f1.add_statements( + self.c1.eq(self.s1) + ) + f2 = Fragment() + f2.add_statements( + self.s1.eq(0) + ) + f1.add_subfragment(f2) + f1._propagate_ports(ports=()) + self.assertEqual(f1.ports, ValueDict()) + self.assertEqual(f2.ports, ValueDict([ + (self.s1, "o"), + ])) + + def test_input_only_in_subfragment(self): + f1 = Fragment() + f2 = Fragment() + f2.add_statements( + self.c1.eq(self.s1) + ) + f1.add_subfragment(f2) + f1._propagate_ports(ports=()) + self.assertEqual(f1.ports, ValueDict([ + (self.s1, "i"), + ])) + self.assertEqual(f2.ports, ValueDict([ + (self.s1, "i"), + ])) + + def test_output_from_subfragment(self): + f1 = Fragment() + f1.add_statements( + self.c1.eq(0) + ) + f2 = Fragment() + f2.add_statements( + self.c2.eq(1) + ) + f1.add_subfragment(f2) + + f1._propagate_ports(ports=(self.c2,)) + self.assertEqual(f1.ports, ValueDict([ + (self.c2, "o"), + ])) + self.assertEqual(f2.ports, ValueDict([ + (self.c2, "o"), + ])) + + def test_input_cd(self): + sync = ClockDomain() + f = Fragment() + f.add_statements( + self.c1.eq(self.s1) + ) + f.add_domains(sync) + f.add_driver(self.c1, "sync") + + f._propagate_ports(ports=()) + self.assertEqual(f.ports, ValueDict([ + (self.s1, "i"), + (sync.clk, "i"), + (sync.rst, "i"), + ])) + + def test_input_cd_reset_less(self): + sync = ClockDomain(reset_less=True) + f = Fragment() + f.add_statements( + self.c1.eq(self.s1) + ) + f.add_domains(sync) + f.add_driver(self.c1, "sync") + + f._propagate_ports(ports=()) + self.assertEqual(f.ports, ValueDict([ + (self.s1, "i"), + (sync.clk, "i"), + ])) + + +class FragmentDomainsTestCase(FHDLTestCase): + def test_iter_signals(self): + cd1 = ClockDomain() + cd2 = ClockDomain(reset_less=True) + s1 = Signal() + s2 = Signal() + + f = Fragment() + f.add_domains(cd1, cd2) + f.add_driver(s1, "cd1") + self.assertEqual(ValueSet((cd1.clk, cd1.rst, s1)), f.iter_signals()) + f.add_driver(s2, "cd2") + self.assertEqual(ValueSet((cd1.clk, cd1.rst, cd2.clk, s1, s2)), f.iter_signals()) + + def test_propagate_up(self): + cd = ClockDomain() + + f1 = Fragment() + f2 = Fragment() + f1.add_subfragment(f2) + f2.add_domains(cd) + + f1._propagate_domains_up() + self.assertEqual(f1.domains, {"cd": cd}) + + def test_domain_conflict(self): + cda = ClockDomain("sync") + cdb = ClockDomain("sync") + + fa = Fragment() + fa.add_domains(cda) + fb = Fragment() + fb.add_domains(cdb) + f = Fragment() + f.add_subfragment(fa, "a") + f.add_subfragment(fb, "b") + + f._propagate_domains_up() + self.assertEqual(f.domains, {"a_sync": cda, "b_sync": cdb}) + (fa, _), (fb, _) = f.subfragments + self.assertEqual(fa.domains, {"a_sync": cda}) + self.assertEqual(fb.domains, {"b_sync": cdb}) + + def test_domain_conflict_anon(self): + cda = ClockDomain("sync") + cdb = ClockDomain("sync") + + fa = Fragment() + fa.add_domains(cda) + fb = Fragment() + fb.add_domains(cdb) + f = Fragment() + f.add_subfragment(fa, "a") + f.add_subfragment(fb) + + with self.assertRaises(DomainError, + msg="Domain 'sync' is defined by subfragments 'a', of fragment " + "'top'; it is necessary to either rename subfragment domains explicitly, " + "or give names to subfragments"): + f._propagate_domains_up() + + def test_domain_conflict_name(self): + cda = ClockDomain("sync") + cdb = ClockDomain("sync") + + fa = Fragment() + fa.add_domains(cda) + fb = Fragment() + fb.add_domains(cdb) + f = Fragment() + f.add_subfragment(fa, "x") + f.add_subfragment(fb, "x") + + with self.assertRaises(DomainError, + msg="Domain 'sync' is defined by subfragments #0, #1 of fragment 'top', some " + "of which have identical names; it is necessary to either rename subfragment " + "domains explicitly, or give distinct names to subfragments"): + f._propagate_domains_up() + + def test_propagate_down(self): + cd = ClockDomain() + + f1 = Fragment() + f2 = Fragment() + f1.add_domains(cd) + f1.add_subfragment(f2) + + f1._propagate_domains_down() + self.assertEqual(f2.domains, {"cd": cd}) + + def test_propagate_down_idempotent(self): + cd = ClockDomain() + + f1 = Fragment() + f1.add_domains(cd) + f2 = Fragment() + f2.add_domains(cd) + f1.add_subfragment(f2) + + f1._propagate_domains_down() + self.assertEqual(f1.domains, {"cd": cd}) + self.assertEqual(f2.domains, {"cd": cd}) + + def test_propagate(self): + cd = ClockDomain() + + f1 = Fragment() + f2 = Fragment() + f1.add_domains(cd) + f1.add_subfragment(f2) + + f1._propagate_domains(ensure_sync_exists=False) + self.assertEqual(f1.domains, {"cd": cd}) + self.assertEqual(f2.domains, {"cd": cd}) + + def test_propagate_ensure_sync(self): + f1 = Fragment() + f2 = Fragment() + f1.add_subfragment(f2) + + f1._propagate_domains(ensure_sync_exists=True) + self.assertEqual(f1.domains.keys(), {"sync"}) + self.assertEqual(f2.domains.keys(), {"sync"}) + self.assertEqual(f1.domains["sync"], f2.domains["sync"]) + + +class FragmentDriverConflictTestCase(FHDLTestCase): + def setUp_self_sub(self): + self.s1 = Signal() + self.c1 = Signal() + self.c2 = Signal() + + self.f1 = Fragment() + self.f1.add_statements(self.c1.eq(0)) + self.f1.add_driver(self.s1) + self.f1.add_driver(self.c1, "sync") + + self.f1a = Fragment() + self.f1.add_subfragment(self.f1a, "f1a") + + self.f2 = Fragment() + self.f2.add_statements(self.c2.eq(1)) + self.f2.add_driver(self.s1) + self.f2.add_driver(self.c2, "sync") + self.f1.add_subfragment(self.f2) + + self.f1b = Fragment() + self.f1.add_subfragment(self.f1b, "f1b") + + self.f2a = Fragment() + self.f2.add_subfragment(self.f2a, "f2a") + + def test_conflict_self_sub(self): + self.setUp_self_sub() + + self.f1._resolve_driver_conflicts(mode="silent") + self.assertEqual(self.f1.subfragments, [ + (self.f1a, "f1a"), + (self.f1b, "f1b"), + (self.f2a, "f2a"), + ]) + self.assertRepr(self.f1.statements, """ + ( + (eq (sig c1) (const 1'd0)) + (eq (sig c2) (const 1'd1)) + ) + """) + self.assertEqual(self.f1.drivers, { + None: ValueSet((self.s1,)), + "sync": ValueSet((self.c1, self.c2)), + }) + + def test_conflict_self_sub_error(self): + self.setUp_self_sub() + + with self.assertRaises(DriverConflict, + msg="Signal '(sig s1)' is driven from multiple fragments: top, top."): + self.f1._resolve_driver_conflicts(mode="error") + + def test_conflict_self_sub_warning(self): + self.setUp_self_sub() + + with self.assertWarns(DriverConflict, + msg="Signal '(sig s1)' is driven from multiple fragments: top, top.; " + "hierarchy will be flattened"): + self.f1._resolve_driver_conflicts(mode="warn") + + def setUp_sub_sub(self): + self.s1 = Signal() + self.c1 = Signal() + self.c2 = Signal() + + self.f1 = Fragment() + + self.f2 = Fragment() + self.f2.add_driver(self.s1) + self.f2.add_statements(self.c1.eq(0)) + self.f1.add_subfragment(self.f2) + + self.f3 = Fragment() + self.f3.add_driver(self.s1) + self.f3.add_statements(self.c2.eq(1)) + self.f1.add_subfragment(self.f3) + + def test_conflict_sub_sub(self): + self.setUp_sub_sub() + + self.f1._resolve_driver_conflicts(mode="silent") + self.assertEqual(self.f1.subfragments, []) + self.assertRepr(self.f1.statements, """ + ( + (eq (sig c1) (const 1'd0)) + (eq (sig c2) (const 1'd1)) + ) + """) + + def setUp_self_subsub(self): + self.s1 = Signal() + self.c1 = Signal() + self.c2 = Signal() + + self.f1 = Fragment() + self.f1.add_driver(self.s1) + + self.f2 = Fragment() + self.f2.add_statements(self.c1.eq(0)) + self.f1.add_subfragment(self.f2) + + self.f3 = Fragment() + self.f3.add_driver(self.s1) + self.f3.add_statements(self.c2.eq(1)) + self.f2.add_subfragment(self.f3) + + def test_conflict_self_subsub(self): + self.setUp_self_subsub() + + self.f1._resolve_driver_conflicts(mode="silent") + self.assertEqual(self.f1.subfragments, []) + self.assertRepr(self.f1.statements, """ + ( + (eq (sig c1) (const 1'd0)) + (eq (sig c2) (const 1'd1)) + ) + """) diff --git a/nmigen/test/test_hdl_xfrm.py b/nmigen/test/test_hdl_xfrm.py new file mode 100644 index 0000000..428bad7 --- /dev/null +++ b/nmigen/test/test_hdl_xfrm.py @@ -0,0 +1,316 @@ +from ..hdl.ast import * +from ..hdl.cd import * +from ..hdl.ir import * +from ..hdl.xfrm import * +from .tools import * + + +class DomainRenamerTestCase(FHDLTestCase): + def setUp(self): + self.s1 = Signal() + self.s2 = Signal() + self.s3 = Signal() + self.s4 = Signal() + self.s5 = Signal() + self.c1 = Signal() + + def test_rename_signals(self): + f = Fragment() + f.add_statements( + self.s1.eq(ClockSignal()), + ResetSignal().eq(self.s2), + self.s3.eq(0), + self.s4.eq(ClockSignal("other")), + self.s5.eq(ResetSignal("other")), + ) + f.add_driver(self.s1, None) + f.add_driver(self.s2, None) + f.add_driver(self.s3, "sync") + + f = DomainRenamer("pix")(f) + self.assertRepr(f.statements, """ + ( + (eq (sig s1) (clk pix)) + (eq (rst pix) (sig s2)) + (eq (sig s3) (const 1'd0)) + (eq (sig s4) (clk other)) + (eq (sig s5) (rst other)) + ) + """) + self.assertEqual(f.drivers, { + None: ValueSet((self.s1, self.s2)), + "pix": ValueSet((self.s3,)), + }) + + def test_rename_multi(self): + f = Fragment() + f.add_statements( + self.s1.eq(ClockSignal()), + self.s2.eq(ResetSignal("other")), + ) + + f = DomainRenamer({"sync": "pix", "other": "pix2"})(f) + self.assertRepr(f.statements, """ + ( + (eq (sig s1) (clk pix)) + (eq (sig s2) (rst pix2)) + ) + """) + + def test_rename_cd(self): + cd_sync = ClockDomain() + cd_pix = ClockDomain() + + f = Fragment() + f.add_domains(cd_sync, cd_pix) + + f = DomainRenamer("ext")(f) + self.assertEqual(cd_sync.name, "ext") + self.assertEqual(f.domains, { + "ext": cd_sync, + "pix": cd_pix, + }) + + def test_rename_cd_subfragment(self): + cd_sync = ClockDomain() + cd_pix = ClockDomain() + + f1 = Fragment() + f1.add_domains(cd_sync, cd_pix) + f2 = Fragment() + f2.add_domains(cd_sync) + f1.add_subfragment(f2) + + f1 = DomainRenamer("ext")(f1) + self.assertEqual(cd_sync.name, "ext") + self.assertEqual(f1.domains, { + "ext": cd_sync, + "pix": cd_pix, + }) + + +class DomainLowererTestCase(FHDLTestCase): + def setUp(self): + self.s = Signal() + + def test_lower_clk(self): + sync = ClockDomain() + f = Fragment() + f.add_statements( + self.s.eq(ClockSignal("sync")) + ) + + f = DomainLowerer({"sync": sync})(f) + self.assertRepr(f.statements, """ + ( + (eq (sig s) (sig clk)) + ) + """) + + def test_lower_rst(self): + sync = ClockDomain() + f = Fragment() + f.add_statements( + self.s.eq(ResetSignal("sync")) + ) + + f = DomainLowerer({"sync": sync})(f) + self.assertRepr(f.statements, """ + ( + (eq (sig s) (sig rst)) + ) + """) + + def test_lower_rst_reset_less(self): + sync = ClockDomain(reset_less=True) + f = Fragment() + f.add_statements( + self.s.eq(ResetSignal("sync", allow_reset_less=True)) + ) + + f = DomainLowerer({"sync": sync})(f) + self.assertRepr(f.statements, """ + ( + (eq (sig s) (const 1'd0)) + ) + """) + + def test_lower_wrong_domain(self): + sync = ClockDomain() + f = Fragment() + f.add_statements( + self.s.eq(ClockSignal("xxx")) + ) + + with self.assertRaises(DomainError, + msg="Signal (clk xxx) refers to nonexistent domain 'xxx'"): + DomainLowerer({"sync": sync})(f) + + def test_lower_wrong_reset_less_domain(self): + sync = ClockDomain(reset_less=True) + f = Fragment() + f.add_statements( + self.s.eq(ResetSignal("sync")) + ) + + with self.assertRaises(DomainError, + msg="Signal (rst sync) refers to reset of reset-less domain 'sync'"): + DomainLowerer({"sync": sync})(f) + + +class ResetInserterTestCase(FHDLTestCase): + def setUp(self): + self.s1 = Signal() + self.s2 = Signal(reset=1) + self.s3 = Signal(reset=1, reset_less=True) + self.c1 = Signal() + + def test_reset_default(self): + f = Fragment() + f.add_statements( + self.s1.eq(1) + ) + f.add_driver(self.s1, "sync") + + f = ResetInserter(self.c1)(f) + self.assertRepr(f.statements, """ + ( + (eq (sig s1) (const 1'd1)) + (switch (sig c1) + (case 1 (eq (sig s1) (const 1'd0))) + ) + ) + """) + + def test_reset_cd(self): + f = Fragment() + f.add_statements( + self.s1.eq(1), + self.s2.eq(0), + ) + f.add_domains(ClockDomain("sync")) + f.add_driver(self.s1, "sync") + f.add_driver(self.s2, "pix") + + f = ResetInserter({"pix": self.c1})(f) + self.assertRepr(f.statements, """ + ( + (eq (sig s1) (const 1'd1)) + (eq (sig s2) (const 1'd0)) + (switch (sig c1) + (case 1 (eq (sig s2) (const 1'd1))) + ) + ) + """) + + def test_reset_value(self): + f = Fragment() + f.add_statements( + self.s2.eq(0) + ) + f.add_driver(self.s2, "sync") + + f = ResetInserter(self.c1)(f) + self.assertRepr(f.statements, """ + ( + (eq (sig s2) (const 1'd0)) + (switch (sig c1) + (case 1 (eq (sig s2) (const 1'd1))) + ) + ) + """) + + def test_reset_less(self): + f = Fragment() + f.add_statements( + self.s3.eq(0) + ) + f.add_driver(self.s3, "sync") + + f = ResetInserter(self.c1)(f) + self.assertRepr(f.statements, """ + ( + (eq (sig s3) (const 1'd0)) + (switch (sig c1) + (case 1 ) + ) + ) + """) + + +class CEInserterTestCase(FHDLTestCase): + def setUp(self): + self.s1 = Signal() + self.s2 = Signal() + self.s3 = Signal() + self.c1 = Signal() + + def test_ce_default(self): + f = Fragment() + f.add_statements( + self.s1.eq(1) + ) + f.add_driver(self.s1, "sync") + + f = CEInserter(self.c1)(f) + self.assertRepr(f.statements, """ + ( + (eq (sig s1) (const 1'd1)) + (switch (sig c1) + (case 0 (eq (sig s1) (sig s1))) + ) + ) + """) + + def test_ce_cd(self): + f = Fragment() + f.add_statements( + self.s1.eq(1), + self.s2.eq(0), + ) + f.add_driver(self.s1, "sync") + f.add_driver(self.s2, "pix") + + f = CEInserter({"pix": self.c1})(f) + self.assertRepr(f.statements, """ + ( + (eq (sig s1) (const 1'd1)) + (eq (sig s2) (const 1'd0)) + (switch (sig c1) + (case 0 (eq (sig s2) (sig s2))) + ) + ) + """) + + def test_ce_subfragment(self): + f1 = Fragment() + f1.add_statements( + self.s1.eq(1) + ) + f1.add_driver(self.s1, "sync") + + f2 = Fragment() + f2.add_statements( + self.s2.eq(1) + ) + f2.add_driver(self.s2, "sync") + f1.add_subfragment(f2) + + f1 = CEInserter(self.c1)(f1) + (f2, _), = f1.subfragments + self.assertRepr(f1.statements, """ + ( + (eq (sig s1) (const 1'd1)) + (switch (sig c1) + (case 0 (eq (sig s1) (sig s1))) + ) + ) + """) + self.assertRepr(f2.statements, """ + ( + (eq (sig s2) (const 1'd1)) + (switch (sig c1) + (case 0 (eq (sig s2) (sig s2))) + ) + ) + """)