b93537d9d2a73bc70d3e4ba8cd47101d03d93df4
[nmigen.git] / nmigen / test / test_hdl_ir.py
1 # nmigen: UnusedElaboratable=no
2
3 from collections import OrderedDict
4
5 from ..hdl.ast import *
6 from ..hdl.cd import *
7 from ..hdl.ir import *
8 from ..hdl.mem import *
9 from .utils import *
10
11
12 class BadElaboratable(Elaboratable):
13 def elaborate(self, platform):
14 return
15
16
17 class FragmentGetTestCase(FHDLTestCase):
18 def test_get_wrong(self):
19 with self.assertRaises(AttributeError,
20 msg="Object None cannot be elaborated"):
21 Fragment.get(None, platform=None)
22
23 with self.assertWarns(UserWarning,
24 msg=".elaborate() returned None; missing return statement?"):
25 with self.assertRaises(AttributeError,
26 msg="Object None cannot be elaborated"):
27 Fragment.get(BadElaboratable(), platform=None)
28
29
30 class FragmentGeneratedTestCase(FHDLTestCase):
31 def test_find_subfragment(self):
32 f1 = Fragment()
33 f2 = Fragment()
34 f1.add_subfragment(f2, "f2")
35
36 self.assertEqual(f1.find_subfragment(0), f2)
37 self.assertEqual(f1.find_subfragment("f2"), f2)
38
39 def test_find_subfragment_wrong(self):
40 f1 = Fragment()
41 f2 = Fragment()
42 f1.add_subfragment(f2, "f2")
43
44 with self.assertRaises(NameError,
45 msg="No subfragment at index #1"):
46 f1.find_subfragment(1)
47 with self.assertRaises(NameError,
48 msg="No subfragment with name 'fx'"):
49 f1.find_subfragment("fx")
50
51 def test_find_generated(self):
52 f1 = Fragment()
53 f2 = Fragment()
54 f2.generated["sig"] = sig = Signal()
55 f1.add_subfragment(f2, "f2")
56
57 self.assertEqual(SignalKey(f1.find_generated("f2", "sig")),
58 SignalKey(sig))
59
60
61 class FragmentDriversTestCase(FHDLTestCase):
62 def test_empty(self):
63 f = Fragment()
64 self.assertEqual(list(f.iter_comb()), [])
65 self.assertEqual(list(f.iter_sync()), [])
66
67
68 class FragmentPortsTestCase(FHDLTestCase):
69 def setUp(self):
70 self.s1 = Signal()
71 self.s2 = Signal()
72 self.s3 = Signal()
73 self.c1 = Signal()
74 self.c2 = Signal()
75 self.c3 = Signal()
76
77 def test_empty(self):
78 f = Fragment()
79 self.assertEqual(list(f.iter_ports()), [])
80
81 f._propagate_ports(ports=(), all_undef_as_ports=True)
82 self.assertEqual(f.ports, SignalDict([]))
83
84 def test_iter_signals(self):
85 f = Fragment()
86 f.add_ports(self.s1, self.s2, dir="io")
87 self.assertEqual(SignalSet((self.s1, self.s2)), f.iter_signals())
88
89 def test_self_contained(self):
90 f = Fragment()
91 f.add_statements(
92 self.c1.eq(self.s1),
93 self.s1.eq(self.c1)
94 )
95
96 f._propagate_ports(ports=(), all_undef_as_ports=True)
97 self.assertEqual(f.ports, SignalDict([]))
98
99 def test_infer_input(self):
100 f = Fragment()
101 f.add_statements(
102 self.c1.eq(self.s1)
103 )
104
105 f._propagate_ports(ports=(), all_undef_as_ports=True)
106 self.assertEqual(f.ports, SignalDict([
107 (self.s1, "i")
108 ]))
109
110 def test_request_output(self):
111 f = Fragment()
112 f.add_statements(
113 self.c1.eq(self.s1)
114 )
115
116 f._propagate_ports(ports=(self.c1,), all_undef_as_ports=True)
117 self.assertEqual(f.ports, SignalDict([
118 (self.s1, "i"),
119 (self.c1, "o")
120 ]))
121
122 def test_input_in_subfragment(self):
123 f1 = Fragment()
124 f1.add_statements(
125 self.c1.eq(self.s1)
126 )
127 f2 = Fragment()
128 f2.add_statements(
129 self.s1.eq(0)
130 )
131 f1.add_subfragment(f2)
132 f1._propagate_ports(ports=(), all_undef_as_ports=True)
133 self.assertEqual(f1.ports, SignalDict())
134 self.assertEqual(f2.ports, SignalDict([
135 (self.s1, "o"),
136 ]))
137
138 def test_input_only_in_subfragment(self):
139 f1 = Fragment()
140 f2 = Fragment()
141 f2.add_statements(
142 self.c1.eq(self.s1)
143 )
144 f1.add_subfragment(f2)
145 f1._propagate_ports(ports=(), all_undef_as_ports=True)
146 self.assertEqual(f1.ports, SignalDict([
147 (self.s1, "i"),
148 ]))
149 self.assertEqual(f2.ports, SignalDict([
150 (self.s1, "i"),
151 ]))
152
153 def test_output_from_subfragment(self):
154 f1 = Fragment()
155 f1.add_statements(
156 self.c1.eq(0)
157 )
158 f2 = Fragment()
159 f2.add_statements(
160 self.c2.eq(1)
161 )
162 f1.add_subfragment(f2)
163
164 f1._propagate_ports(ports=(self.c2,), all_undef_as_ports=True)
165 self.assertEqual(f1.ports, SignalDict([
166 (self.c2, "o"),
167 ]))
168 self.assertEqual(f2.ports, SignalDict([
169 (self.c2, "o"),
170 ]))
171
172 def test_output_from_subfragment_2(self):
173 f1 = Fragment()
174 f1.add_statements(
175 self.c1.eq(self.s1)
176 )
177 f2 = Fragment()
178 f2.add_statements(
179 self.c2.eq(self.s1)
180 )
181 f1.add_subfragment(f2)
182 f3 = Fragment()
183 f3.add_statements(
184 self.s1.eq(0)
185 )
186 f2.add_subfragment(f3)
187
188 f1._propagate_ports(ports=(), all_undef_as_ports=True)
189 self.assertEqual(f2.ports, SignalDict([
190 (self.s1, "o"),
191 ]))
192
193 def test_input_output_sibling(self):
194 f1 = Fragment()
195 f2 = Fragment()
196 f2.add_statements(
197 self.c1.eq(self.c2)
198 )
199 f1.add_subfragment(f2)
200 f3 = Fragment()
201 f3.add_statements(
202 self.c2.eq(0)
203 )
204 f3.add_driver(self.c2)
205 f1.add_subfragment(f3)
206
207 f1._propagate_ports(ports=(), all_undef_as_ports=True)
208 self.assertEqual(f1.ports, SignalDict())
209
210 def test_output_input_sibling(self):
211 f1 = Fragment()
212 f2 = Fragment()
213 f2.add_statements(
214 self.c2.eq(0)
215 )
216 f2.add_driver(self.c2)
217 f1.add_subfragment(f2)
218 f3 = Fragment()
219 f3.add_statements(
220 self.c1.eq(self.c2)
221 )
222 f1.add_subfragment(f3)
223
224 f1._propagate_ports(ports=(), all_undef_as_ports=True)
225 self.assertEqual(f1.ports, SignalDict())
226
227 def test_input_cd(self):
228 sync = ClockDomain()
229 f = Fragment()
230 f.add_statements(
231 self.c1.eq(self.s1)
232 )
233 f.add_domains(sync)
234 f.add_driver(self.c1, "sync")
235
236 f._propagate_ports(ports=(), all_undef_as_ports=True)
237 self.assertEqual(f.ports, SignalDict([
238 (self.s1, "i"),
239 (sync.clk, "i"),
240 (sync.rst, "i"),
241 ]))
242
243 def test_input_cd_reset_less(self):
244 sync = ClockDomain(reset_less=True)
245 f = Fragment()
246 f.add_statements(
247 self.c1.eq(self.s1)
248 )
249 f.add_domains(sync)
250 f.add_driver(self.c1, "sync")
251
252 f._propagate_ports(ports=(), all_undef_as_ports=True)
253 self.assertEqual(f.ports, SignalDict([
254 (self.s1, "i"),
255 (sync.clk, "i"),
256 ]))
257
258 def test_inout(self):
259 s = Signal()
260 f1 = Fragment()
261 f2 = Instance("foo", io_x=s)
262 f1.add_subfragment(f2)
263
264 f1._propagate_ports(ports=(), all_undef_as_ports=True)
265 self.assertEqual(f1.ports, SignalDict([
266 (s, "io")
267 ]))
268
269 def test_in_out_same_signal(self):
270 s = Signal()
271
272 f1 = Instance("foo", i_x=s, o_y=s)
273 f2 = Fragment()
274 f2.add_subfragment(f1)
275
276 f2._propagate_ports(ports=(), all_undef_as_ports=True)
277 self.assertEqual(f1.ports, SignalDict([
278 (s, "o")
279 ]))
280
281 f3 = Instance("foo", o_y=s, i_x=s)
282 f4 = Fragment()
283 f4.add_subfragment(f3)
284
285 f4._propagate_ports(ports=(), all_undef_as_ports=True)
286 self.assertEqual(f3.ports, SignalDict([
287 (s, "o")
288 ]))
289
290 def test_clk_rst(self):
291 sync = ClockDomain()
292 f = Fragment()
293 f.add_domains(sync)
294
295 f = f.prepare(ports=(ClockSignal("sync"), ResetSignal("sync")))
296 self.assertEqual(f.ports, SignalDict([
297 (sync.clk, "i"),
298 (sync.rst, "i"),
299 ]))
300
301 def test_port_wrong(self):
302 f = Fragment()
303 with self.assertRaises(TypeError,
304 msg="Only signals may be added as ports, not (const 1'd1)"):
305 f.prepare(ports=(Const(1),))
306
307 def test_port_not_iterable(self):
308 f = Fragment()
309 with self.assertRaises(TypeError,
310 msg="`ports` must be either a list or a tuple, not 1"):
311 f.prepare(ports=1)
312 with self.assertRaises(TypeError,
313 msg="`ports` must be either a list or a tuple, not (const 1'd1)" +
314 " (did you mean `ports=(<signal>,)`, rather than `ports=<signal>`?)"):
315 f.prepare(ports=Const(1))
316
317 class FragmentDomainsTestCase(FHDLTestCase):
318 def test_iter_signals(self):
319 cd1 = ClockDomain()
320 cd2 = ClockDomain(reset_less=True)
321 s1 = Signal()
322 s2 = Signal()
323
324 f = Fragment()
325 f.add_domains(cd1, cd2)
326 f.add_driver(s1, "cd1")
327 self.assertEqual(SignalSet((cd1.clk, cd1.rst, s1)), f.iter_signals())
328 f.add_driver(s2, "cd2")
329 self.assertEqual(SignalSet((cd1.clk, cd1.rst, cd2.clk, s1, s2)), f.iter_signals())
330
331 def test_propagate_up(self):
332 cd = ClockDomain()
333
334 f1 = Fragment()
335 f2 = Fragment()
336 f1.add_subfragment(f2)
337 f2.add_domains(cd)
338
339 f1._propagate_domains_up()
340 self.assertEqual(f1.domains, {"cd": cd})
341
342 def test_propagate_up_local(self):
343 cd = ClockDomain(local=True)
344
345 f1 = Fragment()
346 f2 = Fragment()
347 f1.add_subfragment(f2)
348 f2.add_domains(cd)
349
350 f1._propagate_domains_up()
351 self.assertEqual(f1.domains, {})
352
353 def test_domain_conflict(self):
354 cda = ClockDomain("sync")
355 cdb = ClockDomain("sync")
356
357 fa = Fragment()
358 fa.add_domains(cda)
359 fb = Fragment()
360 fb.add_domains(cdb)
361 f = Fragment()
362 f.add_subfragment(fa, "a")
363 f.add_subfragment(fb, "b")
364
365 f._propagate_domains_up()
366 self.assertEqual(f.domains, {"a_sync": cda, "b_sync": cdb})
367 (fa, _), (fb, _) = f.subfragments
368 self.assertEqual(fa.domains, {"a_sync": cda})
369 self.assertEqual(fb.domains, {"b_sync": cdb})
370
371 def test_domain_conflict_anon(self):
372 cda = ClockDomain("sync")
373 cdb = ClockDomain("sync")
374
375 fa = Fragment()
376 fa.add_domains(cda)
377 fb = Fragment()
378 fb.add_domains(cdb)
379 f = Fragment()
380 f.add_subfragment(fa, "a")
381 f.add_subfragment(fb)
382
383 with self.assertRaises(DomainError,
384 msg="Domain 'sync' is defined by subfragments 'a', <unnamed #1> of fragment "
385 "'top'; it is necessary to either rename subfragment domains explicitly, "
386 "or give names to subfragments"):
387 f._propagate_domains_up()
388
389 def test_domain_conflict_name(self):
390 cda = ClockDomain("sync")
391 cdb = ClockDomain("sync")
392
393 fa = Fragment()
394 fa.add_domains(cda)
395 fb = Fragment()
396 fb.add_domains(cdb)
397 f = Fragment()
398 f.add_subfragment(fa, "x")
399 f.add_subfragment(fb, "x")
400
401 with self.assertRaises(DomainError,
402 msg="Domain 'sync' is defined by subfragments #0, #1 of fragment 'top', some "
403 "of which have identical names; it is necessary to either rename subfragment "
404 "domains explicitly, or give distinct names to subfragments"):
405 f._propagate_domains_up()
406
407 def test_domain_conflict_rename_drivers(self):
408 cda = ClockDomain("sync")
409 cdb = ClockDomain("sync")
410
411 fa = Fragment()
412 fa.add_domains(cda)
413 fb = Fragment()
414 fb.add_domains(cdb)
415 fb.add_driver(ResetSignal("sync"), None)
416 f = Fragment()
417 f.add_subfragment(fa, "a")
418 f.add_subfragment(fb, "b")
419
420 f._propagate_domains_up()
421 fb_new, _ = f.subfragments[1]
422 self.assertEqual(fb_new.drivers, OrderedDict({
423 None: SignalSet((ResetSignal("b_sync"),))
424 }))
425
426 def test_domain_conflict_rename_drivers(self):
427 cda = ClockDomain("sync")
428 cdb = ClockDomain("sync")
429 s = Signal()
430
431 fa = Fragment()
432 fa.add_domains(cda)
433 fb = Fragment()
434 fb.add_domains(cdb)
435 f = Fragment()
436 f.add_subfragment(fa, "a")
437 f.add_subfragment(fb, "b")
438 f.add_driver(s, "b_sync")
439
440 f._propagate_domains(lambda name: ClockDomain(name))
441
442 def test_propagate_down(self):
443 cd = ClockDomain()
444
445 f1 = Fragment()
446 f2 = Fragment()
447 f1.add_domains(cd)
448 f1.add_subfragment(f2)
449
450 f1._propagate_domains_down()
451 self.assertEqual(f2.domains, {"cd": cd})
452
453 def test_propagate_down_idempotent(self):
454 cd = ClockDomain()
455
456 f1 = Fragment()
457 f1.add_domains(cd)
458 f2 = Fragment()
459 f2.add_domains(cd)
460 f1.add_subfragment(f2)
461
462 f1._propagate_domains_down()
463 self.assertEqual(f1.domains, {"cd": cd})
464 self.assertEqual(f2.domains, {"cd": cd})
465
466 def test_propagate(self):
467 cd = ClockDomain()
468
469 f1 = Fragment()
470 f2 = Fragment()
471 f1.add_domains(cd)
472 f1.add_subfragment(f2)
473
474 new_domains = f1._propagate_domains(missing_domain=lambda name: None)
475 self.assertEqual(f1.domains, {"cd": cd})
476 self.assertEqual(f2.domains, {"cd": cd})
477 self.assertEqual(new_domains, [])
478
479 def test_propagate_missing(self):
480 s1 = Signal()
481 f1 = Fragment()
482 f1.add_driver(s1, "sync")
483
484 with self.assertRaises(DomainError,
485 msg="Domain 'sync' is used but not defined"):
486 f1._propagate_domains(missing_domain=lambda name: None)
487
488 def test_propagate_create_missing(self):
489 s1 = Signal()
490 f1 = Fragment()
491 f1.add_driver(s1, "sync")
492 f2 = Fragment()
493 f1.add_subfragment(f2)
494
495 new_domains = f1._propagate_domains(missing_domain=lambda name: ClockDomain(name))
496 self.assertEqual(f1.domains.keys(), {"sync"})
497 self.assertEqual(f2.domains.keys(), {"sync"})
498 self.assertEqual(f1.domains["sync"], f2.domains["sync"])
499 self.assertEqual(new_domains, [f1.domains["sync"]])
500
501 def test_propagate_create_missing_fragment(self):
502 s1 = Signal()
503 f1 = Fragment()
504 f1.add_driver(s1, "sync")
505
506 cd = ClockDomain("sync")
507 f2 = Fragment()
508 f2.add_domains(cd)
509
510 new_domains = f1._propagate_domains(missing_domain=lambda name: f2)
511 self.assertEqual(f1.domains.keys(), {"sync"})
512 self.assertEqual(f1.domains["sync"], f2.domains["sync"])
513 self.assertEqual(new_domains, [])
514 self.assertEqual(f1.subfragments, [
515 (f2, "cd_sync")
516 ])
517
518 def test_propagate_create_missing_fragment_many_domains(self):
519 s1 = Signal()
520 f1 = Fragment()
521 f1.add_driver(s1, "sync")
522
523 cd_por = ClockDomain("por")
524 cd_sync = ClockDomain("sync")
525 f2 = Fragment()
526 f2.add_domains(cd_por, cd_sync)
527
528 new_domains = f1._propagate_domains(missing_domain=lambda name: f2)
529 self.assertEqual(f1.domains.keys(), {"sync", "por"})
530 self.assertEqual(f2.domains.keys(), {"sync", "por"})
531 self.assertEqual(f1.domains["sync"], f2.domains["sync"])
532 self.assertEqual(new_domains, [])
533 self.assertEqual(f1.subfragments, [
534 (f2, "cd_sync")
535 ])
536
537 def test_propagate_create_missing_fragment_wrong(self):
538 s1 = Signal()
539 f1 = Fragment()
540 f1.add_driver(s1, "sync")
541
542 f2 = Fragment()
543 f2.add_domains(ClockDomain("foo"))
544
545 with self.assertRaises(DomainError,
546 msg="Fragment returned by missing domain callback does not define requested "
547 "domain 'sync' (defines 'foo')."):
548 f1._propagate_domains(missing_domain=lambda name: f2)
549
550
551 class FragmentHierarchyConflictTestCase(FHDLTestCase):
552 def setUp_self_sub(self):
553 self.s1 = Signal()
554 self.c1 = Signal()
555 self.c2 = Signal()
556
557 self.f1 = Fragment()
558 self.f1.add_statements(self.c1.eq(0))
559 self.f1.add_driver(self.s1)
560 self.f1.add_driver(self.c1, "sync")
561
562 self.f1a = Fragment()
563 self.f1.add_subfragment(self.f1a, "f1a")
564
565 self.f2 = Fragment()
566 self.f2.add_statements(self.c2.eq(1))
567 self.f2.add_driver(self.s1)
568 self.f2.add_driver(self.c2, "sync")
569 self.f1.add_subfragment(self.f2)
570
571 self.f1b = Fragment()
572 self.f1.add_subfragment(self.f1b, "f1b")
573
574 self.f2a = Fragment()
575 self.f2.add_subfragment(self.f2a, "f2a")
576
577 def test_conflict_self_sub(self):
578 self.setUp_self_sub()
579
580 self.f1._resolve_hierarchy_conflicts(mode="silent")
581 self.assertEqual(self.f1.subfragments, [
582 (self.f1a, "f1a"),
583 (self.f1b, "f1b"),
584 (self.f2a, "f2a"),
585 ])
586 self.assertRepr(self.f1.statements, """
587 (
588 (eq (sig c1) (const 1'd0))
589 (eq (sig c2) (const 1'd1))
590 )
591 """)
592 self.assertEqual(self.f1.drivers, {
593 None: SignalSet((self.s1,)),
594 "sync": SignalSet((self.c1, self.c2)),
595 })
596
597 def test_conflict_self_sub_error(self):
598 self.setUp_self_sub()
599
600 with self.assertRaises(DriverConflict,
601 msg="Signal '(sig s1)' is driven from multiple fragments: top, top.<unnamed #1>"):
602 self.f1._resolve_hierarchy_conflicts(mode="error")
603
604 def test_conflict_self_sub_warning(self):
605 self.setUp_self_sub()
606
607 with self.assertWarns(DriverConflict,
608 msg="Signal '(sig s1)' is driven from multiple fragments: top, top.<unnamed #1>; "
609 "hierarchy will be flattened"):
610 self.f1._resolve_hierarchy_conflicts(mode="warn")
611
612 def setUp_sub_sub(self):
613 self.s1 = Signal()
614 self.c1 = Signal()
615 self.c2 = Signal()
616
617 self.f1 = Fragment()
618
619 self.f2 = Fragment()
620 self.f2.add_driver(self.s1)
621 self.f2.add_statements(self.c1.eq(0))
622 self.f1.add_subfragment(self.f2)
623
624 self.f3 = Fragment()
625 self.f3.add_driver(self.s1)
626 self.f3.add_statements(self.c2.eq(1))
627 self.f1.add_subfragment(self.f3)
628
629 def test_conflict_sub_sub(self):
630 self.setUp_sub_sub()
631
632 self.f1._resolve_hierarchy_conflicts(mode="silent")
633 self.assertEqual(self.f1.subfragments, [])
634 self.assertRepr(self.f1.statements, """
635 (
636 (eq (sig c1) (const 1'd0))
637 (eq (sig c2) (const 1'd1))
638 )
639 """)
640
641 def setUp_self_subsub(self):
642 self.s1 = Signal()
643 self.c1 = Signal()
644 self.c2 = Signal()
645
646 self.f1 = Fragment()
647 self.f1.add_driver(self.s1)
648
649 self.f2 = Fragment()
650 self.f2.add_statements(self.c1.eq(0))
651 self.f1.add_subfragment(self.f2)
652
653 self.f3 = Fragment()
654 self.f3.add_driver(self.s1)
655 self.f3.add_statements(self.c2.eq(1))
656 self.f2.add_subfragment(self.f3)
657
658 def test_conflict_self_subsub(self):
659 self.setUp_self_subsub()
660
661 self.f1._resolve_hierarchy_conflicts(mode="silent")
662 self.assertEqual(self.f1.subfragments, [])
663 self.assertRepr(self.f1.statements, """
664 (
665 (eq (sig c1) (const 1'd0))
666 (eq (sig c2) (const 1'd1))
667 )
668 """)
669
670 def setUp_memory(self):
671 self.m = Memory(width=8, depth=4)
672 self.fr = self.m.read_port().elaborate(platform=None)
673 self.fw = self.m.write_port().elaborate(platform=None)
674 self.f1 = Fragment()
675 self.f2 = Fragment()
676 self.f2.add_subfragment(self.fr)
677 self.f1.add_subfragment(self.f2)
678 self.f3 = Fragment()
679 self.f3.add_subfragment(self.fw)
680 self.f1.add_subfragment(self.f3)
681
682 def test_conflict_memory(self):
683 self.setUp_memory()
684
685 self.f1._resolve_hierarchy_conflicts(mode="silent")
686 self.assertEqual(self.f1.subfragments, [
687 (self.fr, None),
688 (self.fw, None),
689 ])
690
691 def test_conflict_memory_error(self):
692 self.setUp_memory()
693
694 with self.assertRaises(DriverConflict,
695 msg="Memory 'm' is accessed from multiple fragments: top.<unnamed #0>, "
696 "top.<unnamed #1>"):
697 self.f1._resolve_hierarchy_conflicts(mode="error")
698
699 def test_conflict_memory_warning(self):
700 self.setUp_memory()
701
702 with self.assertWarns(DriverConflict,
703 msg="Memory 'm' is accessed from multiple fragments: top.<unnamed #0>, "
704 "top.<unnamed #1>; hierarchy will be flattened"):
705 self.f1._resolve_hierarchy_conflicts(mode="warn")
706
707 def test_explicit_flatten(self):
708 self.f1 = Fragment()
709 self.f2 = Fragment()
710 self.f2.flatten = True
711 self.f1.add_subfragment(self.f2)
712
713 self.f1._resolve_hierarchy_conflicts(mode="silent")
714 self.assertEqual(self.f1.subfragments, [])
715
716 def test_no_conflict_local_domains(self):
717 f1 = Fragment()
718 cd1 = ClockDomain("d", local=True)
719 f1.add_domains(cd1)
720 f1.add_driver(ClockSignal("d"))
721 f2 = Fragment()
722 cd2 = ClockDomain("d", local=True)
723 f2.add_domains(cd2)
724 f2.add_driver(ClockSignal("d"))
725 f3 = Fragment()
726 f3.add_subfragment(f1)
727 f3.add_subfragment(f2)
728 f3.prepare()
729
730
731 class InstanceTestCase(FHDLTestCase):
732 def test_construct(self):
733 s1 = Signal()
734 s2 = Signal()
735 s3 = Signal()
736 s4 = Signal()
737 s5 = Signal()
738 s6 = Signal()
739 inst = Instance("foo",
740 ("a", "ATTR1", 1),
741 ("p", "PARAM1", 0x1234),
742 ("i", "s1", s1),
743 ("o", "s2", s2),
744 ("io", "s3", s3),
745 a_ATTR2=2,
746 p_PARAM2=0x5678,
747 i_s4=s4,
748 o_s5=s5,
749 io_s6=s6,
750 )
751 self.assertEqual(inst.attrs, OrderedDict([
752 ("ATTR1", 1),
753 ("ATTR2", 2),
754 ]))
755 self.assertEqual(inst.parameters, OrderedDict([
756 ("PARAM1", 0x1234),
757 ("PARAM2", 0x5678),
758 ]))
759 self.assertEqual(inst.named_ports, OrderedDict([
760 ("s1", (s1, "i")),
761 ("s2", (s2, "o")),
762 ("s3", (s3, "io")),
763 ("s4", (s4, "i")),
764 ("s5", (s5, "o")),
765 ("s6", (s6, "io")),
766 ]))
767
768 def test_cast_ports(self):
769 inst = Instance("foo",
770 ("i", "s1", 1),
771 ("o", "s2", 2),
772 ("io", "s3", 3),
773 i_s4=4,
774 o_s5=5,
775 io_s6=6,
776 )
777 self.assertRepr(inst.named_ports["s1"][0], "(const 1'd1)")
778 self.assertRepr(inst.named_ports["s2"][0], "(const 2'd2)")
779 self.assertRepr(inst.named_ports["s3"][0], "(const 2'd3)")
780 self.assertRepr(inst.named_ports["s4"][0], "(const 3'd4)")
781 self.assertRepr(inst.named_ports["s5"][0], "(const 3'd5)")
782 self.assertRepr(inst.named_ports["s6"][0], "(const 3'd6)")
783
784 def test_wrong_construct_arg(self):
785 s = Signal()
786 with self.assertRaises(NameError,
787 msg="Instance argument ('', 's1', (sig s)) should be a tuple "
788 "(kind, name, value) where kind is one of \"p\", \"i\", \"o\", or \"io\""):
789 Instance("foo", ("", "s1", s))
790
791 def test_wrong_construct_kwarg(self):
792 s = Signal()
793 with self.assertRaises(NameError,
794 msg="Instance keyword argument x_s1=(sig s) does not start with one of "
795 "\"p_\", \"i_\", \"o_\", or \"io_\""):
796 Instance("foo", x_s1=s)
797
798 def setUp_cpu(self):
799 self.rst = Signal()
800 self.stb = Signal()
801 self.pins = Signal(8)
802 self.datal = Signal(4)
803 self.datah = Signal(4)
804 self.inst = Instance("cpu",
805 p_RESET=0x1234,
806 i_clk=ClockSignal(),
807 i_rst=self.rst,
808 o_stb=self.stb,
809 o_data=Cat(self.datal, self.datah),
810 io_pins=self.pins[:]
811 )
812 self.wrap = Fragment()
813 self.wrap.add_subfragment(self.inst)
814
815 def test_init(self):
816 self.setUp_cpu()
817 f = self.inst
818 self.assertEqual(f.type, "cpu")
819 self.assertEqual(f.parameters, OrderedDict([("RESET", 0x1234)]))
820 self.assertEqual(list(f.named_ports.keys()), ["clk", "rst", "stb", "data", "pins"])
821 self.assertEqual(f.ports, SignalDict([]))
822
823 def test_prepare(self):
824 self.setUp_cpu()
825 f = self.wrap.prepare()
826 sync_clk = f.domains["sync"].clk
827 self.assertEqual(f.ports, SignalDict([
828 (sync_clk, "i"),
829 (self.rst, "i"),
830 (self.pins, "io"),
831 ]))
832
833 def test_prepare_explicit_ports(self):
834 self.setUp_cpu()
835 f = self.wrap.prepare(ports=[self.rst, self.stb])
836 sync_clk = f.domains["sync"].clk
837 sync_rst = f.domains["sync"].rst
838 self.assertEqual(f.ports, SignalDict([
839 (sync_clk, "i"),
840 (sync_rst, "i"),
841 (self.rst, "i"),
842 (self.stb, "o"),
843 (self.pins, "io"),
844 ]))
845
846 def test_prepare_slice_in_port(self):
847 s = Signal(2)
848 f = Fragment()
849 f.add_subfragment(Instance("foo", o_O=s[0]))
850 f.add_subfragment(Instance("foo", o_O=s[1]))
851 fp = f.prepare(ports=[s], missing_domain=lambda name: None)
852 self.assertEqual(fp.ports, SignalDict([
853 (s, "o"),
854 ]))
855
856 def test_prepare_attrs(self):
857 self.setUp_cpu()
858 self.inst.attrs["ATTR"] = 1
859 f = self.inst.prepare()
860 self.assertEqual(f.attrs, OrderedDict([
861 ("ATTR", 1),
862 ]))