+++ /dev/null
-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)")
+++ /dev/null
-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")
+++ /dev/null
-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)
+++ /dev/null
-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', <unnamed #1> 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.<unnamed #1>"):
- 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.<unnamed #1>; "
- "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))
- )
- """)
+++ /dev/null
-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)))
- )
- )
- """)
--- /dev/null
+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)")
--- /dev/null
+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")
--- /dev/null
+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)
--- /dev/null
+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', <unnamed #1> 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.<unnamed #1>"):
+ 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.<unnamed #1>; "
+ "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))
+ )
+ """)
--- /dev/null
+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)))
+ )
+ )
+ """)