1 from collections
import OrderedDict
3 from ..hdl
.ast
import *
6 from ..hdl
.mem
import *
10 class FragmentGetTestCase(FHDLTestCase
):
11 def test_get_wrong(self
):
12 with self
.assertRaises(AttributeError,
13 msg
="Object 'None' cannot be elaborated"):
14 Fragment
.get(None, platform
=None)
17 class FragmentGeneratedTestCase(FHDLTestCase
):
18 def test_find_subfragment(self
):
21 f1
.add_subfragment(f2
, "f2")
23 self
.assertEqual(f1
.find_subfragment(0), f2
)
24 self
.assertEqual(f1
.find_subfragment("f2"), f2
)
26 def test_find_subfragment_wrong(self
):
29 f1
.add_subfragment(f2
, "f2")
31 with self
.assertRaises(NameError,
32 msg
="No subfragment at index #1"):
33 f1
.find_subfragment(1)
34 with self
.assertRaises(NameError,
35 msg
="No subfragment with name 'fx'"):
36 f1
.find_subfragment("fx")
38 def test_find_generated(self
):
41 f2
.generated
["sig"] = sig
= Signal()
42 f1
.add_subfragment(f2
, "f2")
44 self
.assertEqual(SignalKey(f1
.find_generated("f2", "sig")),
48 class FragmentDriversTestCase(FHDLTestCase
):
51 self
.assertEqual(list(f
.iter_comb()), [])
52 self
.assertEqual(list(f
.iter_sync()), [])
55 class FragmentPortsTestCase(FHDLTestCase
):
66 self
.assertEqual(list(f
.iter_ports()), [])
68 f
._propagate
_ports
(ports
=(), all_undef_as_ports
=True)
69 self
.assertEqual(f
.ports
, SignalDict([]))
71 def test_iter_signals(self
):
73 f
.add_ports(self
.s1
, self
.s2
, dir="io")
74 self
.assertEqual(SignalSet((self
.s1
, self
.s2
)), f
.iter_signals())
76 def test_self_contained(self
):
83 f
._propagate
_ports
(ports
=(), all_undef_as_ports
=True)
84 self
.assertEqual(f
.ports
, SignalDict([]))
86 def test_infer_input(self
):
92 f
._propagate
_ports
(ports
=(), all_undef_as_ports
=True)
93 self
.assertEqual(f
.ports
, SignalDict([
97 def test_request_output(self
):
103 f
._propagate
_ports
(ports
=(self
.c1
,), all_undef_as_ports
=True)
104 self
.assertEqual(f
.ports
, SignalDict([
109 def test_input_in_subfragment(self
):
118 f1
.add_subfragment(f2
)
119 f1
._propagate_ports(ports
=(), all_undef_as_ports
=True)
120 self
.assertEqual(f1
.ports
, SignalDict())
121 self
.assertEqual(f2
.ports
, SignalDict([
125 def test_input_only_in_subfragment(self
):
131 f1
.add_subfragment(f2
)
132 f1
._propagate_ports(ports
=(), all_undef_as_ports
=True)
133 self
.assertEqual(f1
.ports
, SignalDict([
136 self
.assertEqual(f2
.ports
, SignalDict([
140 def test_output_from_subfragment(self
):
149 f1
.add_subfragment(f2
)
151 f1
._propagate_ports(ports
=(self
.c2
,), all_undef_as_ports
=True)
152 self
.assertEqual(f1
.ports
, SignalDict([
155 self
.assertEqual(f2
.ports
, SignalDict([
159 def test_output_from_subfragment_2(self
):
168 f1
.add_subfragment(f2
)
173 f2
.add_subfragment(f3
)
175 f1
._propagate_ports(ports
=(), all_undef_as_ports
=True)
176 self
.assertEqual(f2
.ports
, SignalDict([
180 def test_input_output_sibling(self
):
186 f1
.add_subfragment(f2
)
191 f3
.add_driver(self
.c2
)
192 f1
.add_subfragment(f3
)
194 f1
._propagate_ports(ports
=(), all_undef_as_ports
=True)
195 self
.assertEqual(f1
.ports
, SignalDict())
197 def test_output_input_sibling(self
):
203 f2
.add_driver(self
.c2
)
204 f1
.add_subfragment(f2
)
209 f1
.add_subfragment(f3
)
211 f1
._propagate_ports(ports
=(), all_undef_as_ports
=True)
212 self
.assertEqual(f1
.ports
, SignalDict())
214 def test_input_cd(self
):
221 f
.add_driver(self
.c1
, "sync")
223 f
._propagate
_ports
(ports
=(), all_undef_as_ports
=True)
224 self
.assertEqual(f
.ports
, SignalDict([
230 def test_input_cd_reset_less(self
):
231 sync
= ClockDomain(reset_less
=True)
237 f
.add_driver(self
.c1
, "sync")
239 f
._propagate
_ports
(ports
=(), all_undef_as_ports
=True)
240 self
.assertEqual(f
.ports
, SignalDict([
245 def test_inout(self
):
248 f2
= Instance("foo", io_x
=s
)
249 f1
.add_subfragment(f2
)
251 f1
._propagate_ports(ports
=(), all_undef_as_ports
=True)
252 self
.assertEqual(f1
.ports
, SignalDict([
257 class FragmentDomainsTestCase(FHDLTestCase
):
258 def test_iter_signals(self
):
260 cd2
= ClockDomain(reset_less
=True)
265 f
.add_domains(cd1
, cd2
)
266 f
.add_driver(s1
, "cd1")
267 self
.assertEqual(SignalSet((cd1
.clk
, cd1
.rst
, s1
)), f
.iter_signals())
268 f
.add_driver(s2
, "cd2")
269 self
.assertEqual(SignalSet((cd1
.clk
, cd1
.rst
, cd2
.clk
, s1
, s2
)), f
.iter_signals())
271 def test_propagate_up(self
):
276 f1
.add_subfragment(f2
)
279 f1
._propagate_domains_up()
280 self
.assertEqual(f1
.domains
, {"cd": cd
})
282 def test_domain_conflict(self
):
283 cda
= ClockDomain("sync")
284 cdb
= ClockDomain("sync")
291 f
.add_subfragment(fa
, "a")
292 f
.add_subfragment(fb
, "b")
294 f
._propagate
_domains
_up
()
295 self
.assertEqual(f
.domains
, {"a_sync": cda
, "b_sync": cdb
})
296 (fa
, _
), (fb
, _
) = f
.subfragments
297 self
.assertEqual(fa
.domains
, {"a_sync": cda
})
298 self
.assertEqual(fb
.domains
, {"b_sync": cdb
})
300 def test_domain_conflict_anon(self
):
301 cda
= ClockDomain("sync")
302 cdb
= ClockDomain("sync")
309 f
.add_subfragment(fa
, "a")
310 f
.add_subfragment(fb
)
312 with self
.assertRaises(DomainError
,
313 msg
="Domain 'sync' is defined by subfragments 'a', <unnamed #1> of fragment "
314 "'top'; it is necessary to either rename subfragment domains explicitly, "
315 "or give names to subfragments"):
316 f
._propagate
_domains
_up
()
318 def test_domain_conflict_name(self
):
319 cda
= ClockDomain("sync")
320 cdb
= ClockDomain("sync")
327 f
.add_subfragment(fa
, "x")
328 f
.add_subfragment(fb
, "x")
330 with self
.assertRaises(DomainError
,
331 msg
="Domain 'sync' is defined by subfragments #0, #1 of fragment 'top', some "
332 "of which have identical names; it is necessary to either rename subfragment "
333 "domains explicitly, or give distinct names to subfragments"):
334 f
._propagate
_domains
_up
()
336 def test_propagate_down(self
):
342 f1
.add_subfragment(f2
)
344 f1
._propagate_domains_down()
345 self
.assertEqual(f2
.domains
, {"cd": cd
})
347 def test_propagate_down_idempotent(self
):
354 f1
.add_subfragment(f2
)
356 f1
._propagate_domains_down()
357 self
.assertEqual(f1
.domains
, {"cd": cd
})
358 self
.assertEqual(f2
.domains
, {"cd": cd
})
360 def test_propagate(self
):
366 f1
.add_subfragment(f2
)
368 f1
._propagate_domains(ensure_sync_exists
=False)
369 self
.assertEqual(f1
.domains
, {"cd": cd
})
370 self
.assertEqual(f2
.domains
, {"cd": cd
})
372 def test_propagate_ensure_sync(self
):
375 f1
.add_subfragment(f2
)
377 f1
._propagate_domains(ensure_sync_exists
=True)
378 self
.assertEqual(f1
.domains
.keys(), {"sync"})
379 self
.assertEqual(f2
.domains
.keys(), {"sync"})
380 self
.assertEqual(f1
.domains
["sync"], f2
.domains
["sync"])
383 class FragmentHierarchyConflictTestCase(FHDLTestCase
):
384 def setUp_self_sub(self
):
390 self
.f1
.add_statements(self
.c1
.eq(0))
391 self
.f1
.add_driver(self
.s1
)
392 self
.f1
.add_driver(self
.c1
, "sync")
394 self
.f1a
= Fragment()
395 self
.f1
.add_subfragment(self
.f1a
, "f1a")
398 self
.f2
.add_statements(self
.c2
.eq(1))
399 self
.f2
.add_driver(self
.s1
)
400 self
.f2
.add_driver(self
.c2
, "sync")
401 self
.f1
.add_subfragment(self
.f2
)
403 self
.f1b
= Fragment()
404 self
.f1
.add_subfragment(self
.f1b
, "f1b")
406 self
.f2a
= Fragment()
407 self
.f2
.add_subfragment(self
.f2a
, "f2a")
409 def test_conflict_self_sub(self
):
410 self
.setUp_self_sub()
412 self
.f1
._resolve_hierarchy_conflicts(mode
="silent")
413 self
.assertEqual(self
.f1
.subfragments
, [
418 self
.assertRepr(self
.f1
.statements
, """
420 (eq (sig c1) (const 1'd0))
421 (eq (sig c2) (const 1'd1))
424 self
.assertEqual(self
.f1
.drivers
, {
425 None: SignalSet((self
.s1
,)),
426 "sync": SignalSet((self
.c1
, self
.c2
)),
429 def test_conflict_self_sub_error(self
):
430 self
.setUp_self_sub()
432 with self
.assertRaises(DriverConflict
,
433 msg
="Signal '(sig s1)' is driven from multiple fragments: top, top.<unnamed #1>"):
434 self
.f1
._resolve_hierarchy_conflicts(mode
="error")
436 def test_conflict_self_sub_warning(self
):
437 self
.setUp_self_sub()
439 with self
.assertWarns(DriverConflict
,
440 msg
="Signal '(sig s1)' is driven from multiple fragments: top, top.<unnamed #1>; "
441 "hierarchy will be flattened"):
442 self
.f1
._resolve_hierarchy_conflicts(mode
="warn")
444 def setUp_sub_sub(self
):
452 self
.f2
.add_driver(self
.s1
)
453 self
.f2
.add_statements(self
.c1
.eq(0))
454 self
.f1
.add_subfragment(self
.f2
)
457 self
.f3
.add_driver(self
.s1
)
458 self
.f3
.add_statements(self
.c2
.eq(1))
459 self
.f1
.add_subfragment(self
.f3
)
461 def test_conflict_sub_sub(self
):
464 self
.f1
._resolve_hierarchy_conflicts(mode
="silent")
465 self
.assertEqual(self
.f1
.subfragments
, [])
466 self
.assertRepr(self
.f1
.statements
, """
468 (eq (sig c1) (const 1'd0))
469 (eq (sig c2) (const 1'd1))
473 def setUp_self_subsub(self
):
479 self
.f1
.add_driver(self
.s1
)
482 self
.f2
.add_statements(self
.c1
.eq(0))
483 self
.f1
.add_subfragment(self
.f2
)
486 self
.f3
.add_driver(self
.s1
)
487 self
.f3
.add_statements(self
.c2
.eq(1))
488 self
.f2
.add_subfragment(self
.f3
)
490 def test_conflict_self_subsub(self
):
491 self
.setUp_self_subsub()
493 self
.f1
._resolve_hierarchy_conflicts(mode
="silent")
494 self
.assertEqual(self
.f1
.subfragments
, [])
495 self
.assertRepr(self
.f1
.statements
, """
497 (eq (sig c1) (const 1'd0))
498 (eq (sig c2) (const 1'd1))
502 def setUp_memory(self
):
503 self
.m
= Memory(width
=8, depth
=4)
504 self
.fr
= self
.m
.read_port().elaborate(platform
=None)
505 self
.fw
= self
.m
.write_port().elaborate(platform
=None)
508 self
.f2
.add_subfragment(self
.fr
)
509 self
.f1
.add_subfragment(self
.f2
)
511 self
.f3
.add_subfragment(self
.fw
)
512 self
.f1
.add_subfragment(self
.f3
)
514 def test_conflict_memory(self
):
517 self
.f1
._resolve_hierarchy_conflicts(mode
="silent")
518 self
.assertEqual(self
.f1
.subfragments
, [
523 def test_conflict_memory_error(self
):
526 with self
.assertRaises(DriverConflict
,
527 msg
="Memory 'm' is accessed from multiple fragments: top.<unnamed #0>, "
529 self
.f1
._resolve_hierarchy_conflicts(mode
="error")
531 def test_conflict_memory_warning(self
):
534 with self
.assertWarns(DriverConflict
,
535 msg
="Memory 'm' is accessed from multiple fragments: top.<unnamed #0>, "
536 "top.<unnamed #1>; hierarchy will be flattened"):
537 self
.f1
._resolve_hierarchy_conflicts(mode
="warn")
539 def test_explicit_flatten(self
):
542 self
.f2
.flatten
= True
543 self
.f1
.add_subfragment(self
.f2
)
545 self
.f1
._resolve_hierarchy_conflicts(mode
="silent")
546 self
.assertEqual(self
.f1
.subfragments
, [])
549 class InstanceTestCase(FHDLTestCase
):
550 def test_construct(self
):
557 inst
= Instance("foo",
559 ("p", "PARAM1", 0x1234),
569 self
.assertEqual(inst
.attrs
, OrderedDict([
573 self
.assertEqual(inst
.parameters
, OrderedDict([
577 self
.assertEqual(inst
.named_ports
, OrderedDict([
586 def test_wrong_construct_arg(self
):
588 with self
.assertRaises(NameError,
589 msg
="Instance argument ('', 's1', (sig s)) should be a tuple "
590 "(kind, name, value) where kind is one of \"p\", \"i\", \"o\", or \"io\""):
591 Instance("foo", ("", "s1", s
))
593 def test_wrong_construct_kwarg(self
):
595 with self
.assertRaises(NameError,
596 msg
="Instance keyword argument x_s1=(sig s) does not start with one of "
597 "\"p_\", \"i_\", \"o_\", or \"io_\""):
598 Instance("foo", x_s1
=s
)
603 self
.pins
= Signal(8)
604 self
.datal
= Signal(4)
605 self
.datah
= Signal(4)
606 self
.inst
= Instance("cpu",
611 o_data
=Cat(self
.datal
, self
.datah
),
614 self
.wrap
= Fragment()
615 self
.wrap
.add_subfragment(self
.inst
)
620 self
.assertEqual(f
.type, "cpu")
621 self
.assertEqual(f
.parameters
, OrderedDict([("RESET", 0x1234)]))
622 self
.assertEqual(list(f
.named_ports
.keys()), ["clk", "rst", "stb", "data", "pins"])
623 self
.assertEqual(f
.ports
, SignalDict([]))
625 def test_prepare(self
):
627 f
= self
.wrap
.prepare()
628 sync_clk
= f
.domains
["sync"].clk
629 self
.assertEqual(f
.ports
, SignalDict([
635 def test_prepare_explicit_ports(self
):
637 f
= self
.wrap
.prepare(ports
=[self
.rst
, self
.stb
])
638 sync_clk
= f
.domains
["sync"].clk
639 sync_rst
= f
.domains
["sync"].rst
640 self
.assertEqual(f
.ports
, SignalDict([
648 def test_prepare_slice_in_port(self
):
651 f
.add_subfragment(Instance("foo", o_O
=s
[0]))
652 f
.add_subfragment(Instance("foo", o_O
=s
[1]))
653 fp
= f
.prepare(ports
=[s
], ensure_sync_exists
=False)
654 self
.assertEqual(fp
.ports
, SignalDict([
658 def test_prepare_attrs(self
):
660 self
.inst
.attrs
["ATTR"] = 1
661 f
= self
.inst
.prepare()
662 self
.assertEqual(f
.attrs
, OrderedDict([