hdl: appropriately rename tests. NFC.
[nmigen.git] / nmigen / test / test_hdl_ir.py
1 from ..hdl.ast import *
2 from ..hdl.cd import *
3 from ..hdl.ir import *
4 from .tools import *
5
6
7 class FragmentDriversTestCase(FHDLTestCase):
8 def test_empty(self):
9 f = Fragment()
10 self.assertEqual(list(f.iter_comb()), [])
11 self.assertEqual(list(f.iter_sync()), [])
12
13
14 class FragmentPortsTestCase(FHDLTestCase):
15 def setUp(self):
16 self.s1 = Signal()
17 self.s2 = Signal()
18 self.s3 = Signal()
19 self.c1 = Signal()
20 self.c2 = Signal()
21 self.c3 = Signal()
22
23 def test_empty(self):
24 f = Fragment()
25 self.assertEqual(list(f.iter_ports()), [])
26
27 f._propagate_ports(ports=())
28 self.assertEqual(f.ports, ValueDict([]))
29
30 def test_iter_signals(self):
31 f = Fragment()
32 f.add_ports(self.s1, self.s2, kind="io")
33 self.assertEqual(ValueSet((self.s1, self.s2)), f.iter_signals())
34
35 def test_self_contained(self):
36 f = Fragment()
37 f.add_statements(
38 self.c1.eq(self.s1),
39 self.s1.eq(self.c1)
40 )
41
42 f._propagate_ports(ports=())
43 self.assertEqual(f.ports, ValueDict([]))
44
45 def test_infer_input(self):
46 f = Fragment()
47 f.add_statements(
48 self.c1.eq(self.s1)
49 )
50
51 f._propagate_ports(ports=())
52 self.assertEqual(f.ports, ValueDict([
53 (self.s1, "i")
54 ]))
55
56 def test_request_output(self):
57 f = Fragment()
58 f.add_statements(
59 self.c1.eq(self.s1)
60 )
61
62 f._propagate_ports(ports=(self.c1,))
63 self.assertEqual(f.ports, ValueDict([
64 (self.s1, "i"),
65 (self.c1, "o")
66 ]))
67
68 def test_input_in_subfragment(self):
69 f1 = Fragment()
70 f1.add_statements(
71 self.c1.eq(self.s1)
72 )
73 f2 = Fragment()
74 f2.add_statements(
75 self.s1.eq(0)
76 )
77 f1.add_subfragment(f2)
78 f1._propagate_ports(ports=())
79 self.assertEqual(f1.ports, ValueDict())
80 self.assertEqual(f2.ports, ValueDict([
81 (self.s1, "o"),
82 ]))
83
84 def test_input_only_in_subfragment(self):
85 f1 = Fragment()
86 f2 = Fragment()
87 f2.add_statements(
88 self.c1.eq(self.s1)
89 )
90 f1.add_subfragment(f2)
91 f1._propagate_ports(ports=())
92 self.assertEqual(f1.ports, ValueDict([
93 (self.s1, "i"),
94 ]))
95 self.assertEqual(f2.ports, ValueDict([
96 (self.s1, "i"),
97 ]))
98
99 def test_output_from_subfragment(self):
100 f1 = Fragment()
101 f1.add_statements(
102 self.c1.eq(0)
103 )
104 f2 = Fragment()
105 f2.add_statements(
106 self.c2.eq(1)
107 )
108 f1.add_subfragment(f2)
109
110 f1._propagate_ports(ports=(self.c2,))
111 self.assertEqual(f1.ports, ValueDict([
112 (self.c2, "o"),
113 ]))
114 self.assertEqual(f2.ports, ValueDict([
115 (self.c2, "o"),
116 ]))
117
118 def test_input_cd(self):
119 sync = ClockDomain()
120 f = Fragment()
121 f.add_statements(
122 self.c1.eq(self.s1)
123 )
124 f.add_domains(sync)
125 f.add_driver(self.c1, "sync")
126
127 f._propagate_ports(ports=())
128 self.assertEqual(f.ports, ValueDict([
129 (self.s1, "i"),
130 (sync.clk, "i"),
131 (sync.rst, "i"),
132 ]))
133
134 def test_input_cd_reset_less(self):
135 sync = ClockDomain(reset_less=True)
136 f = Fragment()
137 f.add_statements(
138 self.c1.eq(self.s1)
139 )
140 f.add_domains(sync)
141 f.add_driver(self.c1, "sync")
142
143 f._propagate_ports(ports=())
144 self.assertEqual(f.ports, ValueDict([
145 (self.s1, "i"),
146 (sync.clk, "i"),
147 ]))
148
149
150 class FragmentDomainsTestCase(FHDLTestCase):
151 def test_iter_signals(self):
152 cd1 = ClockDomain()
153 cd2 = ClockDomain(reset_less=True)
154 s1 = Signal()
155 s2 = Signal()
156
157 f = Fragment()
158 f.add_domains(cd1, cd2)
159 f.add_driver(s1, "cd1")
160 self.assertEqual(ValueSet((cd1.clk, cd1.rst, s1)), f.iter_signals())
161 f.add_driver(s2, "cd2")
162 self.assertEqual(ValueSet((cd1.clk, cd1.rst, cd2.clk, s1, s2)), f.iter_signals())
163
164 def test_propagate_up(self):
165 cd = ClockDomain()
166
167 f1 = Fragment()
168 f2 = Fragment()
169 f1.add_subfragment(f2)
170 f2.add_domains(cd)
171
172 f1._propagate_domains_up()
173 self.assertEqual(f1.domains, {"cd": cd})
174
175 def test_domain_conflict(self):
176 cda = ClockDomain("sync")
177 cdb = ClockDomain("sync")
178
179 fa = Fragment()
180 fa.add_domains(cda)
181 fb = Fragment()
182 fb.add_domains(cdb)
183 f = Fragment()
184 f.add_subfragment(fa, "a")
185 f.add_subfragment(fb, "b")
186
187 f._propagate_domains_up()
188 self.assertEqual(f.domains, {"a_sync": cda, "b_sync": cdb})
189 (fa, _), (fb, _) = f.subfragments
190 self.assertEqual(fa.domains, {"a_sync": cda})
191 self.assertEqual(fb.domains, {"b_sync": cdb})
192
193 def test_domain_conflict_anon(self):
194 cda = ClockDomain("sync")
195 cdb = ClockDomain("sync")
196
197 fa = Fragment()
198 fa.add_domains(cda)
199 fb = Fragment()
200 fb.add_domains(cdb)
201 f = Fragment()
202 f.add_subfragment(fa, "a")
203 f.add_subfragment(fb)
204
205 with self.assertRaises(DomainError,
206 msg="Domain 'sync' is defined by subfragments 'a', <unnamed #1> of fragment "
207 "'top'; it is necessary to either rename subfragment domains explicitly, "
208 "or give names to subfragments"):
209 f._propagate_domains_up()
210
211 def test_domain_conflict_name(self):
212 cda = ClockDomain("sync")
213 cdb = ClockDomain("sync")
214
215 fa = Fragment()
216 fa.add_domains(cda)
217 fb = Fragment()
218 fb.add_domains(cdb)
219 f = Fragment()
220 f.add_subfragment(fa, "x")
221 f.add_subfragment(fb, "x")
222
223 with self.assertRaises(DomainError,
224 msg="Domain 'sync' is defined by subfragments #0, #1 of fragment 'top', some "
225 "of which have identical names; it is necessary to either rename subfragment "
226 "domains explicitly, or give distinct names to subfragments"):
227 f._propagate_domains_up()
228
229 def test_propagate_down(self):
230 cd = ClockDomain()
231
232 f1 = Fragment()
233 f2 = Fragment()
234 f1.add_domains(cd)
235 f1.add_subfragment(f2)
236
237 f1._propagate_domains_down()
238 self.assertEqual(f2.domains, {"cd": cd})
239
240 def test_propagate_down_idempotent(self):
241 cd = ClockDomain()
242
243 f1 = Fragment()
244 f1.add_domains(cd)
245 f2 = Fragment()
246 f2.add_domains(cd)
247 f1.add_subfragment(f2)
248
249 f1._propagate_domains_down()
250 self.assertEqual(f1.domains, {"cd": cd})
251 self.assertEqual(f2.domains, {"cd": cd})
252
253 def test_propagate(self):
254 cd = ClockDomain()
255
256 f1 = Fragment()
257 f2 = Fragment()
258 f1.add_domains(cd)
259 f1.add_subfragment(f2)
260
261 f1._propagate_domains(ensure_sync_exists=False)
262 self.assertEqual(f1.domains, {"cd": cd})
263 self.assertEqual(f2.domains, {"cd": cd})
264
265 def test_propagate_ensure_sync(self):
266 f1 = Fragment()
267 f2 = Fragment()
268 f1.add_subfragment(f2)
269
270 f1._propagate_domains(ensure_sync_exists=True)
271 self.assertEqual(f1.domains.keys(), {"sync"})
272 self.assertEqual(f2.domains.keys(), {"sync"})
273 self.assertEqual(f1.domains["sync"], f2.domains["sync"])
274
275
276 class FragmentDriverConflictTestCase(FHDLTestCase):
277 def setUp_self_sub(self):
278 self.s1 = Signal()
279 self.c1 = Signal()
280 self.c2 = Signal()
281
282 self.f1 = Fragment()
283 self.f1.add_statements(self.c1.eq(0))
284 self.f1.add_driver(self.s1)
285 self.f1.add_driver(self.c1, "sync")
286
287 self.f1a = Fragment()
288 self.f1.add_subfragment(self.f1a, "f1a")
289
290 self.f2 = Fragment()
291 self.f2.add_statements(self.c2.eq(1))
292 self.f2.add_driver(self.s1)
293 self.f2.add_driver(self.c2, "sync")
294 self.f1.add_subfragment(self.f2)
295
296 self.f1b = Fragment()
297 self.f1.add_subfragment(self.f1b, "f1b")
298
299 self.f2a = Fragment()
300 self.f2.add_subfragment(self.f2a, "f2a")
301
302 def test_conflict_self_sub(self):
303 self.setUp_self_sub()
304
305 self.f1._resolve_driver_conflicts(mode="silent")
306 self.assertEqual(self.f1.subfragments, [
307 (self.f1a, "f1a"),
308 (self.f1b, "f1b"),
309 (self.f2a, "f2a"),
310 ])
311 self.assertRepr(self.f1.statements, """
312 (
313 (eq (sig c1) (const 1'd0))
314 (eq (sig c2) (const 1'd1))
315 )
316 """)
317 self.assertEqual(self.f1.drivers, {
318 None: ValueSet((self.s1,)),
319 "sync": ValueSet((self.c1, self.c2)),
320 })
321
322 def test_conflict_self_sub_error(self):
323 self.setUp_self_sub()
324
325 with self.assertRaises(DriverConflict,
326 msg="Signal '(sig s1)' is driven from multiple fragments: top, top.<unnamed #1>"):
327 self.f1._resolve_driver_conflicts(mode="error")
328
329 def test_conflict_self_sub_warning(self):
330 self.setUp_self_sub()
331
332 with self.assertWarns(DriverConflict,
333 msg="Signal '(sig s1)' is driven from multiple fragments: top, top.<unnamed #1>; "
334 "hierarchy will be flattened"):
335 self.f1._resolve_driver_conflicts(mode="warn")
336
337 def setUp_sub_sub(self):
338 self.s1 = Signal()
339 self.c1 = Signal()
340 self.c2 = Signal()
341
342 self.f1 = Fragment()
343
344 self.f2 = Fragment()
345 self.f2.add_driver(self.s1)
346 self.f2.add_statements(self.c1.eq(0))
347 self.f1.add_subfragment(self.f2)
348
349 self.f3 = Fragment()
350 self.f3.add_driver(self.s1)
351 self.f3.add_statements(self.c2.eq(1))
352 self.f1.add_subfragment(self.f3)
353
354 def test_conflict_sub_sub(self):
355 self.setUp_sub_sub()
356
357 self.f1._resolve_driver_conflicts(mode="silent")
358 self.assertEqual(self.f1.subfragments, [])
359 self.assertRepr(self.f1.statements, """
360 (
361 (eq (sig c1) (const 1'd0))
362 (eq (sig c2) (const 1'd1))
363 )
364 """)
365
366 def setUp_self_subsub(self):
367 self.s1 = Signal()
368 self.c1 = Signal()
369 self.c2 = Signal()
370
371 self.f1 = Fragment()
372 self.f1.add_driver(self.s1)
373
374 self.f2 = Fragment()
375 self.f2.add_statements(self.c1.eq(0))
376 self.f1.add_subfragment(self.f2)
377
378 self.f3 = Fragment()
379 self.f3.add_driver(self.s1)
380 self.f3.add_statements(self.c2.eq(1))
381 self.f2.add_subfragment(self.f3)
382
383 def test_conflict_self_subsub(self):
384 self.setUp_self_subsub()
385
386 self.f1._resolve_driver_conflicts(mode="silent")
387 self.assertEqual(self.f1.subfragments, [])
388 self.assertRepr(self.f1.statements, """
389 (
390 (eq (sig c1) (const 1'd0))
391 (eq (sig c2) (const 1'd1))
392 )
393 """)