hdl.xfrm, back.rtlil: implement and use LHSGroupFilter.
[nmigen.git] / nmigen / test / test_hdl_xfrm.py
1 from ..hdl.ast import *
2 from ..hdl.cd import *
3 from ..hdl.ir import *
4 from ..hdl.xfrm import *
5 from .tools import *
6
7
8 class DomainRenamerTestCase(FHDLTestCase):
9 def setUp(self):
10 self.s1 = Signal()
11 self.s2 = Signal()
12 self.s3 = Signal()
13 self.s4 = Signal()
14 self.s5 = Signal()
15 self.c1 = Signal()
16
17 def test_rename_signals(self):
18 f = Fragment()
19 f.add_statements(
20 self.s1.eq(ClockSignal()),
21 ResetSignal().eq(self.s2),
22 self.s3.eq(0),
23 self.s4.eq(ClockSignal("other")),
24 self.s5.eq(ResetSignal("other")),
25 )
26 f.add_driver(self.s1, None)
27 f.add_driver(self.s2, None)
28 f.add_driver(self.s3, "sync")
29
30 f = DomainRenamer("pix")(f)
31 self.assertRepr(f.statements, """
32 (
33 (eq (sig s1) (clk pix))
34 (eq (rst pix) (sig s2))
35 (eq (sig s3) (const 1'd0))
36 (eq (sig s4) (clk other))
37 (eq (sig s5) (rst other))
38 )
39 """)
40 self.assertEqual(f.drivers, {
41 None: SignalSet((self.s1, self.s2)),
42 "pix": SignalSet((self.s3,)),
43 })
44
45 def test_rename_multi(self):
46 f = Fragment()
47 f.add_statements(
48 self.s1.eq(ClockSignal()),
49 self.s2.eq(ResetSignal("other")),
50 )
51
52 f = DomainRenamer({"sync": "pix", "other": "pix2"})(f)
53 self.assertRepr(f.statements, """
54 (
55 (eq (sig s1) (clk pix))
56 (eq (sig s2) (rst pix2))
57 )
58 """)
59
60 def test_rename_cd(self):
61 cd_sync = ClockDomain()
62 cd_pix = ClockDomain()
63
64 f = Fragment()
65 f.add_domains(cd_sync, cd_pix)
66
67 f = DomainRenamer("ext")(f)
68 self.assertEqual(cd_sync.name, "ext")
69 self.assertEqual(f.domains, {
70 "ext": cd_sync,
71 "pix": cd_pix,
72 })
73
74 def test_rename_cd_subfragment(self):
75 cd_sync = ClockDomain()
76 cd_pix = ClockDomain()
77
78 f1 = Fragment()
79 f1.add_domains(cd_sync, cd_pix)
80 f2 = Fragment()
81 f2.add_domains(cd_sync)
82 f1.add_subfragment(f2)
83
84 f1 = DomainRenamer("ext")(f1)
85 self.assertEqual(cd_sync.name, "ext")
86 self.assertEqual(f1.domains, {
87 "ext": cd_sync,
88 "pix": cd_pix,
89 })
90
91
92 class DomainLowererTestCase(FHDLTestCase):
93 def setUp(self):
94 self.s = Signal()
95
96 def test_lower_clk(self):
97 sync = ClockDomain()
98 f = Fragment()
99 f.add_statements(
100 self.s.eq(ClockSignal("sync"))
101 )
102
103 f = DomainLowerer({"sync": sync})(f)
104 self.assertRepr(f.statements, """
105 (
106 (eq (sig s) (sig clk))
107 )
108 """)
109
110 def test_lower_rst(self):
111 sync = ClockDomain()
112 f = Fragment()
113 f.add_statements(
114 self.s.eq(ResetSignal("sync"))
115 )
116
117 f = DomainLowerer({"sync": sync})(f)
118 self.assertRepr(f.statements, """
119 (
120 (eq (sig s) (sig rst))
121 )
122 """)
123
124 def test_lower_rst_reset_less(self):
125 sync = ClockDomain(reset_less=True)
126 f = Fragment()
127 f.add_statements(
128 self.s.eq(ResetSignal("sync", allow_reset_less=True))
129 )
130
131 f = DomainLowerer({"sync": sync})(f)
132 self.assertRepr(f.statements, """
133 (
134 (eq (sig s) (const 1'd0))
135 )
136 """)
137
138 def test_lower_wrong_domain(self):
139 sync = ClockDomain()
140 f = Fragment()
141 f.add_statements(
142 self.s.eq(ClockSignal("xxx"))
143 )
144
145 with self.assertRaises(DomainError,
146 msg="Signal (clk xxx) refers to nonexistent domain 'xxx'"):
147 DomainLowerer({"sync": sync})(f)
148
149 def test_lower_wrong_reset_less_domain(self):
150 sync = ClockDomain(reset_less=True)
151 f = Fragment()
152 f.add_statements(
153 self.s.eq(ResetSignal("sync"))
154 )
155
156 with self.assertRaises(DomainError,
157 msg="Signal (rst sync) refers to reset of reset-less domain 'sync'"):
158 DomainLowerer({"sync": sync})(f)
159
160
161 class SwitchCleanerTestCase(FHDLTestCase):
162 def test_clean(self):
163 a = Signal()
164 b = Signal()
165 c = Signal()
166 stmts = [
167 Switch(a, {
168 1: a.eq(0),
169 0: [
170 b.eq(1),
171 Switch(b, {1: [
172 Switch(a|b, {})
173 ]})
174 ]
175 })
176 ]
177
178 self.assertRepr(SwitchCleaner()(stmts), """
179 (
180 (switch (sig a)
181 (case 1
182 (eq (sig a) (const 1'd0)))
183 (case 0
184 (eq (sig b) (const 1'd1)))
185 )
186 )
187 """)
188
189
190 class LHSGroupAnalyzerTestCase(FHDLTestCase):
191 def test_no_group_unrelated(self):
192 a = Signal()
193 b = Signal()
194 stmts = [
195 a.eq(0),
196 b.eq(0),
197 ]
198
199 groups = LHSGroupAnalyzer()(stmts)
200 self.assertEqual(list(groups.values()), [
201 SignalSet((a,)),
202 SignalSet((b,)),
203 ])
204
205 def test_group_related(self):
206 a = Signal()
207 b = Signal()
208 stmts = [
209 a.eq(0),
210 Cat(a, b).eq(0),
211 ]
212
213 groups = LHSGroupAnalyzer()(stmts)
214 self.assertEqual(list(groups.values()), [
215 SignalSet((a, b)),
216 ])
217
218 def test_no_loops(self):
219 a = Signal()
220 b = Signal()
221 stmts = [
222 a.eq(0),
223 Cat(a, b).eq(0),
224 Cat(a, b).eq(0),
225 ]
226
227 groups = LHSGroupAnalyzer()(stmts)
228 self.assertEqual(list(groups.values()), [
229 SignalSet((a, b)),
230 ])
231
232 def test_switch(self):
233 a = Signal()
234 b = Signal()
235 stmts = [
236 a.eq(0),
237 Switch(a, {
238 1: b.eq(0),
239 })
240 ]
241
242 groups = LHSGroupAnalyzer()(stmts)
243 self.assertEqual(list(groups.values()), [
244 SignalSet((a,)),
245 SignalSet((b,)),
246 ])
247
248
249 class LHSGroupFilterTestCase(FHDLTestCase):
250 def test_filter(self):
251 a = Signal()
252 b = Signal()
253 c = Signal()
254 stmts = [
255 Switch(a, {
256 1: a.eq(0),
257 0: [
258 b.eq(1),
259 Switch(b, {1: []})
260 ]
261 })
262 ]
263
264 self.assertRepr(LHSGroupFilter(SignalSet((a,)))(stmts), """
265 (
266 (switch (sig a)
267 (case 1
268 (eq (sig a) (const 1'd0)))
269 (case 0 )
270 )
271 )
272 """)
273
274
275 class ResetInserterTestCase(FHDLTestCase):
276 def setUp(self):
277 self.s1 = Signal()
278 self.s2 = Signal(reset=1)
279 self.s3 = Signal(reset=1, reset_less=True)
280 self.c1 = Signal()
281
282 def test_reset_default(self):
283 f = Fragment()
284 f.add_statements(
285 self.s1.eq(1)
286 )
287 f.add_driver(self.s1, "sync")
288
289 f = ResetInserter(self.c1)(f)
290 self.assertRepr(f.statements, """
291 (
292 (eq (sig s1) (const 1'd1))
293 (switch (sig c1)
294 (case 1 (eq (sig s1) (const 1'd0)))
295 )
296 )
297 """)
298
299 def test_reset_cd(self):
300 f = Fragment()
301 f.add_statements(
302 self.s1.eq(1),
303 self.s2.eq(0),
304 )
305 f.add_domains(ClockDomain("sync"))
306 f.add_driver(self.s1, "sync")
307 f.add_driver(self.s2, "pix")
308
309 f = ResetInserter({"pix": self.c1})(f)
310 self.assertRepr(f.statements, """
311 (
312 (eq (sig s1) (const 1'd1))
313 (eq (sig s2) (const 1'd0))
314 (switch (sig c1)
315 (case 1 (eq (sig s2) (const 1'd1)))
316 )
317 )
318 """)
319
320 def test_reset_value(self):
321 f = Fragment()
322 f.add_statements(
323 self.s2.eq(0)
324 )
325 f.add_driver(self.s2, "sync")
326
327 f = ResetInserter(self.c1)(f)
328 self.assertRepr(f.statements, """
329 (
330 (eq (sig s2) (const 1'd0))
331 (switch (sig c1)
332 (case 1 (eq (sig s2) (const 1'd1)))
333 )
334 )
335 """)
336
337 def test_reset_less(self):
338 f = Fragment()
339 f.add_statements(
340 self.s3.eq(0)
341 )
342 f.add_driver(self.s3, "sync")
343
344 f = ResetInserter(self.c1)(f)
345 self.assertRepr(f.statements, """
346 (
347 (eq (sig s3) (const 1'd0))
348 (switch (sig c1)
349 (case 1 )
350 )
351 )
352 """)
353
354
355 class CEInserterTestCase(FHDLTestCase):
356 def setUp(self):
357 self.s1 = Signal()
358 self.s2 = Signal()
359 self.s3 = Signal()
360 self.c1 = Signal()
361
362 def test_ce_default(self):
363 f = Fragment()
364 f.add_statements(
365 self.s1.eq(1)
366 )
367 f.add_driver(self.s1, "sync")
368
369 f = CEInserter(self.c1)(f)
370 self.assertRepr(f.statements, """
371 (
372 (eq (sig s1) (const 1'd1))
373 (switch (sig c1)
374 (case 0 (eq (sig s1) (sig s1)))
375 )
376 )
377 """)
378
379 def test_ce_cd(self):
380 f = Fragment()
381 f.add_statements(
382 self.s1.eq(1),
383 self.s2.eq(0),
384 )
385 f.add_driver(self.s1, "sync")
386 f.add_driver(self.s2, "pix")
387
388 f = CEInserter({"pix": self.c1})(f)
389 self.assertRepr(f.statements, """
390 (
391 (eq (sig s1) (const 1'd1))
392 (eq (sig s2) (const 1'd0))
393 (switch (sig c1)
394 (case 0 (eq (sig s2) (sig s2)))
395 )
396 )
397 """)
398
399 def test_ce_subfragment(self):
400 f1 = Fragment()
401 f1.add_statements(
402 self.s1.eq(1)
403 )
404 f1.add_driver(self.s1, "sync")
405
406 f2 = Fragment()
407 f2.add_statements(
408 self.s2.eq(1)
409 )
410 f2.add_driver(self.s2, "sync")
411 f1.add_subfragment(f2)
412
413 f1 = CEInserter(self.c1)(f1)
414 (f2, _), = f1.subfragments
415 self.assertRepr(f1.statements, """
416 (
417 (eq (sig s1) (const 1'd1))
418 (switch (sig c1)
419 (case 0 (eq (sig s1) (sig s1)))
420 )
421 )
422 """)
423 self.assertRepr(f2.statements, """
424 (
425 (eq (sig s2) (const 1'd1))
426 (switch (sig c1)
427 (case 0 (eq (sig s2) (sig s2)))
428 )
429 )
430 """)