fhdl.ast, back.pysim: implement shifts.
[nmigen.git] / nmigen / test / test_fhdl_dsl.py
1 from ..fhdl.ast import *
2 from ..fhdl.dsl import *
3 from .tools import *
4
5
6 class DSLTestCase(FHDLTestCase):
7 def setUp(self):
8 self.s1 = Signal()
9 self.s2 = Signal()
10 self.s3 = Signal()
11 self.c1 = Signal()
12 self.c2 = Signal()
13 self.c3 = Signal()
14 self.w1 = Signal(4)
15
16 def test_d_comb(self):
17 m = Module()
18 m.d.comb += self.c1.eq(1)
19 m._flush()
20 self.assertEqual(m._driving[self.c1], None)
21 self.assertRepr(m._statements, """(
22 (eq (sig c1) (const 1'd1))
23 )""")
24
25 def test_d_sync(self):
26 m = Module()
27 m.d.sync += self.c1.eq(1)
28 m._flush()
29 self.assertEqual(m._driving[self.c1], "sync")
30 self.assertRepr(m._statements, """(
31 (eq (sig c1) (const 1'd1))
32 )""")
33
34 def test_d_pix(self):
35 m = Module()
36 m.d.pix += self.c1.eq(1)
37 m._flush()
38 self.assertEqual(m._driving[self.c1], "pix")
39 self.assertRepr(m._statements, """(
40 (eq (sig c1) (const 1'd1))
41 )""")
42
43 def test_d_index(self):
44 m = Module()
45 m.d["pix"] += self.c1.eq(1)
46 m._flush()
47 self.assertEqual(m._driving[self.c1], "pix")
48 self.assertRepr(m._statements, """(
49 (eq (sig c1) (const 1'd1))
50 )""")
51
52 def test_d_no_conflict(self):
53 m = Module()
54 m.d.comb += self.w1[0].eq(1)
55 m.d.comb += self.w1[1].eq(1)
56
57 def test_d_conflict(self):
58 m = Module()
59 with self.assertRaises(SyntaxError,
60 msg="Driver-driver conflict: trying to drive (sig c1) from d.sync, but it "
61 "is already driven from d.comb"):
62 m.d.comb += self.c1.eq(1)
63 m.d.sync += self.c1.eq(1)
64
65 def test_d_wrong(self):
66 m = Module()
67 with self.assertRaises(AttributeError,
68 msg="Cannot assign 'd.pix' attribute; did you mean 'd.pix +='?"):
69 m.d.pix = None
70
71 def test_d_asgn_wrong(self):
72 m = Module()
73 with self.assertRaises(SyntaxError,
74 msg="Only assignments may be appended to d.sync"):
75 m.d.sync += Switch(self.s1, {})
76
77 def test_comb_wrong(self):
78 m = Module()
79 with self.assertRaises(AttributeError,
80 msg="'Module' object has no attribute 'comb'; did you mean 'd.comb'?"):
81 m.comb += self.c1.eq(1)
82
83 def test_sync_wrong(self):
84 m = Module()
85 with self.assertRaises(AttributeError,
86 msg="'Module' object has no attribute 'sync'; did you mean 'd.sync'?"):
87 m.sync += self.c1.eq(1)
88
89 def test_attr_wrong(self):
90 m = Module()
91 with self.assertRaises(AttributeError,
92 msg="'Module' object has no attribute 'nonexistentattr'"):
93 m.nonexistentattr
94
95 def test_If(self):
96 m = Module()
97 with m.If(self.s1):
98 m.d.comb += self.c1.eq(1)
99 m._flush()
100 self.assertRepr(m._statements, """
101 (
102 (switch (cat (sig s1))
103 (case 1 (eq (sig c1) (const 1'd1)))
104 )
105 )
106 """)
107
108 def test_If_Elif(self):
109 m = Module()
110 with m.If(self.s1):
111 m.d.comb += self.c1.eq(1)
112 with m.Elif(self.s2):
113 m.d.sync += self.c2.eq(0)
114 m._flush()
115 self.assertRepr(m._statements, """
116 (
117 (switch (cat (sig s1) (sig s2))
118 (case -1 (eq (sig c1) (const 1'd1)))
119 (case 1- (eq (sig c2) (const 1'd0)))
120 )
121 )
122 """)
123
124 def test_If_Elif_Else(self):
125 m = Module()
126 with m.If(self.s1):
127 m.d.comb += self.c1.eq(1)
128 with m.Elif(self.s2):
129 m.d.sync += self.c2.eq(0)
130 with m.Else():
131 m.d.comb += self.c3.eq(1)
132 m._flush()
133 self.assertRepr(m._statements, """
134 (
135 (switch (cat (sig s1) (sig s2))
136 (case -1 (eq (sig c1) (const 1'd1)))
137 (case 1- (eq (sig c2) (const 1'd0)))
138 (case -- (eq (sig c3) (const 1'd1)))
139 )
140 )
141 """)
142
143 def test_If_If(self):
144 m = Module()
145 with m.If(self.s1):
146 m.d.comb += self.c1.eq(1)
147 with m.If(self.s2):
148 m.d.comb += self.c2.eq(1)
149 m._flush()
150 self.assertRepr(m._statements, """
151 (
152 (switch (cat (sig s1))
153 (case 1 (eq (sig c1) (const 1'd1)))
154 )
155 (switch (cat (sig s2))
156 (case 1 (eq (sig c2) (const 1'd1)))
157 )
158 )
159 """)
160
161 def test_If_nested_If(self):
162 m = Module()
163 with m.If(self.s1):
164 m.d.comb += self.c1.eq(1)
165 with m.If(self.s2):
166 m.d.comb += self.c2.eq(1)
167 m._flush()
168 self.assertRepr(m._statements, """
169 (
170 (switch (cat (sig s1))
171 (case 1 (eq (sig c1) (const 1'd1))
172 (switch (cat (sig s2))
173 (case 1 (eq (sig c2) (const 1'd1)))
174 )
175 )
176 )
177 )
178 """)
179
180 def test_If_dangling_Else(self):
181 m = Module()
182 with m.If(self.s1):
183 m.d.comb += self.c1.eq(1)
184 with m.If(self.s2):
185 m.d.comb += self.c2.eq(1)
186 with m.Else():
187 m.d.comb += self.c3.eq(1)
188 m._flush()
189 self.assertRepr(m._statements, """
190 (
191 (switch (cat (sig s1))
192 (case 1
193 (eq (sig c1) (const 1'd1))
194 (switch (cat (sig s2))
195 (case 1 (eq (sig c2) (const 1'd1)))
196 )
197 )
198 (case -
199 (eq (sig c3) (const 1'd1))
200 )
201 )
202 )
203 """)
204
205 def test_Elif_wrong(self):
206 m = Module()
207 with self.assertRaises(SyntaxError,
208 msg="Elif without preceding If"):
209 with m.Elif(self.s2):
210 pass
211
212 def test_Else_wrong(self):
213 m = Module()
214 with self.assertRaises(SyntaxError,
215 msg="Else without preceding If/Elif"):
216 with m.Else():
217 pass
218
219 def test_If_wide(self):
220 m = Module()
221 with m.If(self.w1):
222 m.d.comb += self.c1.eq(1)
223 m._flush()
224 self.assertRepr(m._statements, """
225 (
226 (switch (cat (b (sig w1)))
227 (case 1 (eq (sig c1) (const 1'd1)))
228 )
229 )
230 """)
231
232 def test_Switch(self):
233 m = Module()
234 with m.Switch(self.w1):
235 with m.Case(3):
236 m.d.comb += self.c1.eq(1)
237 with m.Case("11--"):
238 m.d.comb += self.c2.eq(1)
239 m._flush()
240 self.assertRepr(m._statements, """
241 (
242 (switch (sig w1)
243 (case 0011 (eq (sig c1) (const 1'd1)))
244 (case 11-- (eq (sig c2) (const 1'd1)))
245 )
246 )
247 """)
248
249 def test_Switch_default(self):
250 m = Module()
251 with m.Switch(self.w1):
252 with m.Case(3):
253 m.d.comb += self.c1.eq(1)
254 with m.Case():
255 m.d.comb += self.c2.eq(1)
256 m._flush()
257 self.assertRepr(m._statements, """
258 (
259 (switch (sig w1)
260 (case 0011 (eq (sig c1) (const 1'd1)))
261 (case ---- (eq (sig c2) (const 1'd1)))
262 )
263 )
264 """)
265
266 def test_Switch_const_test(self):
267 m = Module()
268 with m.Switch(1):
269 with m.Case(1):
270 m.d.comb += self.c1.eq(1)
271 m._flush()
272 self.assertRepr(m._statements, """
273 (
274 (switch (const 1'd1)
275 (case 1 (eq (sig c1) (const 1'd1)))
276 )
277 )
278 """)
279
280 def test_Case_width_wrong(self):
281 m = Module()
282 with m.Switch(self.w1):
283 with self.assertRaises(SyntaxError,
284 msg="Case value '--' must have the same width as test (which is 4)"):
285 with m.Case("--"):
286 pass
287
288 def test_Case_outside_Switch_wrong(self):
289 m = Module()
290 with self.assertRaises(SyntaxError,
291 msg="Case is not permitted outside of Switch"):
292 with m.Case():
293 pass
294
295 def test_If_inside_Switch_wrong(self):
296 m = Module()
297 with m.Switch(self.s1):
298 with self.assertRaises(SyntaxError,
299 msg="If is not permitted inside of Switch"):
300 with m.If(self.s2):
301 pass
302
303 def test_auto_pop_ctrl(self):
304 m = Module()
305 with m.If(self.w1):
306 m.d.comb += self.c1.eq(1)
307 m.d.comb += self.c2.eq(1)
308 self.assertRepr(m._statements, """
309 (
310 (switch (cat (b (sig w1)))
311 (case 1 (eq (sig c1) (const 1'd1)))
312 )
313 (eq (sig c2) (const 1'd1))
314 )
315 """)
316
317 def test_submodule_anon(self):
318 m1 = Module()
319 m2 = Module()
320 m1.submodules += m2
321 self.assertEqual(m1._submodules, [(m2, None)])
322
323 def test_submodule_anon_multi(self):
324 m1 = Module()
325 m2 = Module()
326 m3 = Module()
327 m1.submodules += m2, m3
328 self.assertEqual(m1._submodules, [(m2, None), (m3, None)])
329
330 def test_submodule_named(self):
331 m1 = Module()
332 m2 = Module()
333 m1.submodules.foo = m2
334 self.assertEqual(m1._submodules, [(m2, "foo")])
335
336 def test_submodule_wrong(self):
337 m = Module()
338 with self.assertRaises(TypeError,
339 msg="Trying to add '1', which does not implement .get_fragment(), as a submodule"):
340 m.submodules.foo = 1
341 with self.assertRaises(TypeError,
342 msg="Trying to add '1', which does not implement .get_fragment(), as a submodule"):
343 m.submodules += 1
344
345 def test_lower(self):
346 m1 = Module()
347 m1.d.comb += self.c1.eq(self.s1)
348 m2 = Module()
349 m2.d.comb += self.c2.eq(self.s2)
350 m2.d.sync += self.c3.eq(self.s3)
351 m1.submodules.foo = m2
352
353 f1 = m1.lower(platform=None)
354 self.assertRepr(f1.statements, """
355 (
356 (eq (sig c1) (sig s1))
357 )
358 """)
359 self.assertEqual(f1.drivers, {
360 None: ValueSet((self.c1,))
361 })
362 self.assertEqual(len(f1.subfragments), 1)
363 (f2, f2_name), = f1.subfragments
364 self.assertEqual(f2_name, "foo")
365 self.assertRepr(f2.statements, """
366 (
367 (eq (sig c2) (sig s2))
368 (eq (sig c3) (sig s3))
369 )
370 """)
371 self.assertEqual(f2.drivers, {
372 None: ValueSet((self.c2,)),
373 "sync": ValueSet((self.c3,))
374 })
375 self.assertEqual(len(f2.subfragments), 0)