1 from collections
import OrderedDict
3 from ..hdl
.ast
import *
5 from ..hdl
.dsl
import *
9 class DSLTestCase(FHDLTestCase
):
19 def test_d_comb(self
):
21 m
.d
.comb
+= self
.c1
.eq(1)
23 self
.assertEqual(m
._driving
[self
.c1
], None)
24 self
.assertRepr(m
._statements
, """(
25 (eq (sig c1) (const 1'd1))
28 def test_d_sync(self
):
30 m
.d
.sync
+= self
.c1
.eq(1)
32 self
.assertEqual(m
._driving
[self
.c1
], "sync")
33 self
.assertRepr(m
._statements
, """(
34 (eq (sig c1) (const 1'd1))
39 m
.d
.pix
+= self
.c1
.eq(1)
41 self
.assertEqual(m
._driving
[self
.c1
], "pix")
42 self
.assertRepr(m
._statements
, """(
43 (eq (sig c1) (const 1'd1))
46 def test_d_index(self
):
48 m
.d
["pix"] += self
.c1
.eq(1)
50 self
.assertEqual(m
._driving
[self
.c1
], "pix")
51 self
.assertRepr(m
._statements
, """(
52 (eq (sig c1) (const 1'd1))
55 def test_d_no_conflict(self
):
57 m
.d
.comb
+= self
.w1
[0].eq(1)
58 m
.d
.comb
+= self
.w1
[1].eq(1)
60 def test_d_conflict(self
):
62 with self
.assertRaises(SyntaxError,
63 msg
="Driver-driver conflict: trying to drive (sig c1) from d.sync, but it "
64 "is already driven from d.comb"):
65 m
.d
.comb
+= self
.c1
.eq(1)
66 m
.d
.sync
+= self
.c1
.eq(1)
68 def test_d_wrong(self
):
70 with self
.assertRaises(AttributeError,
71 msg
="Cannot assign 'd.pix' attribute; did you mean 'd.pix +='?"):
74 def test_d_asgn_wrong(self
):
76 with self
.assertRaises(SyntaxError,
77 msg
="Only assignments, asserts, and assumes may be appended to d.sync"):
78 m
.d
.sync
+= Switch(self
.s1
, {})
80 def test_comb_wrong(self
):
82 with self
.assertRaises(AttributeError,
83 msg
="'Module' object has no attribute 'comb'; did you mean 'd.comb'?"):
84 m
.comb
+= self
.c1
.eq(1)
86 def test_sync_wrong(self
):
88 with self
.assertRaises(AttributeError,
89 msg
="'Module' object has no attribute 'sync'; did you mean 'd.sync'?"):
90 m
.sync
+= self
.c1
.eq(1)
92 def test_attr_wrong(self
):
94 with self
.assertRaises(AttributeError,
95 msg
="'Module' object has no attribute 'nonexistentattr'"):
98 def test_clock_signal(self
):
100 m
.d
.comb
+= ClockSignal("pix").eq(ClockSignal())
101 self
.assertRepr(m
._statements
, """
103 (eq (clk pix) (clk sync))
107 def test_reset_signal(self
):
109 m
.d
.comb
+= ResetSignal("pix").eq(1)
110 self
.assertRepr(m
._statements
, """
112 (eq (rst pix) (const 1'd1))
116 def test_sample_domain(self
):
122 m
.d
.sync
+= o1
.eq(Past(i
))
123 m
.d
.pix
+= o2
.eq(Past(i
))
124 m
.d
.pix
+= o3
.eq(Past(i
, domain
="sync"))
125 f
= m
.elaborate(platform
=None)
126 self
.assertRepr(f
.statements
, """
128 (eq (sig o1) (sample (sig i) @ sync[1]))
129 (eq (sig o2) (sample (sig i) @ pix[1]))
130 (eq (sig o3) (sample (sig i) @ sync[1]))
137 m
.d
.comb
+= self
.c1
.eq(1)
139 self
.assertRepr(m
._statements
, """
141 (switch (cat (sig s1))
142 (case 1 (eq (sig c1) (const 1'd1)))
147 def test_If_Elif(self
):
150 m
.d
.comb
+= self
.c1
.eq(1)
151 with m
.Elif(self
.s2
):
152 m
.d
.sync
+= self
.c2
.eq(0)
154 self
.assertRepr(m
._statements
, """
156 (switch (cat (sig s1) (sig s2))
157 (case -1 (eq (sig c1) (const 1'd1)))
158 (case 1- (eq (sig c2) (const 1'd0)))
163 def test_If_Elif_Else(self
):
166 m
.d
.comb
+= self
.c1
.eq(1)
167 with m
.Elif(self
.s2
):
168 m
.d
.sync
+= self
.c2
.eq(0)
170 m
.d
.comb
+= self
.c3
.eq(1)
172 self
.assertRepr(m
._statements
, """
174 (switch (cat (sig s1) (sig s2))
175 (case -1 (eq (sig c1) (const 1'd1)))
176 (case 1- (eq (sig c2) (const 1'd0)))
177 (default (eq (sig c3) (const 1'd1)))
182 def test_If_If(self
):
185 m
.d
.comb
+= self
.c1
.eq(1)
187 m
.d
.comb
+= self
.c2
.eq(1)
189 self
.assertRepr(m
._statements
, """
191 (switch (cat (sig s1))
192 (case 1 (eq (sig c1) (const 1'd1)))
194 (switch (cat (sig s2))
195 (case 1 (eq (sig c2) (const 1'd1)))
200 def test_If_nested_If(self
):
203 m
.d
.comb
+= self
.c1
.eq(1)
205 m
.d
.comb
+= self
.c2
.eq(1)
207 self
.assertRepr(m
._statements
, """
209 (switch (cat (sig s1))
210 (case 1 (eq (sig c1) (const 1'd1))
211 (switch (cat (sig s2))
212 (case 1 (eq (sig c2) (const 1'd1)))
219 def test_If_dangling_Else(self
):
222 m
.d
.comb
+= self
.c1
.eq(1)
224 m
.d
.comb
+= self
.c2
.eq(1)
226 m
.d
.comb
+= self
.c3
.eq(1)
228 self
.assertRepr(m
._statements
, """
230 (switch (cat (sig s1))
232 (eq (sig c1) (const 1'd1))
233 (switch (cat (sig s2))
234 (case 1 (eq (sig c2) (const 1'd1)))
238 (eq (sig c3) (const 1'd1))
244 def test_Elif_wrong(self
):
246 with self
.assertRaises(SyntaxError,
247 msg
="Elif without preceding If"):
248 with m
.Elif(self
.s2
):
251 def test_Else_wrong(self
):
253 with self
.assertRaises(SyntaxError,
254 msg
="Else without preceding If/Elif"):
258 def test_If_wide(self
):
261 m
.d
.comb
+= self
.c1
.eq(1)
263 self
.assertRepr(m
._statements
, """
265 (switch (cat (b (sig w1)))
266 (case 1 (eq (sig c1) (const 1'd1)))
271 def test_Switch(self
):
273 with m
.Switch(self
.w1
):
275 m
.d
.comb
+= self
.c1
.eq(1)
277 m
.d
.comb
+= self
.c2
.eq(1)
279 self
.assertRepr(m
._statements
, """
282 (case 0011 (eq (sig c1) (const 1'd1)))
283 (case 11-- (eq (sig c2) (const 1'd1)))
288 def test_Switch_default(self
):
290 with m
.Switch(self
.w1
):
292 m
.d
.comb
+= self
.c1
.eq(1)
294 m
.d
.comb
+= self
.c2
.eq(1)
296 self
.assertRepr(m
._statements
, """
299 (case 0011 (eq (sig c1) (const 1'd1)))
300 (default (eq (sig c2) (const 1'd1)))
305 def test_Switch_const_test(self
):
309 m
.d
.comb
+= self
.c1
.eq(1)
311 self
.assertRepr(m
._statements
, """
314 (case 1 (eq (sig c1) (const 1'd1)))
319 def test_Case_width_wrong(self
):
321 with m
.Switch(self
.w1
):
322 with self
.assertRaises(SyntaxError,
323 msg
="Case value '--' must have the same width as test (which is 4)"):
326 with self
.assertWarns(SyntaxWarning,
327 msg
="Case value '10110' is wider than test (which has width 4); comparison "
328 "will never be true"):
329 with m
.Case(0b10110):
331 self
.assertRepr(m
._statements
, """
337 def test_Case_outside_Switch_wrong(self
):
339 with self
.assertRaises(SyntaxError,
340 msg
="Case is not permitted outside of Switch"):
344 def test_If_inside_Switch_wrong(self
):
346 with m
.Switch(self
.s1
):
347 with self
.assertRaises(SyntaxError,
348 msg
="If is not permitted directly inside of Switch; "
349 "it is permitted inside of Switch Case"):
353 def test_FSM_basic(self
):
359 with m
.State("FIRST"):
362 with m
.State("SECOND"):
367 self
.assertRepr(m
._statements
, """
369 (switch (sig fsm_state)
371 (eq (sig a) (const 1'd1))
372 (eq (sig fsm_state) (const 1'd1))
375 (eq (sig b) (~ (sig b)))
376 (switch (cat (sig c))
378 (eq (sig fsm_state) (const 1'd0)))
384 self
.assertEqual({repr(k
): v
for k
, v
in m
._driving
.items()}, {
386 "(sig fsm_state)": "sync",
390 frag
= m
.elaborate(platform
=None)
391 fsm
= frag
.find_generated("fsm")
392 self
.assertIsInstance(fsm
.state
, Signal
)
393 self
.assertEqual(fsm
.encoding
, OrderedDict({
397 self
.assertEqual(fsm
.decoding
, OrderedDict({
402 def test_FSM_reset(self
):
405 with m
.FSM(reset
="SECOND"):
406 with m
.State("FIRST"):
409 with m
.State("SECOND"):
412 self
.assertRepr(m
._statements
, """
414 (switch (sig fsm_state)
416 (eq (sig a) (const 1'd0))
417 (eq (sig fsm_state) (const 1'd1))
420 (eq (sig fsm_state) (const 1'd0))
426 def test_FSM_ongoing(self
):
431 m
.d
.comb
+= b
.eq(fsm
.ongoing("SECOND"))
432 with m
.State("FIRST"):
434 m
.d
.comb
+= a
.eq(fsm
.ongoing("FIRST"))
435 with m
.State("SECOND"):
438 self
.assertEqual(m
._generated
["fsm"].state
.reset
, 1)
440 self
.assertRepr(m
._statements
, """
442 (eq (sig b) (== (sig fsm_state) (const 1'd0)))
443 (eq (sig a) (== (sig fsm_state) (const 1'd1)))
444 (switch (sig fsm_state)
453 def test_FSM_empty(self
):
457 self
.assertRepr(m
._statements
, """
461 def test_FSM_wrong_domain(self
):
463 with self
.assertRaises(ValueError,
464 msg
="FSM may not be driven by the 'comb' domain"):
465 with m
.FSM(domain
="comb"):
468 def test_FSM_wrong_redefined(self
):
473 with self
.assertRaises(SyntaxError,
474 msg
="FSM state 'FOO' is already defined"):
478 def test_FSM_wrong_next(self
):
480 with self
.assertRaises(SyntaxError,
481 msg
="Only assignment to `m.next` is permitted"):
483 with self
.assertRaises(SyntaxError,
484 msg
="`m.next = <...>` is only permitted inside an FSM state"):
486 with self
.assertRaises(SyntaxError,
487 msg
="`m.next = <...>` is only permitted inside an FSM state"):
491 def test_If_inside_FSM_wrong(self
):
496 with self
.assertRaises(SyntaxError,
497 msg
="If is not permitted directly inside of FSM; "
498 "it is permitted inside of FSM State"):
502 def test_auto_pop_ctrl(self
):
505 m
.d
.comb
+= self
.c1
.eq(1)
506 m
.d
.comb
+= self
.c2
.eq(1)
507 self
.assertRepr(m
._statements
, """
509 (switch (cat (b (sig w1)))
510 (case 1 (eq (sig c1) (const 1'd1)))
512 (eq (sig c2) (const 1'd1))
516 def test_submodule_anon(self
):
520 self
.assertEqual(m1
._submodules
, [(m2
, None)])
522 def test_submodule_anon_multi(self
):
526 m1
.submodules
+= m2
, m3
527 self
.assertEqual(m1
._submodules
, [(m2
, None), (m3
, None)])
529 def test_submodule_named(self
):
532 m1
.submodules
.foo
= m2
533 self
.assertEqual(m1
._submodules
, [(m2
, "foo")])
535 def test_submodule_named_index(self
):
538 m1
.submodules
["foo"] = m2
539 self
.assertEqual(m1
._submodules
, [(m2
, "foo")])
541 def test_submodule_wrong(self
):
543 with self
.assertRaises(TypeError,
544 msg
="Trying to add '1', which does not implement .elaborate(), as a submodule"):
546 with self
.assertRaises(TypeError,
547 msg
="Trying to add '1', which does not implement .elaborate(), as a submodule"):
550 def test_domain_named_implicit(self
):
552 m
.domains
+= ClockDomain("sync")
553 self
.assertEqual(len(m
._domains
), 1)
555 def test_domain_named_explicit(self
):
557 m
.domains
.foo
= ClockDomain()
558 self
.assertEqual(len(m
._domains
), 1)
559 self
.assertEqual(m
._domains
[0].name
, "foo")
561 def test_lower(self
):
563 m1
.d
.comb
+= self
.c1
.eq(self
.s1
)
565 m2
.d
.comb
+= self
.c2
.eq(self
.s2
)
566 m2
.d
.sync
+= self
.c3
.eq(self
.s3
)
567 m1
.submodules
.foo
= m2
569 f1
= m1
.elaborate(platform
=None)
570 self
.assertRepr(f1
.statements
, """
572 (eq (sig c1) (sig s1))
575 self
.assertEqual(f1
.drivers
, {
576 None: SignalSet((self
.c1
,))
578 self
.assertEqual(len(f1
.subfragments
), 1)
579 (f2
, f2_name
), = f1
.subfragments
580 self
.assertEqual(f2_name
, "foo")
581 self
.assertRepr(f2
.statements
, """
583 (eq (sig c2) (sig s2))
584 (eq (sig c3) (sig s3))
587 self
.assertEqual(f2
.drivers
, {
588 None: SignalSet((self
.c2
,)),
589 "sync": SignalSet((self
.c3
,))
591 self
.assertEqual(len(f2
.subfragments
), 0)