1 # nmigen: UnusedElaboratable=no
3 from ..hdl
.ast
import *
6 from ..hdl
.xfrm
import *
7 from ..hdl
.mem
import *
11 class DomainRenamerTestCase(FHDLTestCase
):
20 def test_rename_signals(self
):
23 self
.s1
.eq(ClockSignal()),
24 ResetSignal().eq(self
.s2
),
26 self
.s4
.eq(ClockSignal("other")),
27 self
.s5
.eq(ResetSignal("other")),
29 f
.add_driver(self
.s1
, None)
30 f
.add_driver(self
.s2
, None)
31 f
.add_driver(self
.s3
, "sync")
33 f
= DomainRenamer("pix")(f
)
34 self
.assertRepr(f
.statements
, """
36 (eq (sig s1) (clk pix))
37 (eq (rst pix) (sig s2))
38 (eq (sig s3) (const 1'd0))
39 (eq (sig s4) (clk other))
40 (eq (sig s5) (rst other))
43 self
.assertEqual(f
.drivers
, {
44 None: SignalSet((self
.s1
, self
.s2
)),
45 "pix": SignalSet((self
.s3
,)),
48 def test_rename_multi(self
):
51 self
.s1
.eq(ClockSignal()),
52 self
.s2
.eq(ResetSignal("other")),
55 f
= DomainRenamer({"sync": "pix", "other": "pix2"})(f
)
56 self
.assertRepr(f
.statements
, """
58 (eq (sig s1) (clk pix))
59 (eq (sig s2) (rst pix2))
63 def test_rename_cd(self
):
64 cd_sync
= ClockDomain()
65 cd_pix
= ClockDomain()
68 f
.add_domains(cd_sync
, cd_pix
)
70 f
= DomainRenamer("ext")(f
)
71 self
.assertEqual(cd_sync
.name
, "ext")
72 self
.assertEqual(f
.domains
, {
77 def test_rename_cd_subfragment(self
):
78 cd_sync
= ClockDomain()
79 cd_pix
= ClockDomain()
82 f1
.add_domains(cd_sync
, cd_pix
)
84 f2
.add_domains(cd_sync
)
85 f1
.add_subfragment(f2
)
87 f1
= DomainRenamer("ext")(f1
)
88 self
.assertEqual(cd_sync
.name
, "ext")
89 self
.assertEqual(f1
.domains
, {
94 def test_rename_wrong_to_comb(self
):
95 with self
.assertRaises(ValueError,
96 msg
="Domain 'sync' may not be renamed to 'comb'"):
99 def test_rename_wrong_from_comb(self
):
100 with self
.assertRaises(ValueError,
101 msg
="Domain 'comb' may not be renamed"):
102 DomainRenamer({"comb": "sync"})
105 class DomainLowererTestCase(FHDLTestCase
):
109 def test_lower_clk(self
):
114 self
.s
.eq(ClockSignal("sync"))
117 f
= DomainLowerer()(f
)
118 self
.assertRepr(f
.statements
, """
120 (eq (sig s) (sig clk))
124 def test_lower_rst(self
):
129 self
.s
.eq(ResetSignal("sync"))
132 f
= DomainLowerer()(f
)
133 self
.assertRepr(f
.statements
, """
135 (eq (sig s) (sig rst))
139 def test_lower_rst_reset_less(self
):
140 sync
= ClockDomain(reset_less
=True)
144 self
.s
.eq(ResetSignal("sync", allow_reset_less
=True))
147 f
= DomainLowerer()(f
)
148 self
.assertRepr(f
.statements
, """
150 (eq (sig s) (const 1'd0))
154 def test_lower_drivers(self
):
158 f
.add_domains(sync
, pix
)
159 f
.add_driver(ClockSignal("pix"), None)
160 f
.add_driver(ResetSignal("pix"), "sync")
162 f
= DomainLowerer()(f
)
163 self
.assertEqual(f
.drivers
, {
164 None: SignalSet((pix
.clk
,)),
165 "sync": SignalSet((pix
.rst
,))
168 def test_lower_wrong_domain(self
):
171 self
.s
.eq(ClockSignal("xxx"))
174 with self
.assertRaises(DomainError
,
175 msg
="Signal (clk xxx) refers to nonexistent domain 'xxx'"):
178 def test_lower_wrong_reset_less_domain(self
):
179 sync
= ClockDomain(reset_less
=True)
183 self
.s
.eq(ResetSignal("sync"))
186 with self
.assertRaises(DomainError
,
187 msg
="Signal (rst sync) refers to reset of reset-less domain 'sync'"):
191 class SampleLowererTestCase(FHDLTestCase
):
198 def test_lower_signal(self
):
201 self
.o1
.eq(Sample(self
.i
, 2, "sync")),
202 self
.o2
.eq(Sample(self
.i
, 1, "sync")),
203 self
.o3
.eq(Sample(self
.i
, 1, "pix")),
206 f
= SampleLowerer()(f
)
207 self
.assertRepr(f
.statements
, """
209 (eq (sig o1) (sig $sample$s$i$sync$2))
210 (eq (sig o2) (sig $sample$s$i$sync$1))
211 (eq (sig o3) (sig $sample$s$i$pix$1))
212 (eq (sig $sample$s$i$sync$1) (sig i))
213 (eq (sig $sample$s$i$sync$2) (sig $sample$s$i$sync$1))
214 (eq (sig $sample$s$i$pix$1) (sig i))
217 self
.assertEqual(len(f
.drivers
["sync"]), 2)
218 self
.assertEqual(len(f
.drivers
["pix"]), 1)
220 def test_lower_const(self
):
223 self
.o1
.eq(Sample(1, 2, "sync")),
226 f
= SampleLowerer()(f
)
227 self
.assertRepr(f
.statements
, """
229 (eq (sig o1) (sig $sample$c$1$sync$2))
230 (eq (sig $sample$c$1$sync$1) (const 1'd1))
231 (eq (sig $sample$c$1$sync$2) (sig $sample$c$1$sync$1))
234 self
.assertEqual(len(f
.drivers
["sync"]), 2)
237 class SwitchCleanerTestCase(FHDLTestCase
):
238 def test_clean(self
):
254 self
.assertRepr(SwitchCleaner()(stmts
), """
258 (eq (sig a) (const 1'd0)))
260 (eq (sig b) (const 1'd1)))
266 class LHSGroupAnalyzerTestCase(FHDLTestCase
):
267 def test_no_group_unrelated(self
):
275 groups
= LHSGroupAnalyzer()(stmts
)
276 self
.assertEqual(list(groups
.values()), [
281 def test_group_related(self
):
289 groups
= LHSGroupAnalyzer()(stmts
)
290 self
.assertEqual(list(groups
.values()), [
294 def test_no_loops(self
):
303 groups
= LHSGroupAnalyzer()(stmts
)
304 self
.assertEqual(list(groups
.values()), [
308 def test_switch(self
):
318 groups
= LHSGroupAnalyzer()(stmts
)
319 self
.assertEqual(list(groups
.values()), [
324 def test_lhs_empty(self
):
329 groups
= LHSGroupAnalyzer()(stmts
)
330 self
.assertEqual(list(groups
.values()), [
334 class LHSGroupFilterTestCase(FHDLTestCase
):
335 def test_filter(self
):
349 self
.assertRepr(LHSGroupFilter(SignalSet((a
,)))(stmts
), """
353 (eq (sig a) (const 1'd0)))
359 def test_lhs_empty(self
):
364 self
.assertRepr(LHSGroupFilter(SignalSet())(stmts
), "()")
367 class ResetInserterTestCase(FHDLTestCase
):
370 self
.s2
= Signal(reset
=1)
371 self
.s3
= Signal(reset
=1, reset_less
=True)
374 def test_reset_default(self
):
379 f
.add_driver(self
.s1
, "sync")
381 f
= ResetInserter(self
.c1
)(f
)
382 self
.assertRepr(f
.statements
, """
384 (eq (sig s1) (const 1'd1))
386 (case 1 (eq (sig s1) (const 1'd0)))
391 def test_reset_cd(self
):
397 f
.add_domains(ClockDomain("sync"))
398 f
.add_driver(self
.s1
, "sync")
399 f
.add_driver(self
.s2
, "pix")
401 f
= ResetInserter({"pix": self
.c1
})(f
)
402 self
.assertRepr(f
.statements
, """
404 (eq (sig s1) (const 1'd1))
405 (eq (sig s2) (const 1'd0))
407 (case 1 (eq (sig s2) (const 1'd1)))
412 def test_reset_value(self
):
417 f
.add_driver(self
.s2
, "sync")
419 f
= ResetInserter(self
.c1
)(f
)
420 self
.assertRepr(f
.statements
, """
422 (eq (sig s2) (const 1'd0))
424 (case 1 (eq (sig s2) (const 1'd1)))
429 def test_reset_less(self
):
434 f
.add_driver(self
.s3
, "sync")
436 f
= ResetInserter(self
.c1
)(f
)
437 self
.assertRepr(f
.statements
, """
439 (eq (sig s3) (const 1'd0))
447 class EnableInserterTestCase(FHDLTestCase
):
454 def test_enable_default(self
):
459 f
.add_driver(self
.s1
, "sync")
461 f
= EnableInserter(self
.c1
)(f
)
462 self
.assertRepr(f
.statements
, """
464 (eq (sig s1) (const 1'd1))
466 (case 0 (eq (sig s1) (sig s1)))
471 def test_enable_cd(self
):
477 f
.add_driver(self
.s1
, "sync")
478 f
.add_driver(self
.s2
, "pix")
480 f
= EnableInserter({"pix": self
.c1
})(f
)
481 self
.assertRepr(f
.statements
, """
483 (eq (sig s1) (const 1'd1))
484 (eq (sig s2) (const 1'd0))
486 (case 0 (eq (sig s2) (sig s2)))
491 def test_enable_subfragment(self
):
496 f1
.add_driver(self
.s1
, "sync")
502 f2
.add_driver(self
.s2
, "sync")
503 f1
.add_subfragment(f2
)
505 f1
= EnableInserter(self
.c1
)(f1
)
506 (f2
, _
), = f1
.subfragments
507 self
.assertRepr(f1
.statements
, """
509 (eq (sig s1) (const 1'd1))
511 (case 0 (eq (sig s1) (sig s1)))
515 self
.assertRepr(f2
.statements
, """
517 (eq (sig s2) (const 1'd1))
519 (case 0 (eq (sig s2) (sig s2)))
524 def test_enable_read_port(self
):
525 mem
= Memory(width
=8, depth
=4)
526 f
= EnableInserter(self
.c1
)(mem
.read_port(transparent
=False)).elaborate(platform
=None)
527 self
.assertRepr(f
.named_ports
["EN"][0], """
528 (m (sig c1) (sig mem_r_en) (const 1'd0))
531 def test_enable_write_port(self
):
532 mem
= Memory(width
=8, depth
=4)
533 f
= EnableInserter(self
.c1
)(mem
.write_port()).elaborate(platform
=None)
534 self
.assertRepr(f
.named_ports
["EN"][0], """
535 (m (sig c1) (cat (repl (slice (sig mem_w_en) 0:1) 8)) (const 8'd0))
539 class _MockElaboratable(Elaboratable
):
543 def elaborate(self
, platform
):
548 f
.add_driver(self
.s1
, "sync")
552 class TransformedElaboratableTestCase(FHDLTestCase
):
557 def test_getattr(self
):
558 e
= _MockElaboratable()
559 te
= EnableInserter(self
.c1
)(e
)
561 self
.assertIs(te
.s1
, e
.s1
)
563 def test_composition(self
):
564 e
= _MockElaboratable()
565 te1
= EnableInserter(self
.c1
)(e
)
566 te2
= ResetInserter(self
.c2
)(te1
)
568 self
.assertIsInstance(te1
, TransformedElaboratable
)
569 self
.assertIs(te1
, te2
)
571 f
= Fragment
.get(te2
, None)
572 self
.assertRepr(f
.statements
, """
574 (eq (sig s1) (const 1'd1))
576 (case 0 (eq (sig s1) (sig s1)))
579 (case 1 (eq (sig s1) (const 1'd0)))
585 class MockUserValue(UserValue
):
586 def __init__(self
, lowered
):
588 self
.lowered
= lowered
594 class UserValueTestCase(FHDLTestCase
):
598 self
.uv
= MockUserValue(self
.s
)
600 def test_lower(self
):
607 for signal
in self
.uv
._lhs
_signals
():
608 f
.add_driver(signal
, "sync")
610 f
= ResetInserter(self
.c
)(f
)
611 f
= DomainLowerer()(f
)
612 self
.assertRepr(f
.statements
, """
614 (eq (sig s) (const 1'd1))
616 (case 1 (eq (sig s) (const 1'd0)))
619 (case 1 (eq (sig s) (const 1'd0)))
625 class UserValueRecursiveTestCase(UserValueTestCase
):
629 self
.uv
= MockUserValue(MockUserValue(self
.s
))
631 # inherit the test_lower method from UserValueTestCase because the checks are the same