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